| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | /* | 
					
						
							|  |  |  |   This file is part of go-ethereum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |   it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |   the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |   (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |   GNU General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |   along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2015-01-28 10:22:37 -06:00
										 |  |  | package rpcws | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-27 14:16:34 -06:00
										 |  |  | 	"code.google.com/p/go.net/websocket" | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/rpc" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/xeth" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var wslogger = logger.NewLogger("RPC-WS") | 
					
						
							| 
									
										
										
										
											2015-01-28 10:22:37 -06:00
										 |  |  | var JSON rpc.JsonWrapper | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | type WebSocketServer struct { | 
					
						
							| 
									
										
										
										
											2015-02-02 07:37:44 -06:00
										 |  |  | 	pipe     *xeth.XEth | 
					
						
							|  |  |  | 	port     int | 
					
						
							|  |  |  | 	doneCh   chan bool | 
					
						
							|  |  |  | 	listener net.Listener | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-02 07:37:44 -06:00
										 |  |  | func NewWebSocketServer(pipe *xeth.XEth, port int) (*WebSocketServer, error) { | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 	sport := fmt.Sprintf(":%d", port) | 
					
						
							|  |  |  | 	l, err := net.Listen("tcp", sport) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-02 07:37:44 -06:00
										 |  |  | 	return &WebSocketServer{ | 
					
						
							|  |  |  | 		pipe, | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 		port, | 
					
						
							|  |  |  | 		make(chan bool), | 
					
						
							|  |  |  | 		l, | 
					
						
							|  |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *WebSocketServer) handlerLoop() { | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-self.doneCh: | 
					
						
							|  |  |  | 			wslogger.Infoln("Shutdown RPC-WS server") | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *WebSocketServer) Stop() { | 
					
						
							|  |  |  | 	close(self.doneCh) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *WebSocketServer) Start() { | 
					
						
							|  |  |  | 	wslogger.Infof("Starting RPC-WS server on port %d", self.port) | 
					
						
							|  |  |  | 	go self.handlerLoop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-02 07:37:44 -06:00
										 |  |  | 	api := rpc.NewEthereumApi(self.pipe) | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 	h := self.apiHandler(api) | 
					
						
							|  |  |  | 	http.Handle("/ws", h) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := http.Serve(self.listener, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		wslogger.Errorln("Error on RPC-WS interface:", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-27 14:34:01 -06:00
										 |  |  | func (s *WebSocketServer) apiHandler(api *rpc.EthereumApi) http.Handler { | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 	fn := func(w http.ResponseWriter, req *http.Request) { | 
					
						
							| 
									
										
										
										
											2015-01-27 14:34:01 -06:00
										 |  |  | 		h := sockHandler(api) | 
					
						
							| 
									
										
										
										
											2015-01-27 14:16:34 -06:00
										 |  |  | 		s := websocket.Server{Handler: h} | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 		s.ServeHTTP(w, req) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return http.HandlerFunc(fn) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-27 14:34:01 -06:00
										 |  |  | func sockHandler(api *rpc.EthereumApi) websocket.Handler { | 
					
						
							| 
									
										
										
										
											2015-02-03 17:29:29 -06:00
										 |  |  | 	var jsonrpcver string = "2.0" | 
					
						
							| 
									
										
										
										
											2015-01-27 14:16:34 -06:00
										 |  |  | 	fn := func(conn *websocket.Conn) { | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 		for { | 
					
						
							| 
									
										
										
										
											2015-01-28 10:22:37 -06:00
										 |  |  | 			wslogger.Debugln("Handling connection") | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 			var reqParsed rpc.RpcRequest | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-28 10:22:37 -06:00
										 |  |  | 			// reqParsed, reqerr := JSON.ParseRequestBody(conn.Request()) | 
					
						
							| 
									
										
										
										
											2015-01-27 14:16:34 -06:00
										 |  |  | 			if err := websocket.JSON.Receive(conn, &reqParsed); err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-03 17:29:29 -06:00
										 |  |  | 				jsonerr := &rpc.RpcErrorObject{-32700, rpc.ErrorParseRequest} | 
					
						
							|  |  |  | 				JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr}) | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var response interface{} | 
					
						
							| 
									
										
										
										
											2015-01-27 14:34:01 -06:00
										 |  |  | 			reserr := api.GetRequestReply(&reqParsed, &response) | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 			if reserr != nil { | 
					
						
							| 
									
										
										
										
											2015-02-03 17:29:29 -06:00
										 |  |  | 				wslogger.Warnln(reserr) | 
					
						
							|  |  |  | 				jsonerr := &rpc.RpcErrorObject{-32603, reserr.Error()} | 
					
						
							| 
									
										
										
										
											2015-02-11 11:56:29 +01:00
										 |  |  | 				JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr}) | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			wslogger.Debugf("Generated response: %T %s", response, response) | 
					
						
							| 
									
										
										
										
											2015-02-03 17:29:29 -06:00
										 |  |  | 			JSON.Send(conn, &rpc.RpcSuccessResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Result: response}) | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-27 14:26:42 -06:00
										 |  |  | 	return websocket.Handler(fn) | 
					
						
							| 
									
										
										
										
											2015-01-27 12:27:14 -06:00
										 |  |  | } |