mirror of
https://github.com/status-im/simulation.git
synced 2025-02-23 04:18:09 +00:00
Add server
This commit is contained in:
parent
c82b8d22af
commit
2e30599707
1028
cmd/propagation_simulator/data_test.go
Normal file
1028
cmd/propagation_simulator/data_test.go
Normal file
File diff suppressed because it is too large
Load Diff
37
cmd/propagation_simulator/handler.go
Normal file
37
cmd/propagation_simulator/handler.go
Normal 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)
|
||||||
|
}
|
35
cmd/propagation_simulator/handler_test.go
Normal file
35
cmd/propagation_simulator/handler_test.go
Normal 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())
|
||||||
|
}
|
||||||
|
}
|
@ -1,70 +1,59 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/divan/graphx/formats"
|
"github.com/divan/graphx/formats"
|
||||||
gethlog "github.com/ethereum/go-ethereum/log"
|
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"
|
"github.com/status-im/simulation/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
var (
|
||||||
simType = flag.String("type", "whisperv6", "Type of simulators (naivep2p, whisperv6)")
|
input = flag.String("i", "network.json", "Input filename for pregenerated data to be used with simulation")
|
||||||
ttl = flag.Int("ttl", 10, "Message TTL for simulation")
|
output = flag.String("o", "propagation.json", "Output filename for p2p sending data")
|
||||||
naiveP2PN = flag.Int("naivep2p.N", 3, "Number of peers to propagate (0..N of peers)")
|
gethlogLevel = flag.String("loglevel", "crit", "Geth log level for whisper simulator (crti, error, warn, info, debug, trace)")
|
||||||
naiveP2PDelay = flag.Duration("naivep2p.delay", 10*time.Millisecond, "Delay for each step")
|
server = flag.Bool("server", false, "Start as server to be used with whisperviz")
|
||||||
input = flag.String("i", "network.json", "Input filename for pregenerated data to be used with simulation")
|
serverAddr = flag.String("h", "localhost:8084", "Address to bind to in server mode")
|
||||||
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)")
|
|
||||||
)
|
)
|
||||||
flag.Parse()
|
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)
|
data, err := formats.FromD3JSON(*input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Opening input file failed: ", err)
|
log.Fatal("Opening input file failed: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := os.Create(*output)
|
sim := NewSimulation(data)
|
||||||
if err != nil {
|
log.Printf("Starting message sending simulation for graph with %d nodes...", len(data.Nodes()))
|
||||||
log.Fatal("Opening output file failed: ", err)
|
sim.Start()
|
||||||
}
|
defer sim.Stop()
|
||||||
defer fd.Close()
|
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()
|
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
|
// stats
|
||||||
ss := stats.Analyze(data, plog)
|
ss := stats.Analyze(data, sim.plog)
|
||||||
ss.PrintVerbose()
|
ss.PrintVerbose()
|
||||||
|
|
||||||
err = json.NewEncoder(fd).Encode(plog)
|
log.Printf("Written propagation data into %s", *output)
|
||||||
if err != nil {
|
}
|
||||||
log.Fatal(err)
|
|
||||||
}
|
func setGethLogLevel(level string) {
|
||||||
log.Printf("Written %s propagation data into %s", *simType, *output)
|
lvl, err := gethlog.LvlFromString(level)
|
||||||
|
if err != nil {
|
||||||
|
lvl = gethlog.LvlCrit
|
||||||
|
}
|
||||||
|
gethlog.Root().SetHandler(gethlog.LvlFilterHandler(lvl, gethlog.StreamHandler(os.Stderr, gethlog.TerminalFormat(true))))
|
||||||
}
|
}
|
||||||
|
55
cmd/propagation_simulator/simulation.go
Normal file
55
cmd/propagation_simulator/simulation.go
Normal 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)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user