| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | package comms | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/logger/glog" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/rpc/codec" | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rpc/shared" | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 	"github.com/rs/cors" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	serverIdleTimeout  = 10 * time.Second // idle keep-alive connections | 
					
						
							|  |  |  | 	serverReadTimeout  = 15 * time.Second // per-request read timeout | 
					
						
							|  |  |  | 	serverWriteTimeout = 15 * time.Second // per-request read timeout | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | var ( | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	httpServerMu sync.Mutex | 
					
						
							|  |  |  | 	httpServer   *stopServer | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type HttpConfig struct { | 
					
						
							|  |  |  | 	ListenAddress string | 
					
						
							|  |  |  | 	ListenPort    uint | 
					
						
							|  |  |  | 	CorsDomain    string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | // stopServer augments http.Server with idle connection tracking. | 
					
						
							|  |  |  | // Idle keep-alive connections are shut down when Close is called. | 
					
						
							|  |  |  | type stopServer struct { | 
					
						
							|  |  |  | 	*http.Server | 
					
						
							|  |  |  | 	l net.Listener | 
					
						
							|  |  |  | 	// connection tracking state | 
					
						
							|  |  |  | 	mu       sync.Mutex | 
					
						
							|  |  |  | 	shutdown bool // true when Stop has returned | 
					
						
							|  |  |  | 	idle     map[net.Conn]struct{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type handler struct { | 
					
						
							|  |  |  | 	codec codec.Codec | 
					
						
							|  |  |  | 	api   shared.EthereumApi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StartHTTP starts listening for RPC requests sent via HTTP. | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | func StartHttp(cfg HttpConfig, codec codec.Codec, api shared.EthereumApi) error { | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	httpServerMu.Lock() | 
					
						
							|  |  |  | 	defer httpServerMu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	addr := fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort) | 
					
						
							|  |  |  | 	if httpServer != nil { | 
					
						
							|  |  |  | 		if addr != httpServer.Addr { | 
					
						
							|  |  |  | 			return fmt.Errorf("RPC service already running on %s ", httpServer.Addr) | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return nil // RPC service already running on given host/port | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	// Set up the request handler, wrapping it with CORS headers if configured. | 
					
						
							|  |  |  | 	handler := http.Handler(&handler{codec, api}) | 
					
						
							|  |  |  | 	if len(cfg.CorsDomain) > 0 { | 
					
						
							|  |  |  | 		opts := cors.Options{ | 
					
						
							|  |  |  | 			AllowedMethods: []string{"POST"}, | 
					
						
							|  |  |  | 			AllowedOrigins: strings.Split(cfg.CorsDomain, " "), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		handler = cors.New(opts).Handler(handler) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Start the server. | 
					
						
							|  |  |  | 	s, err := listenHTTP(addr, handler) | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		glog.V(logger.Error).Infof("Can't listen on %s:%d: %v", cfg.ListenAddress, cfg.ListenPort, err) | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	httpServer = s | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { | 
					
						
							|  |  |  | 	w.Header().Set("Content-Type", "application/json") | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	// Limit request size to resist DoS | 
					
						
							|  |  |  | 	if req.ContentLength > maxHttpSizeReqLength { | 
					
						
							|  |  |  | 		err := fmt.Errorf("Request too large") | 
					
						
							|  |  |  | 		response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err) | 
					
						
							|  |  |  | 		sendJSON(w, &response) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	defer req.Body.Close() | 
					
						
							|  |  |  | 	payload, err := ioutil.ReadAll(req.Body) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		err := fmt.Errorf("Could not read request body") | 
					
						
							|  |  |  | 		response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err) | 
					
						
							|  |  |  | 		sendJSON(w, &response) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	c := h.codec.New(nil) | 
					
						
							|  |  |  | 	var rpcReq shared.Request | 
					
						
							|  |  |  | 	if err = c.Decode(payload, &rpcReq); err == nil { | 
					
						
							|  |  |  | 		reply, err := h.api.Execute(&rpcReq) | 
					
						
							|  |  |  | 		res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err) | 
					
						
							|  |  |  | 		sendJSON(w, &res) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	var reqBatch []shared.Request | 
					
						
							|  |  |  | 	if err = c.Decode(payload, &reqBatch); err == nil { | 
					
						
							|  |  |  | 		resBatch := make([]*interface{}, len(reqBatch)) | 
					
						
							|  |  |  | 		resCount := 0 | 
					
						
							|  |  |  | 		for i, rpcReq := range reqBatch { | 
					
						
							|  |  |  | 			reply, err := h.api.Execute(&rpcReq) | 
					
						
							|  |  |  | 			if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal | 
					
						
							|  |  |  | 				resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err) | 
					
						
							|  |  |  | 				resCount += 1 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// make response omitting nil entries | 
					
						
							|  |  |  | 		sendJSON(w, resBatch[:resCount]) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// invalid request | 
					
						
							|  |  |  | 	err = fmt.Errorf("Could not decode request") | 
					
						
							|  |  |  | 	res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err) | 
					
						
							|  |  |  | 	sendJSON(w, res) | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | func sendJSON(w io.Writer, v interface{}) { | 
					
						
							|  |  |  | 	if glog.V(logger.Detail) { | 
					
						
							|  |  |  | 		if payload, err := json.MarshalIndent(v, "", "\t"); err == nil { | 
					
						
							|  |  |  | 			glog.Infof("Sending payload: %s", payload) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := json.NewEncoder(w).Encode(v); err != nil { | 
					
						
							|  |  |  | 		glog.V(logger.Error).Infoln("Error sending JSON:", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stop closes all active HTTP connections and shuts down the server. | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | func StopHttp() { | 
					
						
							| 
									
										
										
										
											2015-08-03 02:29:59 +02:00
										 |  |  | 	httpServerMu.Lock() | 
					
						
							|  |  |  | 	defer httpServerMu.Unlock() | 
					
						
							|  |  |  | 	if httpServer != nil { | 
					
						
							|  |  |  | 		httpServer.Close() | 
					
						
							|  |  |  | 		httpServer = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func listenHTTP(addr string, h http.Handler) (*stopServer, error) { | 
					
						
							|  |  |  | 	l, err := net.Listen("tcp", addr) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s := &stopServer{l: l, idle: make(map[net.Conn]struct{})} | 
					
						
							|  |  |  | 	s.Server = &http.Server{ | 
					
						
							|  |  |  | 		Addr:         addr, | 
					
						
							|  |  |  | 		Handler:      h, | 
					
						
							|  |  |  | 		ReadTimeout:  serverReadTimeout, | 
					
						
							|  |  |  | 		WriteTimeout: serverWriteTimeout, | 
					
						
							|  |  |  | 		ConnState:    s.connState, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	go s.Serve(l) | 
					
						
							|  |  |  | 	return s, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *stopServer) connState(c net.Conn, state http.ConnState) { | 
					
						
							|  |  |  | 	s.mu.Lock() | 
					
						
							|  |  |  | 	defer s.mu.Unlock() | 
					
						
							|  |  |  | 	// Close c immediately if we're past shutdown. | 
					
						
							|  |  |  | 	if s.shutdown { | 
					
						
							|  |  |  | 		if state != http.StateClosed { | 
					
						
							|  |  |  | 			c.Close() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if state == http.StateIdle { | 
					
						
							|  |  |  | 		s.idle[c] = struct{}{} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		delete(s.idle, c) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *stopServer) Close() { | 
					
						
							|  |  |  | 	s.mu.Lock() | 
					
						
							|  |  |  | 	defer s.mu.Unlock() | 
					
						
							|  |  |  | 	// Shut down the acceptor. No new connections can be created. | 
					
						
							|  |  |  | 	s.l.Close() | 
					
						
							|  |  |  | 	// Drop all idle connections. Non-idle connections will be | 
					
						
							|  |  |  | 	// closed by connState as soon as they become idle. | 
					
						
							|  |  |  | 	s.shutdown = true | 
					
						
							|  |  |  | 	for c := range s.idle { | 
					
						
							|  |  |  | 		glog.V(logger.Detail).Infof("closing idle connection %v", c.RemoteAddr()) | 
					
						
							|  |  |  | 		c.Close() | 
					
						
							|  |  |  | 		delete(s.idle, c) | 
					
						
							| 
									
										
										
										
											2015-06-16 13:07:13 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-17 16:22:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | type httpClient struct { | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 	address string | 
					
						
							|  |  |  | 	port    uint | 
					
						
							|  |  |  | 	codec   codec.ApiCoder | 
					
						
							|  |  |  | 	lastRes interface{} | 
					
						
							|  |  |  | 	lastErr error | 
					
						
							| 
									
										
										
										
											2015-06-17 16:22:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Create a new in process client | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | func NewHttpClient(cfg HttpConfig, c codec.Codec) *httpClient { | 
					
						
							| 
									
										
										
										
											2015-06-17 16:22:35 +02:00
										 |  |  | 	return &httpClient{ | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 		address: cfg.ListenAddress, | 
					
						
							|  |  |  | 		port:    cfg.ListenPort, | 
					
						
							|  |  |  | 		codec:   c.New(nil), | 
					
						
							| 
									
										
										
										
											2015-06-17 16:22:35 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *httpClient) Close() { | 
					
						
							|  |  |  | 	// do nothing | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *httpClient) Send(req interface{}) error { | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 	var body []byte | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self.lastRes = nil | 
					
						
							|  |  |  | 	self.lastErr = nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if body, err = self.codec.Encode(req); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	httpReq, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	httpReq.Header.Set("Content-Type", "application/json") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	client := http.Client{} | 
					
						
							|  |  |  | 	resp, err := client.Do(httpReq) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	defer resp.Body.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if resp.Status == "200 OK" { | 
					
						
							|  |  |  | 		reply, _ := ioutil.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		var rpcSuccessResponse shared.SuccessResponse | 
					
						
							|  |  |  | 		if err = self.codec.Decode(reply, &rpcSuccessResponse); err == nil { | 
					
						
							| 
									
										
										
										
											2015-09-07 15:09:59 +01:00
										 |  |  | 			self.lastRes = &rpcSuccessResponse | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 			self.lastErr = err | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var rpcErrorResponse shared.ErrorResponse | 
					
						
							|  |  |  | 			if err = self.codec.Decode(reply, &rpcErrorResponse); err == nil { | 
					
						
							| 
									
										
										
										
											2015-09-07 15:09:59 +01:00
										 |  |  | 				self.lastRes = &rpcErrorResponse | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 				self.lastErr = err | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return fmt.Errorf("Not implemented") | 
					
						
							| 
									
										
										
										
											2015-06-17 16:22:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *httpClient) Recv() (interface{}, error) { | 
					
						
							| 
									
										
										
										
											2015-06-19 12:32:40 +02:00
										 |  |  | 	return self.lastRes, self.lastErr | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *httpClient) SupportedModules() (map[string]string, error) { | 
					
						
							|  |  |  | 	var body []byte | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	payload := shared.Request{ | 
					
						
							|  |  |  | 		Id:      1, | 
					
						
							|  |  |  | 		Jsonrpc: "2.0", | 
					
						
							|  |  |  | 		Method:  "modules", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if body, err = self.codec.Encode(payload); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	req.Header.Set("Content-Type", "application/json") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	client := http.Client{} | 
					
						
							|  |  |  | 	resp, err := client.Do(req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	defer resp.Body.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if resp.Status == "200 OK" { | 
					
						
							|  |  |  | 		reply, _ := ioutil.ReadAll(resp.Body) | 
					
						
							|  |  |  | 		var rpcRes shared.SuccessResponse | 
					
						
							|  |  |  | 		if err = self.codec.Decode(reply, &rpcRes); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		result := make(map[string]string) | 
					
						
							|  |  |  | 		if modules, ok := rpcRes.Result.(map[string]interface{}); ok { | 
					
						
							|  |  |  | 			for a, v := range modules { | 
					
						
							|  |  |  | 				result[a] = fmt.Sprintf("%s", v) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return result, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err = fmt.Errorf("Unable to parse module response - %v", rpcRes.Result) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		fmt.Printf("resp.Status = %s\n", resp.Status) | 
					
						
							|  |  |  | 		fmt.Printf("err = %v\n", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil, err | 
					
						
							| 
									
										
										
										
											2015-06-18 18:23:13 +02:00
										 |  |  | } |