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

Add websockets support #144

Merged
merged 29 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c3a41d2
init websockets branch
kevinheavey Nov 20, 2021
cc7055f
init websockets
kevinheavey Nov 25, 2021
7c6648d
init websockets branch
kevinheavey Nov 20, 2021
9ce07d2
init websockets
kevinheavey Nov 25, 2021
8dedbfb
add asyncstdlib dep
kevinheavey Nov 25, 2021
ff72767
add request_builder file
kevinheavey Nov 25, 2021
0d59b4f
rough work
kevinheavey Nov 26, 2021
ba29727
Merge branch 'websockets' of https://github.com/michaelhly/solana-py …
kevinheavey Nov 26, 2021
568202a
tidy request builder
kevinheavey Nov 26, 2021
e6d132b
remove unnecessary annotation because of obscure apischema bug
kevinheavey Nov 26, 2021
2be312c
more websockets rough work
kevinheavey Nov 27, 2021
106025c
add ProgramNotification
kevinheavey Nov 27, 2021
5d28392
add more websocket responses
kevinheavey Nov 27, 2021
744bde5
more tests
kevinheavey Nov 29, 2021
b178442
more tests and methods
kevinheavey Nov 29, 2021
8dea57e
lint
kevinheavey Nov 29, 2021
264f2b3
more tests
kevinheavey Nov 29, 2021
c7c2210
more tests
kevinheavey Nov 29, 2021
75a33be
all tests passing
kevinheavey Nov 29, 2021
0cf88d8
set docstring extension formatin
kevinheavey Nov 29, 2021
c470ac7
fix extension setting
kevinheavey Nov 29, 2021
c667d04
more docstrings
kevinheavey Nov 29, 2021
96499e9
add vote_subscribe test
kevinheavey Nov 29, 2021
d3fec94
more lint
kevinheavey Nov 30, 2021
b6477d2
cleanup
kevinheavey Nov 30, 2021
aaba4c8
finish up docs
kevinheavey Nov 30, 2021
c48db7d
add websockets tests to ci
kevinheavey Nov 30, 2021
ee220f1
Merge branch 'master' into websockets
kevinheavey Nov 30, 2021
fe11284
lint
kevinheavey Nov 30, 2021
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
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ jobs:
'integration/test_async_token_client.py',
'integration/test_http_client.py',
'integration/test_token_client.py',
'integration/test_websockets.py',
'unit'
]

Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
"python.linting.pydocstyleEnabled": true,
"editor.formatOnSave": true,
"python.languageServer": "Jedi",
"autoDocstring.docstringFormat": "sphinx",
}
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,36 @@ async def main():
asyncio.run(main())
```

### Websockets Client

```py
import asyncio
from asyncstdlib import enumerate
from solana.rpc.websocket_api import connect

async def main():
async with connect("ws://api.devnet.solana.com") as websocket:
await websocket.logs_subscribe()
first_resp = await websocket.recv()
subscription_id = first_resp.result
next_resp = await websocket.recv()
print(next_resp)
await websocket.logs_unsubscribe(subscription_id)

# Alternatively, use the client as an infinite asynchronous iterator:
async with connect("ws://api.devnet.solana.com") as websocket:
await websocket.logs_subscribe()
first_resp = await websocket.recv()
subscription_id = first_resp.result
async for idx, msg in enumerate(websocket):
if idx == 3:
break
print(msg)
await websocket.logs_unsubscribe(subscription_id)

asyncio.run(main())
```

## Development

### Setup
Expand Down
6 changes: 6 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ Async API Client
.. autoclass:: solana.rpc.async_api.AsyncClient
:members:

Websockets Client
=================

.. automodule:: solana.rpc.websocket_api
:members:

Commitment
==========

Expand Down
231 changes: 191 additions & 40 deletions poetry.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ requests = "^2.24"
typing-extensions = "^3.10.0"
cachetools = "^4.2.2"
types-cachetools = "^4.2.4"
jsonrpcclient = "^4.0.1"
websockets = "^10.1"
jsonrpcserver = "^5.0.4"
apischema = "^0.16.1"

[tool.poetry.dev-dependencies]
black = "^21.9b0"
Expand All @@ -47,6 +51,7 @@ types-requests = "^2.25.11"
pytest-asyncio = "^0.16.0"
pytest-cov = "^3.0.0"
sphinx-rtd-theme = "^1.0.0"
asyncstdlib = "^3.10.2"


[build-system]
Expand Down
36 changes: 36 additions & 0 deletions src/solana/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,47 @@ async def main():

asyncio.run(main())


Websockets Client:

.. note::
The websockets code in solana-py is mostly just wrapping around the `websockets <https://websockets.readthedocs.io/en/stable/index.html>`_ library.

.. highlight:: py
.. code-block:: py

import asyncio
from asyncstdlib import enumerate
from solana.rpc.websocket_api import connect

async def main():
async with connect("ws://api.devnet.solana.com") as websocket:
await websocket.logs_subscribe()
first_resp = await websocket.recv()
subscription_id = first_resp.result
next_resp = await websocket.recv()
print(next_resp)
await websocket.logs_unsubscribe(subscription_id)

# Alternatively, use the client as an infinite asynchronous iterator:
async with connect("ws://api.devnet.solana.com") as websocket:
await websocket.logs_subscribe()
first_resp = await websocket.recv()
subscription_id = first_resp.result
async for idx, msg in enumerate(websocket):
if idx == 3:
break
print(msg)
await websocket.logs_unsubscribe(subscription_id)

asyncio.run(main())

Additional Resources:

Check out `anchorpy <https://kevinheavey.github.io/anchorpy/>`_, a Python client for `Anchor
<https://project-serum.github.io/anchor/getting-started/introduction.html>`_ based programs on Solana.


""" # pylint: disable=line-too-long # noqa: E501
import sys

Expand Down
2 changes: 1 addition & 1 deletion src/solana/publickey.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class PublicKey:
LENGTH = 32
"""Constant for standard length of a public key."""

def __init__(self, value: Union[bytearray, bytes, int, str, List[int]]) -> None:
def __init__(self, value: Union[bytearray, bytes, int, str, List[int]]):
"""Init PublicKey object."""
self._key: Optional[bytes] = None
if isinstance(value, str):
Expand Down
Loading