Support for socket.io interface, initial commit

pull/1/head
Martin Boehm 2018-02-06 12:06:30 +01:00
parent ec87f4ed8d
commit b0f163e21c
5 changed files with 159 additions and 6 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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

89
server/socketio.go 100644
View File

@ -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)
}

View File

@ -0,0 +1,34 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.4/socket.io.js"></script>
<title>Test socket.io</title>
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<h1>Socket.io tester</h1>
</div>
</div>
</body>
<script>
var socket = io('ws://127.0.0.1:8334', { transports: ['websocket'] });
socket.on('message', function (message) {
console.log('new message');
console.log(message);
});
socket.on('connect', function () {
console.log('socket connected');
socket.emit('send', { name: "my name", message: "hello" }, function (result) {
console.log('sent successfully');
console.log(result);
});
});
</script>
</html>