Skip to content

Commit 883ae6d

Browse files
committed
refactor: update backend interface
The interface was a bit inconsistent and loose. These refactors just tighten things up a bit. Signed-off-by: Daniel Bluhm <dbluhm@pm.me>
1 parent 2c4cb4b commit 883ae6d

9 files changed

Lines changed: 86 additions & 50 deletions

File tree

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ version: '3'
22

33
services:
44
websocket-gateway:
5-
build: .
5+
build: ..
66
ports:
77
- "8765:8765"
88
volumes:
9-
- ./server:/code
109
- ./wait-for-tunnel.sh:/wait-for-tunnel.sh:ro,z
1110
entrypoint: /wait-for-tunnel.sh
1211
command: >
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ version: '3'
22

33
services:
44
websocket-gateway:
5-
build: .
5+
build: ..
66
ports:
77
- "8765:8765"
88
volumes:
9-
- ./socketdock:/usr/src/app/socketdock:z
9+
- ../socketdock:/usr/src/app/socketdock:z
1010
command: >
1111
--bindip 0.0.0.0
1212
--backend http
File renamed without changes.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ done
99
WS_ENDPOINT=$(curl --silent "${TUNNEL_ENDPOINT}/start" | python -c "import sys, json; print(json.load(sys.stdin)['url'])" | sed -rn 's#https?://([^/]+).*#\1#p')
1010
echo "fetched hostname and port [$WS_ENDPOINT]"
1111

12-
exec "$@" --externalhostandport ${WS_ENDPOINT}
12+
exec "$@" --externalhostandport ${WS_ENDPOINT}

socketdock/__main__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import argparse
55
from sanic import Sanic
66

7-
from .api import api, backend_var, endpoint_var
7+
from .api import api, backend_var
88

99

1010
def config() -> argparse.Namespace:
@@ -38,12 +38,13 @@ def main():
3838
elif args.backend == "http":
3939
from .httpbackend import HTTPBackend
4040

41-
backend = HTTPBackend(args.connect_uri, args.message_uri, args.disconnect_uri)
41+
backend = HTTPBackend(
42+
args.endpoint, args.connect_uri, args.message_uri, args.disconnect_uri
43+
)
4244
else:
4345
raise ValueError("Invalid backend type")
4446

4547
backend_var.set(backend)
46-
endpoint_var.set(args.endpoint)
4748

4849
logging.basicConfig(level=args.log_level)
4950

socketdock/api.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from .backend import Backend
1010

1111
backend_var: ContextVar[Backend] = ContextVar("backend")
12-
endpoint_var: ContextVar[str] = ContextVar("endpoint")
1312

1413
api = Blueprint("api", url_prefix="/")
1514

@@ -78,9 +77,6 @@ async def socket_handler(request: Request, websocket: Websocket):
7877
global lifetime_connections
7978
backend = backend_var.get()
8079
socket_id = None
81-
endpoint = endpoint_var.get()
82-
send = f"{endpoint}/socket/{socket_id}/send"
83-
disconnect = f"{endpoint_var.get()}/socket/{socket_id}/disconnect"
8480
try:
8581
# register user
8682
LOGGER.info("new client connected")
@@ -92,23 +88,15 @@ async def socket_handler(request: Request, websocket: Websocket):
9288
LOGGER.info("Request headers: %s", dict(request.headers.items()))
9389

9490
await backend.socket_connected(
95-
{
96-
"connection_id": socket_id,
97-
"headers": dict(request.headers.items()),
98-
"send": send,
99-
"disconnect": disconnect,
100-
},
91+
connection_id=socket_id,
92+
headers=dict(request.headers.items()),
10193
)
10294

10395
async for message in websocket:
10496
if message:
10597
await backend.inbound_socket_message(
106-
{
107-
"connection_id": socket_id,
108-
"send": send,
109-
"disconnect": disconnect,
110-
},
111-
message,
98+
connection_id=socket_id,
99+
message=message,
112100
)
113101
else:
114102
LOGGER.warning("empty message received")
@@ -118,4 +106,4 @@ async def socket_handler(request: Request, websocket: Websocket):
118106
if socket_id:
119107
del active_connections[socket_id]
120108
LOGGER.info("Removed connection: %s", socket_id)
121-
await backend.socket_disconnected({"connection_id": socket_id})
109+
await backend.socket_disconnected(socket_id)

socketdock/backend.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
"""Backend interface for SocketDock."""
22

33
from abc import ABC, abstractmethod
4-
from typing import Union
4+
from typing import Dict, Union
55

66

77
class Backend(ABC):
88
"""Backend interface for SocketDock."""
99

1010
@abstractmethod
11-
async def socket_connected(self, callback_uris: dict):
11+
async def socket_connected(
12+
self,
13+
connection_id: str,
14+
headers: Dict[str, str],
15+
):
1216
"""Handle new socket connections, with calback provided."""
13-
raise NotImplementedError()
1417

1518
@abstractmethod
1619
async def inbound_socket_message(
17-
self, callback_uris: dict, message: Union[str, bytes]
20+
self,
21+
connection_id: str,
22+
message: Union[str, bytes],
1823
):
1924
"""Handle inbound socket message, with calback provided."""
20-
raise NotImplementedError()
2125

2226
@abstractmethod
23-
async def socket_disconnected(self, bundle: dict):
27+
async def socket_disconnected(self, connection_id: str):
2428
"""Handle socket disconnected."""
25-
raise NotImplementedError()

