diff --git a/README.md b/README.md index 45ef1f6c..3a7111f9 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,10 @@ Install Go interface to ZeroMQ: go get github.com/pebbe/zmq4 ``` -Install glog logging: +Install additional go libraries - glog logging, socket.io: ``` go get github.com/golang/glog +go get github.com/graarh/golang-socketio ``` Install blockbook: @@ -112,7 +113,7 @@ The data are separated to different column families: - stream results to REST and websocket interfaces - parallel sync - rewrite - it is not possible to gracefully stop it now, can leave holes in the block - ~~parallel sync - let rocksdb to compact itself from time to time, otherwise it consumes too much disk space~~ -- disconnect blocks - optimize - full range scan is too slow and takes too much disk space (creates snapshot of the whole outputs), split to multiple iterators +- ~~disconnect blocks - optimize - full range scan is too slow and takes too much disk space (creates snapshot of the whole outputs), split to multiple iterators~~ - disconnect blocks - keep map of transactions in the last 100 blocks - xpub index - tests diff --git a/blockbook.go b/blockbook.go index 19a1ad2d..2637547d 100644 --- a/blockbook.go +++ b/blockbook.go @@ -56,6 +56,8 @@ var ( httpServerBinding = flag.String("httpserver", "", "http server binding [address]:port, if missing no http server") + socketIoBinding = flag.String("socketio", "", "socketio server binding [address]:port[/path], if missing no socketio server") + zeroMQBinding = flag.String("zeromq", "", "binding to zeromq, if missing no zeromq connection") ) @@ -152,6 +154,24 @@ func main() { }() } + var socketIoServer *server.SocketIoServer + if *socketIoBinding != "" { + socketIoServer, err = server.NewSocketIoServer(*socketIoBinding, index, mempool) + if err != nil { + glog.Fatal("socketio: ", err) + } + go func() { + err = socketIoServer.Run() + if err != nil { + if err.Error() == "http: Server closed" { + glog.Info(err) + } else { + glog.Fatal(err) + } + } + }() + } + var mq *bchain.MQ if *zeroMQBinding != "" { if !*synchronize { @@ -193,7 +213,7 @@ func main() { } if httpServer != nil || mq != nil { - waitForSignalAndShutdown(httpServer, mq, 5*time.Second) + waitForSignalAndShutdown(httpServer, socketIoServer, mq, 5*time.Second) } if *synchronize { @@ -263,7 +283,7 @@ func mqHandler(m *bchain.MQMessage) { } } -func waitForSignalAndShutdown(s *server.HTTPServer, mq *bchain.MQ, timeout time.Duration) { +func waitForSignalAndShutdown(https *server.HTTPServer, socketio *server.SocketIoServer, mq *bchain.MQ, timeout time.Duration) { stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM) @@ -280,11 +300,17 @@ func waitForSignalAndShutdown(s *server.HTTPServer, mq *bchain.MQ, timeout time. } } - if s != nil { - if err := s.Shutdown(ctx); err != nil { + if https != nil { + if err := https.Shutdown(ctx); err != nil { glog.Error("HttpServer.Shutdown error: ", err) } } + + if socketio != nil { + if err := socketio.Shutdown(ctx); err != nil { + glog.Error("SocketIo.Shutdown error: ", err) + } + } } func printResult(txid string, vout uint32, isOutput bool) error { diff --git a/server/https.go b/server/https.go index c1594636..d01dddb5 100644 --- a/server/https.go +++ b/server/https.go @@ -42,6 +42,9 @@ func NewHTTPServer(httpServerBinding string, db *db.RocksDB, mempool *bchain.Mem r.HandleFunc("/confirmedTransactions/{address}/{lower}/{higher}", s.confirmedTransactions) r.HandleFunc("/unconfirmedTransactions/{address}", s.unconfirmedTransactions) + // support for testing of socket.io interface + r.PathPrefix("/socket.io/").Handler(http.StripPrefix("/socket.io/", http.FileServer(http.Dir("./server/static/")))) + var h http.Handler = r h = handlers.LoggingHandler(os.Stderr, h) https.Handler = h diff --git a/server/socketio.go b/server/socketio.go new file mode 100644 index 00000000..e8037c1d --- /dev/null +++ b/server/socketio.go @@ -0,0 +1,89 @@ +package server + +import ( + "blockbook/bchain" + "blockbook/db" + "context" + "net/http" + "strings" + + "github.com/golang/glog" + "github.com/graarh/golang-socketio" + "github.com/graarh/golang-socketio/transport" +) + +// SocketIoServer is handle to SocketIoServer +type SocketIoServer struct { + binding string + server *gosocketio.Server + https *http.Server + db *db.RocksDB + mempool *bchain.Mempool +} + +// NewSocketIoServer creates new SocketIo interface to blockbook and returns its handle +func NewSocketIoServer(binding string, db *db.RocksDB, mempool *bchain.Mempool) (*SocketIoServer, error) { + server := gosocketio.NewServer(transport.GetDefaultWebsocketTransport()) + + server.On(gosocketio.OnConnection, func(c *gosocketio.Channel) { + glog.Info("Client connected ", c.Id()) + c.Join("chat") + }) + + server.On(gosocketio.OnDisconnection, func(c *gosocketio.Channel) { + glog.Info("Client disconnected ", c.Id()) + }) + + type Message struct { + Name string `json:"name"` + Message string `json:"message"` + } + + server.On("send", func(c *gosocketio.Channel, msg Message) string { + c.BroadcastTo("chat", "message", msg) + return "OK" + }) + + addr, path := splitBinding(binding) + serveMux := http.NewServeMux() + serveMux.Handle(path, server) + https := &http.Server{ + Addr: addr, + Handler: serveMux, + } + + s := &SocketIoServer{ + binding: binding, + https: https, + server: server, + db: db, + mempool: mempool, + } + return s, nil +} + +func splitBinding(binding string) (addr string, path string) { + i := strings.Index(binding, "/") + if i >= 0 { + return binding[0:i], binding[i:] + } + return binding, "/" +} + +// Run starts the server +func (s *SocketIoServer) Run() error { + glog.Info("socketio server starting to listen on ", s.https.Addr) + return s.https.ListenAndServe() +} + +// Close closes the server +func (s *SocketIoServer) Close() error { + glog.Infof("socketio server closing") + return s.https.Close() +} + +// Shutdown shuts down the server +func (s *SocketIoServer) Shutdown(ctx context.Context) error { + glog.Infof("socketio server shutdown") + return s.https.Shutdown(ctx) +} diff --git a/server/static/test.html b/server/static/test.html new file mode 100644 index 00000000..da2bb2eb --- /dev/null +++ b/server/static/test.html @@ -0,0 +1,34 @@ + + + + + + + + + Test socket.io + + + +
+
+

Socket.io tester

+
+
+ + + \ No newline at end of file