Add server

This commit is contained in:
Ivan Danyliuk 2018-09-19 19:55:58 +03:00
parent c82b8d22af
commit 2e30599707
No known key found for this signature in database
GPG Key ID: 97ED33CE024E1DBF
5 changed files with 1185 additions and 41 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
package main
import (
"log"
"net/http"
"github.com/divan/graphx/formats"
)
// simulationHandler serves request to start simulation. It expectes network graph
// in the request body, syncronously runs a new simulation on this network and
// sends back simulation log in JSON format.
//
// TODO(divan): in the future, simulation will probably take longer, so it'll have to upgrade
// connection to Websocket and talk to frontend this way.
func simulationHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
w.WriteHeader(http.StatusBadRequest)
return
}
data, err := formats.FromD3JSONReader(r.Body)
if err != nil {
log.Println("[ERROR] Bad payload:", err)
w.WriteHeader(http.StatusBadRequest)
return
}
defer r.Body.Close()
log.Printf("Loaded graph with %d nodes", len(data.Nodes()))
sim := NewSimulation(data)
sim.Start()
defer sim.Stop()
log.Println("Sending propagation log")
sim.WriteOutput(w)
}

View File

@ -0,0 +1,35 @@
package main
import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
)
func TestHandler(t *testing.T) {
payload := bytes.NewBuffer(testdataJSON)
req, err := http.NewRequest("POST", "/", payload)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(simulationHandler)
handler.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
// Check the response body size (it should be reasonably big)
// We can't compare output as it's non-deterministic (each simulation
// produce different results).
// TODO(divan): decode response and compare data sizes fields, at least.
if len(rr.Body.String()) < 100 {
t.Errorf("handler returned unexpected body: got %v",
rr.Body.String())
}
}

View File

@ -1,70 +1,59 @@
package main
import (
"encoding/json"
"flag"
"log"
"net/http"
"os"
"time"
"github.com/divan/graphx/formats"
gethlog "github.com/ethereum/go-ethereum/log"
"github.com/status-im/simulation/propagation"
"github.com/status-im/simulation/propagation/naivep2p"
"github.com/status-im/simulation/propagation/whisperv6"
"github.com/status-im/simulation/stats"
)
func main() {
var (
simType = flag.String("type", "whisperv6", "Type of simulators (naivep2p, whisperv6)")
ttl = flag.Int("ttl", 10, "Message TTL for simulation")
naiveP2PN = flag.Int("naivep2p.N", 3, "Number of peers to propagate (0..N of peers)")
naiveP2PDelay = flag.Duration("naivep2p.delay", 10*time.Millisecond, "Delay for each step")
input = flag.String("i", "network.json", "Input filename for pregenerated data to be used with simulation")
output = flag.String("o", "propagation.json", "Output filename for p2p sending data")
gethlogLevel = flag.String("loglevel", "crit", "Geth log level for whisper simulator (crti, error, warn, info, debug, trace)")
input = flag.String("i", "network.json", "Input filename for pregenerated data to be used with simulation")
output = flag.String("o", "propagation.json", "Output filename for p2p sending data")
gethlogLevel = flag.String("loglevel", "crit", "Geth log level for whisper simulator (crti, error, warn, info, debug, trace)")
server = flag.Bool("server", false, "Start as server to be used with whisperviz")
serverAddr = flag.String("h", "localhost:8084", "Address to bind to in server mode")
)
flag.Parse()
setGethLogLevel(*gethlogLevel)
if *server {
log.Println("Starting simulator server on", *serverAddr)
http.HandleFunc("/", simulationHandler)
log.Fatal(http.ListenAndServe(*serverAddr, nil))
return
}
data, err := formats.FromD3JSON(*input)
if err != nil {
log.Fatal("Opening input file failed: ", err)
}
fd, err := os.Create(*output)
if err != nil {
log.Fatal("Opening output file failed: ", err)
}
defer fd.Close()
sim := NewSimulation(data)
log.Printf("Starting message sending simulation for graph with %d nodes...", len(data.Nodes()))
sim.Start()
defer sim.Stop()
sim.WriteOutputToFile(*output)
var sim propagation.Simulator
switch *simType {
case "naivep2p":
sim = naivep2p.NewSimulator(data, *naiveP2PN, *naiveP2PDelay)
case "whisperv6":
lvl, err := gethlog.LvlFromString(*gethlogLevel)
if err != nil {
lvl = gethlog.LvlCrit
}
gethlog.Root().SetHandler(gethlog.LvlFilterHandler(lvl, gethlog.StreamHandler(os.Stderr, gethlog.TerminalFormat(true))))
sim = whisperv6.NewSimulator(data)
default:
log.Fatal("Unknown simulation type: ", *simType)
}
defer sim.Stop()
// Start simulation by sending single message
log.Printf("Starting message sending %s simulation for graph with %d nodes...", *simType, len(data.Nodes()))
plog := sim.SendMessage(0, *ttl)
// stats
ss := stats.Analyze(data, plog)
ss := stats.Analyze(data, sim.plog)
ss.PrintVerbose()
err = json.NewEncoder(fd).Encode(plog)
if err != nil {
log.Fatal(err)
}
log.Printf("Written %s propagation data into %s", *simType, *output)
log.Printf("Written propagation data into %s", *output)
}
func setGethLogLevel(level string) {
lvl, err := gethlog.LvlFromString(level)
if err != nil {
lvl = gethlog.LvlCrit
}
gethlog.Root().SetHandler(gethlog.LvlFilterHandler(lvl, gethlog.StreamHandler(os.Stderr, gethlog.TerminalFormat(true))))
}

View File

@ -0,0 +1,55 @@
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"github.com/divan/graphx/graph"
"github.com/status-im/simulation/propagation"
"github.com/status-im/simulation/propagation/whisperv6"
)
// Simulation represents single simulation.
type Simulation struct {
network *graph.Graph
sim propagation.Simulator
plog *propagation.Log
}
// NewSimulation creates Simulation for the given network.
func NewSimulation(network *graph.Graph) *Simulation {
sim := whisperv6.NewSimulator(network)
return &Simulation{
network: network,
sim: sim,
}
}
// Start starts simulation, creating network and preparing it for message sending.
func (s *Simulation) Start() {
s.plog = s.sim.SendMessage(0, 10)
}
// Stop stops simulation and shuts down network.
func (s *Simulation) Stop() error {
return s.sim.Stop()
}
// WriteOutput writes propagation log to the given io.Writer.
func (s *Simulation) WriteOutput(w io.Writer) error {
return json.NewEncoder(w).Encode(s.plog)
}
// WriteOutputToFile writes propagation log to the given io.Writer.
func (s *Simulation) WriteOutputToFile(path string) error {
fd, err := os.Create(path)
if err != nil {
return fmt.Errorf("create output file: %v", err)
}
defer fd.Close()
return s.WriteOutput(fd)
}