Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rpc/subscription): implement state_unsubscribeStorage #1574

Merged
merged 13 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions dot/rpc/subscription/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,18 @@ func newSubscriptionResponseJSON(subID uint, reqID float64) ResponseJSON {
ID: reqID,
}
}

// BooleanResponseJSON for responses that return boolean values
type BooleanResponseJSON struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
type BooleanResponseJSON struct {
type BooleanResponse struct {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Jsonrpc string `json:"jsonrpc"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Jsonrpc string `json:"jsonrpc"`
JSONRPC string `json:"jsonrpc"`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated.

Result bool `json:"result"`
ID float64 `json:"id"`
}

func newBooleanResponseJSON(value bool, reqID float64) BooleanResponseJSON {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the type is public why not the constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason... I've updated this.

return BooleanResponseJSON{
Jsonrpc: "2.0",
Result: value,
ID: reqID,
}
}
31 changes: 27 additions & 4 deletions dot/rpc/subscription/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ func (c *WSConn) HandleComm() {
}
c.startListener(rvl)
case "state_unsubscribeStorage":
c.unsubscribeStorageListener(params)
c.unsubscribeStorageListener(reqid, params)

}
continue
}
Expand Down Expand Up @@ -212,10 +213,32 @@ func (c *WSConn) initStorageChangeListener(reqID float64, params interface{}) (u
return myObs.id, nil
}

func (c *WSConn) unsubscribeStorageListener(params interface{}) {
id := params.([]interface{})[0].(float64)
observer := c.Subscriptions[uint(id)].(state.Observer)
func (c *WSConn) unsubscribeStorageListener(reqID float64, params interface{}) {
switch v := params.(type) {
case []interface{}:
if l := len(v); l < 1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if l := len(v); l < 1 {
if len(v) == 0 {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated.

c.safeSendError(reqID, big.NewInt(-32600), "Invalid request")
return
}
default:
c.safeSendError(reqID, big.NewInt(-32600), "Invalid request")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declare this as constant

big.NewInt(-32600)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't make big.NewInt(-32600) a const, so I've made -32600 a const and I'm using that.

return
}

id, ok := params.([]interface{})[0].(float64)
if !ok {
c.safeSendError(reqID, big.NewInt(-32600), "Invalid request")
return
}
observer, ok := c.Subscriptions[uint(id)].(state.Observer)
if !ok {
initRes := newBooleanResponseJSON(false, reqID)
c.safeSend(initRes)
return
}

c.StorageAPI.UnregisterStorageObserver(observer)
c.safeSend(newBooleanResponseJSON(true, reqID))
}

func (c *WSConn) initBlockListener(reqID float64) (uint, error) {
Expand Down
46 changes: 46 additions & 0 deletions dot/rpc/subscription/websocket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,52 @@ func TestWSConn_HandleComm(t *testing.T) {
require.NoError(t, err)
require.Equal(t, []byte(`{"jsonrpc":"2.0","result":4,"id":7}`+"\n"), msg)

// test state_unsubscribeStorage
c.WriteMessage(websocket.TextMessage, []byte(`{
"jsonrpc": "2.0",
"method": "state_unsubscribeStorage",
"params": "foo",
"id": 7}`))
_, msg, err = c.ReadMessage()
require.NoError(t, err)
require.Equal(t, []byte(`{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":7}`+"\n"), msg)

c.WriteMessage(websocket.TextMessage, []byte(`{
"jsonrpc": "2.0",
"method": "state_unsubscribeStorage",
"params": [],
"id": 7}`))
_, msg, err = c.ReadMessage()
require.NoError(t, err)
require.Equal(t, []byte(`{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":7}`+"\n"), msg)

c.WriteMessage(websocket.TextMessage, []byte(`{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to spec, this shouldn't fail.
subscriber ID is either string or U32
https://github.com/w3f/PSPs/blob/psp-rpc-api/PSPs/drafts/psp-6.md#11116-state_unsubscribestorage-pubsub
Any reason we have subscriber ID as float?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I've updated so that it can handle strings as well. I've got params as a interface{}, so that it can accept any type, then when I parse the types it seems that all number are treated as float64 (I think this is happens when the json is unmashalled). I'm now taking the float64 or string and casting into uint. Let me know if there is a better approach to handling these.

"jsonrpc": "2.0",
"method": "state_unsubscribeStorage",
"params": ["4"],
"id": 7}`))
_, msg, err = c.ReadMessage()
require.NoError(t, err)
require.Equal(t, []byte(`{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":7}`+"\n"), msg)

c.WriteMessage(websocket.TextMessage, []byte(`{
"jsonrpc": "2.0",
"method": "state_unsubscribeStorage",
"params": [6],
"id": 7}`))
_, msg, err = c.ReadMessage()
require.NoError(t, err)
require.Equal(t, []byte(`{"jsonrpc":"2.0","result":false,"id":7}`+"\n"), msg)

c.WriteMessage(websocket.TextMessage, []byte(`{
"jsonrpc": "2.0",
"method": "state_unsubscribeStorage",
"params": [4],
"id": 7}`))
_, msg, err = c.ReadMessage()
require.NoError(t, err)
require.Equal(t, []byte(`{"jsonrpc":"2.0","result":true,"id":7}`+"\n"), msg)

// test initBlockListener
res, err = wsconn.initBlockListener(1)
require.EqualError(t, err, "error BlockAPI not set")
Expand Down