You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

516 lines
15 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package rpcserver
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io/ioutil"
  8. "net/http"
  9. "reflect"
  10. "sort"
  11. "time"
  12. "github.com/gorilla/websocket"
  13. . "github.com/tendermint/go-common"
  14. "github.com/tendermint/go-wire"
  15. "github.com/tendermint/tendermint/events"
  16. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  17. . "github.com/tendermint/tendermint/rpc/types"
  18. "github.com/tendermint/tendermint/types"
  19. )
  20. func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc) {
  21. // HTTP endpoints
  22. for funcName, rpcFunc := range funcMap {
  23. mux.HandleFunc("/"+funcName, makeHTTPHandler(rpcFunc))
  24. }
  25. // JSONRPC endpoints
  26. mux.HandleFunc("/", makeJSONRPCHandler(funcMap))
  27. }
  28. //-------------------------------------
  29. // function introspection
  30. // holds all type information for each function
  31. type RPCFunc struct {
  32. f reflect.Value // underlying rpc function
  33. args []reflect.Type // type of each function arg
  34. returns []reflect.Type // type of each return arg
  35. argNames []string // name of each argument
  36. }
  37. // wraps a function for quicker introspection
  38. func NewRPCFunc(f interface{}, args []string) *RPCFunc {
  39. return &RPCFunc{
  40. f: reflect.ValueOf(f),
  41. args: funcArgTypes(f),
  42. returns: funcReturnTypes(f),
  43. argNames: args,
  44. }
  45. }
  46. // return a function's argument types
  47. func funcArgTypes(f interface{}) []reflect.Type {
  48. t := reflect.TypeOf(f)
  49. n := t.NumIn()
  50. typez := make([]reflect.Type, n)
  51. for i := 0; i < n; i++ {
  52. typez[i] = t.In(i)
  53. }
  54. return typez
  55. }
  56. // return a function's return types
  57. func funcReturnTypes(f interface{}) []reflect.Type {
  58. t := reflect.TypeOf(f)
  59. n := t.NumOut()
  60. typez := make([]reflect.Type, n)
  61. for i := 0; i < n; i++ {
  62. typez[i] = t.Out(i)
  63. }
  64. return typez
  65. }
  66. // function introspection
  67. //-----------------------------------------------------------------------------
  68. // rpc.json
  69. // jsonrpc calls grab the given method's function info and runs reflect.Call
  70. func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc {
  71. return func(w http.ResponseWriter, r *http.Request) {
  72. b, _ := ioutil.ReadAll(r.Body)
  73. // if its an empty request (like from a browser),
  74. // just display a list of functions
  75. if len(b) == 0 {
  76. writeListOfEndpoints(w, r, funcMap)
  77. return
  78. }
  79. var request RPCRequest
  80. err := json.Unmarshal(b, &request)
  81. if err != nil {
  82. WriteRPCResponse(w, NewRPCResponse("", nil, err.Error()))
  83. return
  84. }
  85. if len(r.URL.Path) > 1 {
  86. WriteRPCResponse(w, NewRPCResponse(request.ID, nil, fmt.Sprintf("Invalid JSONRPC endpoint %s", r.URL.Path)))
  87. return
  88. }
  89. rpcFunc := funcMap[request.Method]
  90. if rpcFunc == nil {
  91. WriteRPCResponse(w, NewRPCResponse(request.ID, nil, "RPC method unknown: "+request.Method))
  92. return
  93. }
  94. args, err := jsonParamsToArgs(rpcFunc, request.Params)
  95. if err != nil {
  96. WriteRPCResponse(w, NewRPCResponse(request.ID, nil, err.Error()))
  97. return
  98. }
  99. returns := rpcFunc.f.Call(args)
  100. log.Info("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns)
  101. result, err := unreflectResult(returns)
  102. if err != nil {
  103. WriteRPCResponse(w, NewRPCResponse(request.ID, nil, err.Error()))
  104. return
  105. }
  106. WriteRPCResponse(w, NewRPCResponse(request.ID, result, ""))
  107. }
  108. }
  109. // covert a list of interfaces to properly typed values
  110. func jsonParamsToArgs(rpcFunc *RPCFunc, params []interface{}) ([]reflect.Value, error) {
  111. if len(rpcFunc.argNames) != len(params) {
  112. return nil, errors.New(fmt.Sprintf("Expected %v parameters (%v), got %v (%v)",
  113. len(rpcFunc.argNames), rpcFunc.argNames, len(params), params))
  114. }
  115. values := make([]reflect.Value, len(params))
  116. for i, p := range params {
  117. ty := rpcFunc.args[i]
  118. v, err := _jsonObjectToArg(ty, p)
  119. if err != nil {
  120. return nil, err
  121. }
  122. values[i] = v
  123. }
  124. return values, nil
  125. }
  126. func _jsonObjectToArg(ty reflect.Type, object interface{}) (reflect.Value, error) {
  127. var err error
  128. v := reflect.New(ty)
  129. wire.ReadJSONObjectPtr(v.Interface(), object, &err)
  130. if err != nil {
  131. return v, err
  132. }
  133. v = v.Elem()
  134. return v, nil
  135. }
  136. // rpc.json
  137. //-----------------------------------------------------------------------------
  138. // rpc.http
  139. // convert from a function name to the http handler
  140. func makeHTTPHandler(rpcFunc *RPCFunc) func(http.ResponseWriter, *http.Request) {
  141. return func(w http.ResponseWriter, r *http.Request) {
  142. args, err := httpParamsToArgs(rpcFunc, r)
  143. if err != nil {
  144. WriteRPCResponse(w, NewRPCResponse("", nil, err.Error()))
  145. return
  146. }
  147. returns := rpcFunc.f.Call(args)
  148. log.Info("HTTPRestRPC", "method", r.URL.Path, "args", args, "returns", returns)
  149. result, err := unreflectResult(returns)
  150. if err != nil {
  151. WriteRPCResponse(w, NewRPCResponse("", nil, err.Error()))
  152. return
  153. }
  154. WriteRPCResponse(w, NewRPCResponse("", result, ""))
  155. }
  156. }
  157. // Covert an http query to a list of properly typed values.
  158. // To be properly decoded the arg must be a concrete type from tendermint (if its an interface).
  159. func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error) {
  160. argTypes := rpcFunc.args
  161. argNames := rpcFunc.argNames
  162. var err error
  163. values := make([]reflect.Value, len(argNames))
  164. for i, name := range argNames {
  165. ty := argTypes[i]
  166. arg := GetParam(r, name)
  167. values[i], err = _jsonStringToArg(ty, arg)
  168. if err != nil {
  169. return nil, err
  170. }
  171. }
  172. return values, nil
  173. }
  174. func _jsonStringToArg(ty reflect.Type, arg string) (reflect.Value, error) {
  175. var err error
  176. v := reflect.New(ty)
  177. wire.ReadJSONPtr(v.Interface(), []byte(arg), &err)
  178. if err != nil {
  179. return v, err
  180. }
  181. v = v.Elem()
  182. return v, nil
  183. }
  184. // rpc.http
  185. //-----------------------------------------------------------------------------
  186. // rpc.websocket
  187. const (
  188. writeChanCapacity = 20
  189. wsWriteTimeoutSeconds = 30 // each write times out after this
  190. wsReadTimeoutSeconds = 30 // connection times out if we haven't received *anything* in this long, not even pings.
  191. wsPingTickerSeconds = 10 // send a ping every PingTickerSeconds.
  192. )
  193. // a single websocket connection
  194. // contains listener id, underlying ws connection,
  195. // and the event switch for subscribing to events
  196. type WSConnection struct {
  197. QuitService
  198. id string
  199. baseConn *websocket.Conn
  200. writeChan chan RPCResponse
  201. readTimeout *time.Timer
  202. pingTicker *time.Ticker
  203. funcMap map[string]*RPCFunc
  204. evsw *events.EventSwitch
  205. }
  206. // new websocket connection wrapper
  207. func NewWSConnection(baseConn *websocket.Conn, funcMap map[string]*RPCFunc, evsw *events.EventSwitch) *WSConnection {
  208. wsc := &WSConnection{
  209. id: baseConn.RemoteAddr().String(),
  210. baseConn: baseConn,
  211. writeChan: make(chan RPCResponse, writeChanCapacity), // error when full.
  212. funcMap: funcMap,
  213. evsw: evsw,
  214. }
  215. wsc.QuitService = *NewQuitService(log, "WSConnection", wsc)
  216. return wsc
  217. }
  218. // wsc.Start() blocks until the connection closes.
  219. func (wsc *WSConnection) OnStart() error {
  220. wsc.QuitService.OnStart()
  221. // Read subscriptions/unsubscriptions to events
  222. go wsc.readRoutine()
  223. // Custom Ping handler to touch readTimeout
  224. wsc.readTimeout = time.NewTimer(time.Second * wsReadTimeoutSeconds)
  225. wsc.pingTicker = time.NewTicker(time.Second * wsPingTickerSeconds)
  226. wsc.baseConn.SetPingHandler(func(m string) error {
  227. wsc.baseConn.WriteControl(websocket.PongMessage, []byte(m), time.Now().Add(time.Second*wsWriteTimeoutSeconds))
  228. wsc.readTimeout.Reset(time.Second * wsReadTimeoutSeconds)
  229. return nil
  230. })
  231. wsc.baseConn.SetPongHandler(func(m string) error {
  232. wsc.readTimeout.Reset(time.Second * wsReadTimeoutSeconds)
  233. return nil
  234. })
  235. go wsc.readTimeoutRoutine()
  236. // Write responses, BLOCKING.
  237. wsc.writeRoutine()
  238. return nil
  239. }
  240. func (wsc *WSConnection) OnStop() {
  241. wsc.QuitService.OnStop()
  242. wsc.evsw.RemoveListener(wsc.id)
  243. wsc.readTimeout.Stop()
  244. wsc.pingTicker.Stop()
  245. // The write loop closes the websocket connection
  246. // when it exits its loop, and the read loop
  247. // closes the writeChan
  248. }
  249. func (wsc *WSConnection) readTimeoutRoutine() {
  250. select {
  251. case <-wsc.readTimeout.C:
  252. log.Notice("Stopping connection due to read timeout")
  253. wsc.Stop()
  254. case <-wsc.Quit:
  255. return
  256. }
  257. }
  258. // Attempt to write response to writeChan and record failures
  259. func (wsc *WSConnection) writeRPCResponse(resp RPCResponse) {
  260. select {
  261. case wsc.writeChan <- resp:
  262. default:
  263. log.Notice("Stopping connection due to writeChan overflow", "id", wsc.id)
  264. wsc.Stop() // writeChan capacity exceeded, error.
  265. }
  266. }
  267. // Read from the socket and subscribe to or unsubscribe from events
  268. func (wsc *WSConnection) readRoutine() {
  269. // Do not close writeChan, to allow writeRPCResponse() to fail.
  270. // defer close(wsc.writeChan)
  271. for {
  272. select {
  273. case <-wsc.Quit:
  274. return
  275. default:
  276. var in []byte
  277. // Do not set a deadline here like below:
  278. // wsc.baseConn.SetReadDeadline(time.Now().Add(time.Second * wsReadTimeoutSeconds))
  279. // The client may not send anything for a while.
  280. // We use `readTimeout` to handle read timeouts.
  281. _, in, err := wsc.baseConn.ReadMessage()
  282. if err != nil {
  283. log.Notice("Failed to read from connection", "id", wsc.id)
  284. // an error reading the connection,
  285. // kill the connection
  286. wsc.Stop()
  287. return
  288. }
  289. var request RPCRequest
  290. err = json.Unmarshal(in, &request)
  291. if err != nil {
  292. errStr := fmt.Sprintf("Error unmarshaling data: %s", err.Error())
  293. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, errStr))
  294. continue
  295. }
  296. switch request.Method {
  297. case "subscribe":
  298. if len(request.Params) != 1 {
  299. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, "subscribe takes 1 event parameter string"))
  300. continue
  301. }
  302. if event, ok := request.Params[0].(string); !ok {
  303. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, "subscribe takes 1 event parameter string"))
  304. continue
  305. } else {
  306. log.Notice("Subscribe to event", "id", wsc.id, "event", event)
  307. wsc.evsw.AddListenerForEvent(wsc.id, event, func(msg types.EventData) {
  308. // NOTE: RPCResponses of subscribed events have id suffix "#event"
  309. wsc.writeRPCResponse(NewRPCResponse(request.ID+"#event", ctypes.ResultEvent{event, msg}, ""))
  310. })
  311. continue
  312. }
  313. case "unsubscribe":
  314. if len(request.Params) == 0 {
  315. log.Notice("Unsubscribe from all events", "id", wsc.id)
  316. wsc.evsw.RemoveListener(wsc.id)
  317. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, ""))
  318. continue
  319. } else if len(request.Params) == 1 {
  320. if event, ok := request.Params[0].(string); !ok {
  321. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, "unsubscribe takes 0 or 1 event parameter strings"))
  322. continue
  323. } else {
  324. log.Notice("Unsubscribe from event", "id", wsc.id, "event", event)
  325. wsc.evsw.RemoveListenerForEvent(event, wsc.id)
  326. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, ""))
  327. continue
  328. }
  329. } else {
  330. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, "unsubscribe takes 0 or 1 event parameter strings"))
  331. continue
  332. }
  333. default:
  334. rpcFunc := wsc.funcMap[request.Method]
  335. if rpcFunc == nil {
  336. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, "RPC method unknown: "+request.Method))
  337. continue
  338. }
  339. args, err := jsonParamsToArgs(rpcFunc, request.Params)
  340. if err != nil {
  341. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, err.Error()))
  342. continue
  343. }
  344. returns := rpcFunc.f.Call(args)
  345. log.Info("WSJSONRPC", "method", request.Method, "args", args, "returns", returns)
  346. result, err := unreflectResult(returns)
  347. if err != nil {
  348. wsc.writeRPCResponse(NewRPCResponse(request.ID, nil, err.Error()))
  349. continue
  350. } else {
  351. wsc.writeRPCResponse(NewRPCResponse(request.ID, result, ""))
  352. continue
  353. }
  354. }
  355. }
  356. }
  357. }
  358. // receives on a write channel and writes out on the socket
  359. func (wsc *WSConnection) writeRoutine() {
  360. defer wsc.baseConn.Close()
  361. var n, err = int(0), error(nil)
  362. for {
  363. select {
  364. case <-wsc.Quit:
  365. return
  366. case <-wsc.pingTicker.C:
  367. err := wsc.baseConn.WriteMessage(websocket.PingMessage, []byte{})
  368. if err != nil {
  369. log.Error("Failed to write ping message on websocket", "error", err)
  370. wsc.Stop()
  371. return
  372. }
  373. case msg := <-wsc.writeChan:
  374. buf := new(bytes.Buffer)
  375. wire.WriteJSON(msg, buf, &n, &err)
  376. if err != nil {
  377. log.Error("Failed to marshal RPCResponse to JSON", "error", err)
  378. } else {
  379. wsc.baseConn.SetWriteDeadline(time.Now().Add(time.Second * wsWriteTimeoutSeconds))
  380. if err = wsc.baseConn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil {
  381. log.Warn("Failed to write response on websocket", "error", err)
  382. wsc.Stop()
  383. return
  384. }
  385. }
  386. }
  387. }
  388. }
  389. //----------------------------------------
  390. // Main manager for all websocket connections
  391. // Holds the event switch
  392. // NOTE: The websocket path is defined externally, e.g. in node/node.go
  393. type WebsocketManager struct {
  394. websocket.Upgrader
  395. funcMap map[string]*RPCFunc
  396. evsw *events.EventSwitch
  397. }
  398. func NewWebsocketManager(funcMap map[string]*RPCFunc, evsw *events.EventSwitch) *WebsocketManager {
  399. return &WebsocketManager{
  400. funcMap: funcMap,
  401. evsw: evsw,
  402. Upgrader: websocket.Upgrader{
  403. ReadBufferSize: 1024,
  404. WriteBufferSize: 1024,
  405. CheckOrigin: func(r *http.Request) bool {
  406. // TODO
  407. return true
  408. },
  409. },
  410. }
  411. }
  412. // Upgrade the request/response (via http.Hijack) and starts the WSConnection.
  413. func (wm *WebsocketManager) WebsocketHandler(w http.ResponseWriter, r *http.Request) {
  414. wsConn, err := wm.Upgrade(w, r, nil)
  415. if err != nil {
  416. // TODO - return http error
  417. log.Error("Failed to upgrade to websocket connection", "error", err)
  418. return
  419. }
  420. // register connection
  421. con := NewWSConnection(wsConn, wm.funcMap, wm.evsw)
  422. log.Notice("New websocket connection", "origin", con.id)
  423. con.Start() // Blocking
  424. }
  425. // rpc.websocket
  426. //-----------------------------------------------------------------------------
  427. // returns is result struct and error. If error is not nil, return it
  428. func unreflectResult(returns []reflect.Value) (interface{}, error) {
  429. errV := returns[1]
  430. if errV.Interface() != nil {
  431. return nil, fmt.Errorf("%v", errV.Interface())
  432. }
  433. return returns[0].Interface(), nil
  434. }
  435. // writes a list of available rpc endpoints as an html page
  436. func writeListOfEndpoints(w http.ResponseWriter, r *http.Request, funcMap map[string]*RPCFunc) {
  437. noArgNames := []string{}
  438. argNames := []string{}
  439. for name, funcData := range funcMap {
  440. if len(funcData.args) == 0 {
  441. noArgNames = append(noArgNames, name)
  442. } else {
  443. argNames = append(argNames, name)
  444. }
  445. }
  446. sort.Strings(noArgNames)
  447. sort.Strings(argNames)
  448. buf := new(bytes.Buffer)
  449. buf.WriteString("<html><body>")
  450. buf.WriteString("<br>Available endpoints:<br>")
  451. for _, name := range noArgNames {
  452. link := fmt.Sprintf("http://%s/%s", r.Host, name)
  453. buf.WriteString(fmt.Sprintf("<a href=\"%s\">%s</a></br>", link, link))
  454. }
  455. buf.WriteString("<br>Endpoints that require arguments:<br>")
  456. for _, name := range argNames {
  457. link := fmt.Sprintf("http://%s/%s?", r.Host, name)
  458. funcData := funcMap[name]
  459. for i, argName := range funcData.argNames {
  460. link += argName + "=_"
  461. if i < len(funcData.argNames)-1 {
  462. link += "&"
  463. }
  464. }
  465. buf.WriteString(fmt.Sprintf("<a href=\"%s\">%s</a></br>", link, link))
  466. }
  467. buf.WriteString("</body></html>")
  468. w.Header().Set("Content-Type", "text/html")
  469. w.WriteHeader(200)
  470. w.Write(buf.Bytes())
  471. }