github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/rpc/ws/server.go (about) 1 /* 2 This file is part of go-ethereum 3 4 go-ethereum is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 go-ethereum is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 package rpcws 18 19 import ( 20 "fmt" 21 "net" 22 "net/http" 23 24 "code.google.com/p/go.net/websocket" 25 "github.com/jonasnick/go-ethereum/logger" 26 "github.com/jonasnick/go-ethereum/rpc" 27 "github.com/jonasnick/go-ethereum/xeth" 28 ) 29 30 var wslogger = logger.NewLogger("RPC-WS") 31 var JSON rpc.JsonWrapper 32 33 type WebSocketServer struct { 34 pipe *xeth.XEth 35 port int 36 doneCh chan bool 37 listener net.Listener 38 } 39 40 func NewWebSocketServer(pipe *xeth.XEth, port int) (*WebSocketServer, error) { 41 sport := fmt.Sprintf(":%d", port) 42 l, err := net.Listen("tcp", sport) 43 if err != nil { 44 return nil, err 45 } 46 47 return &WebSocketServer{ 48 pipe, 49 port, 50 make(chan bool), 51 l, 52 }, nil 53 } 54 55 func (self *WebSocketServer) handlerLoop() { 56 for { 57 select { 58 case <-self.doneCh: 59 wslogger.Infoln("Shutdown RPC-WS server") 60 return 61 } 62 } 63 } 64 65 func (self *WebSocketServer) Stop() { 66 close(self.doneCh) 67 } 68 69 func (self *WebSocketServer) Start() { 70 wslogger.Infof("Starting RPC-WS server on port %d", self.port) 71 go self.handlerLoop() 72 73 api := rpc.NewEthereumApi(self.pipe) 74 h := self.apiHandler(api) 75 http.Handle("/ws", h) 76 77 err := http.Serve(self.listener, nil) 78 if err != nil { 79 wslogger.Errorln("Error on RPC-WS interface:", err) 80 } 81 } 82 83 func (s *WebSocketServer) apiHandler(api *rpc.EthereumApi) http.Handler { 84 fn := func(w http.ResponseWriter, req *http.Request) { 85 h := sockHandler(api) 86 s := websocket.Server{Handler: h} 87 s.ServeHTTP(w, req) 88 } 89 90 return http.HandlerFunc(fn) 91 } 92 93 func sockHandler(api *rpc.EthereumApi) websocket.Handler { 94 var jsonrpcver string = "2.0" 95 fn := func(conn *websocket.Conn) { 96 for { 97 wslogger.Debugln("Handling connection") 98 var reqParsed rpc.RpcRequest 99 100 // reqParsed, reqerr := JSON.ParseRequestBody(conn.Request()) 101 if err := websocket.JSON.Receive(conn, &reqParsed); err != nil { 102 jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest} 103 JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr}) 104 continue 105 } 106 107 var response interface{} 108 reserr := api.GetRequestReply(&reqParsed, &response) 109 if reserr != nil { 110 wslogger.Warnln(reserr) 111 jsonerr := &rpc.RpcErrorObject{-32603, reserr.Error()} 112 JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr}) 113 continue 114 } 115 116 wslogger.Debugf("Generated response: %T %s", response, response) 117 JSON.Send(conn, &rpc.RpcSuccessResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Result: response}) 118 } 119 } 120 return websocket.Handler(fn) 121 }