socketdock/httpbackend.py

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""HTTP backend for SocketDock."""
22

33
import logging
4-
from typing import Union
4+
from typing import Dict, Union
55

66
import aiohttp
77

@@ -14,16 +14,46 @@
1414
class HTTPBackend(Backend):
1515
"""HTTP backend for SocketDock."""
1616

17-
def __init__(self, connect_uri: str, message_uri: str, disconnect_uri: str):
17+
def __init__(
18+
self,
19+
socket_base_uri: str,
20+
connect_uri: str,
21+
message_uri: str,
22+
disconnect_uri: str,
23+
):
1824
"""Initialize HTTP backend."""
1925
self._connect_uri = connect_uri
2026
self._message_uri = message_uri
2127
self._disconnect_uri = disconnect_uri
28+
self.socket_base_uri = socket_base_uri
29+
30+
def send_callback(self, connection_id: str) -> str:
31+
"""Return the callback URI for sending a message to a connected socket."""
32+
return f"{self.socket_base_uri}/{connection_id}/send"
33+
34+
def disconnect_callback(self, connection_id: str) -> str:
35+
"""Return the callback URI for disconnecting a connected socket."""
36+
return f"{self.socket_base_uri}/{connection_id}/disconnect"
2237

23-
async def socket_connected(self, callback_uris: dict):
38+
def callback_uris(self, connection_id: str) -> Dict[str, str]:
39+
"""Return labelled callback URIs."""
40+
return {
41+
"send": self.send_callback(connection_id),
42+
"disconnect": self.disconnect_callback(connection_id),
43+
}
44+
45+
async def socket_connected(
46+
self,
47+
connection_id: str,
48+
headers: Dict[str, str],
49+
):
2450
"""Handle inbound socket message, with calback provided."""
2551
http_body = {
26-
"meta": callback_uris,
52+
"meta": {
53+
**self.callback_uris(connection_id),
54+
"headers": headers,
55+
"connection_id": connection_id,
56+
},
2757
}
2858

2959
if self._connect_uri:
@@ -37,11 +67,16 @@ async def socket_connected(self, callback_uris: dict):
3767
LOGGER.debug("Response: %s", response)
3868

3969
async def inbound_socket_message(
40-
self, callback_uris: dict, message: Union[str, bytes]
70+
self,
71+
connection_id: str,
72+
message: Union[str, bytes],
4173
):
4274
"""Handle inbound socket message, with calback provided."""
4375
http_body = {
44-
"meta": callback_uris,
76+
"meta": {
77+
**self.callback_uris(connection_id),
78+
"connection_id": connection_id,
79+
},
4580
"message": message.decode("utf-8") if isinstance(message, bytes) else message,
4681
}
4782

@@ -54,11 +89,15 @@ async def inbound_socket_message(
5489
else:
5590
LOGGER.debug("Response: %s", response)
5691

57-
async def socket_disconnected(self, bundle: dict):
92+
async def socket_disconnected(self, connection_id: str):
5893
"""Handle socket disconnected."""
5994
async with aiohttp.ClientSession() as session:
60-
LOGGER.info("Notifying of disconnect: %s %s", self._disconnect_uri, bundle)
61-
async with session.post(self._disconnect_uri, json=bundle) as resp:
95+
LOGGER.info(
96+
"Notifying of disconnect: %s %s", self._disconnect_uri, connection_id
97+
)
98+
async with session.post(
99+
self._disconnect_uri, json={"connection_id": connection_id}
100+
) as resp:
62101
response = await resp.text()
63102
if resp.status != 200:
64103
LOGGER.error("Error posting to disconnect uri: %s", response)

socketdock/testbackend.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Test backend for SocketDock."""
22

3-
from typing import Union
3+
from typing import Dict, Union
44
import aiohttp
55

66
from .backend import Backend
@@ -9,27 +9,33 @@
99
class TestBackend(Backend):
1010
"""Test backend for SocketDock."""
1111

12-
async def socket_connected(self, callback_uris: dict):
12+
def __init__(self, base_uri: str):
13+
"""Initialize backend."""
14+
self.base_uri = base_uri
15+
16+
async def socket_connected(
17+
self,
18+
connection_id: str,
19+
headers: Dict[str, str],
20+
):
1321
"""Socket connected.
1422
1523
This test backend doesn't care, but can be useful to clean up state.
1624
"""
1725

1826
async def inbound_socket_message(
19-
self, callback_uris: dict, message: Union[str, bytes]
27+
self,
28+
connection_id: str,
29+
message: Union[str, bytes],
2030
):
2131
"""Receive socket message."""
22-
# send three backend messages in response
23-
# TODO: send response message via callback URI for sending a message
24-
send_uri = callback_uris["send"]
32+
send_uri = f"{self.base_uri}/{connection_id}/send"
2533
async with aiohttp.ClientSession() as session:
2634
async with session.post(send_uri, data="Hello yourself") as resp:
2735
response = await resp.text()
2836
print(response)
2937

30-
# response = requests.post(send_uri, data="Hello yourself!")
31-
32-
async def socket_disconnected(self, bundle: dict):
38+
async def socket_disconnected(self, connection_id: str):
3339
"""Socket disconnected.
3440
3541
This test backend doesn't care, but can be useful to clean up state.

0 commit comments

Comments
 (0)