Skip to content

Commit

Permalink
Add a websocket session RPC.
Browse files Browse the repository at this point in the history
  • Loading branch information
jrick committed Sep 17, 2015
1 parent 22b196b commit bb98bbb
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 4 deletions.
12 changes: 11 additions & 1 deletion btcjson/chainsvrwscmds.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2014 The btcsuite developers
// Copyright (c) 2014-2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -56,6 +56,15 @@ func NewNotifyNewTransactionsCmd(verbose *bool) *NotifyNewTransactionsCmd {
}
}

// SessionCmd defines the session JSON-RPC command.
type SessionCmd struct{}

// NewSessionCmd returns a new instance which can be used to issue a session
// JSON-RPC command.
func NewSessionCmd() *SessionCmd {
return &SessionCmd{}
}

// StopNotifyNewTransactionsCmd defines the stopnotifynewtransactions JSON-RPC command.
type StopNotifyNewTransactionsCmd struct{}

Expand Down Expand Up @@ -158,6 +167,7 @@ func init() {
MustRegisterCmd("notifynewtransactions", (*NotifyNewTransactionsCmd)(nil), flags)
MustRegisterCmd("notifyreceived", (*NotifyReceivedCmd)(nil), flags)
MustRegisterCmd("notifyspent", (*NotifySpentCmd)(nil), flags)
MustRegisterCmd("session", (*SessionCmd)(nil), flags)
MustRegisterCmd("stopnotifyblocks", (*StopNotifyBlocksCmd)(nil), flags)
MustRegisterCmd("stopnotifynewtransactions", (*StopNotifyNewTransactionsCmd)(nil), flags)
MustRegisterCmd("stopnotifyspent", (*StopNotifySpentCmd)(nil), flags)
Expand Down
10 changes: 10 additions & 0 deletions btcjson/chainsvrwsresults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcjson

// SessionResult models the data from the session command.
type SessionResult struct {
SessionID uint64 `json:sessionid`
}
15 changes: 15 additions & 0 deletions docs/json_rpc_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ user. Click the method name for further details such as parameter and return in
|8|[rescan](#rescan)|Rescan block chain for transactions to addresses and spent transaction outpoints.|[recvtx](#recvtx), [redeemingtx](#redeemingtx), [rescanprogress](#rescanprogress), and [rescanfinished](#rescanfinished) |
|9|[notifynewtransactions](#notifynewtransactions)|Send notifications for all new transactions as they are accepted into the mempool.|[txaccepted](#txaccepted) or [txacceptedverbose](#txacceptedverbose)|
|10|[stopnotifynewtransactions](#stopnotifynewtransactions)|Stop sending either a txaccepted or a txacceptedverbose notification when a new transaction is accepted into the mempool.|None|
|11|[session](#session)|Return details regarding a websocket client's current connection.|None|

<a name="WSExtMethodDetails" />
**7.2 Method Details**<br />
Expand Down Expand Up @@ -815,6 +816,20 @@ user. Click the method name for further details such as parameter and return in
|Returns|Nothing|
[Return to Overview](#WSExtMethodOverview)<br />

***

<a name="session"/>

| | |
|---|---|
|Method|session|
|Notifications|None|
|Parameters|None|
|Description|Return a JSON object with details regarding a websocket client's current connection to the RPC server. This currently only includes the session ID, a random unsigned 64-bit integer that is created for each newly connected client. Session IDs may be used to verify that the current connection was not lost and subsequently reestablished.|
|Returns|`{ (json object)`<br />&nbsp;&nbsp;`"sessionid": n (numeric) the session ID`<br />`}`|
|Example Return|`{`<br />&nbsp;&nbsp;`"sessionid": 67089679842`<br />`}`|
[Return to Overview](#WSExtMethodOverview)<br />


<a name="Notifications" />
### 8. Notifications (Websocket-specific)
Expand Down
5 changes: 5 additions & 0 deletions rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,10 @@ var helpDescsEnUS = map[string]string{

// -------- Websocket-specific help --------

// Session help.
"session--synopsis": "Return details regarding a websocket client's current connection session.",
"sessionresult-sessionid": "The unique session ID for a client's websocket connection.",

// NotifyBlocksCmd help.
"notifyblocks--synopsis": "Request notifications for whenever a block is connected or disconnected from the main (best) chain.",

Expand Down Expand Up @@ -616,6 +620,7 @@ var rpcResultTypes = map[string][]interface{}{
"verifymessage": []interface{}{(*bool)(nil)},

// Websocket commands.
"session": []interface{}{(*btcjson.SessionResult)(nil)},
"notifyblocks": nil,
"stopnotifyblocks": nil,
"notifynewtransactions": nil,
Expand Down
30 changes: 27 additions & 3 deletions rpcwebsocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ var wsHandlersBeforeInit = map[string]wsCommandHandler{
"notifynewtransactions": handleNotifyNewTransactions,
"notifyreceived": handleNotifyReceived,
"notifyspent": handleNotifySpent,
"session": handleSession,
"stopnotifyblocks": handleStopNotifyBlocks,
"stopnotifynewtransactions": handleStopNotifyNewTransactions,
"stopnotifyspent": handleStopNotifySpent,
Expand Down Expand Up @@ -94,7 +95,12 @@ func (s *rpcServer) WebsocketHandler(conn *websocket.Conn, remoteAddr string,
// Create a new websocket client to handle the new websocket connection
// and wait for it to shutdown. Once it has shutdown (and hence
// disconnected), remove it and any notifications it registered for.
client := newWebsocketClient(s, conn, remoteAddr, authenticated, isAdmin)
client, err := newWebsocketClient(s, conn, remoteAddr, authenticated, isAdmin)
if err != nil {
rpcsLog.Errorf("Failed to serve client %s: %v", remoteAddr, err)
conn.Close()
return
}
s.ntfnMgr.AddClient(client)
client.Start()
client.WaitForShutdown()
Expand Down Expand Up @@ -869,6 +875,11 @@ type wsClient struct {
// false means its access is only to the limited set of RPC calls.
isAdmin bool

// sessionID is a random ID generated for each client when connected.
// These IDs may be queried by a client using the session RPC. A change
// to the session ID indicates that the client reconnected.
sessionID uint64

// verboseTxUpdates specifies whether a client has requested verbose
// information about all new transactions.
verboseTxUpdates bool
Expand Down Expand Up @@ -1383,13 +1394,19 @@ func (c *wsClient) WaitForShutdown() {
// incoming and outgoing messages in separate goroutines complete with queueing
// and asynchrous handling for long-running operations.
func newWebsocketClient(server *rpcServer, conn *websocket.Conn,
remoteAddr string, authenticated bool, isAdmin bool) *wsClient {
remoteAddr string, authenticated bool, isAdmin bool) (*wsClient, error) {

sessionID, err := wire.RandomUint64()
if err != nil {
return nil, err
}

return &wsClient{
client := &wsClient{
conn: conn,
addr: remoteAddr,
authenticated: authenticated,
isAdmin: isAdmin,
sessionID: sessionID,
server: server,
addrRequests: make(map[string]struct{}),
spentRequests: make(map[wire.OutPoint]struct{}),
Expand All @@ -1398,6 +1415,7 @@ func newWebsocketClient(server *rpcServer, conn *websocket.Conn,
sendChan: make(chan wsResponse, websocketSendBufferSize),
quit: make(chan struct{}),
}
return client, nil
}

// handleWebsocketHelp implements the help command for websocket connections.
Expand Down Expand Up @@ -1454,6 +1472,12 @@ func handleNotifyBlocks(wsc *wsClient, icmd interface{}) (interface{}, error) {
return nil, nil
}

// handleSession implements the session command extension for websocket
// connections.
func handleSession(wsc *wsClient, icmd interface{}) (interface{}, error) {
return &btcjson.SessionResult{SessionID: wsc.sessionID}, nil
}

// handleStopNotifyBlocks implements the stopnotifyblocks command extension for
// websocket connections.
func handleStopNotifyBlocks(wsc *wsClient, icmd interface{}) (interface{}, error) {
Expand Down

0 comments on commit bb98bbb

Please sign in to comment.