The SSH host key has changed on 8 April, 2022 to this one: SHA256:573uTBSeh74kvOo0HJXi5ijdzRm8me27suzNEDlGyrQ
Python implementation of [Earthstar](https://earthstar-project.org/)
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.
earthsnake/earthsnake/syncer/__init__.py

104 lines
2.9 KiB

"""Workspace syncing classes"""
from enum import Enum, auto
from typing import Any, Callable, Dict, Generic, Optional, TypeVar
from ..watchable import Watchable, WatchableSet
FnsBag = Dict[str, Callable[[Any], Any]]
Thunk = Callable[[], None]
T = TypeVar('T')
class TransportStatus(Enum):
OPEN = auto()
CLOSED = auto()
class ConnectionStatus(Enum):
CONNECTING = auto()
CLOSED = auto()
class TransportBase:
"""Base class for workspace syncers"""
status: Watchable[TransportStatus]
is_closed: bool
methods: FnsBag
device_id: str
connections: WatchableSet[Connection]
def __init__(self, device_id: str, methods: FnsBag):
raise NotImplementedError()
def on_close(self, cb: Thunk) -> Thunk:
"""Set a handler for when the connection closes"""
raise NotImplementedError()
def close(self) -> None:
"""Close the syncer’s connection"""
raise NotImplementedError()
class TransportLocal(TransportBase):
def __init__(self, device_id: str, methods: BagType, description: str) -> None:
self.device_id = device_id
self.methods = methods
self.description = description
@property
def is_closed(self) -> bool:
return self.status == TransportStatus.CLOSED
def on_close(self, func: Thunk) -> Thunk:
return self.status.on_change_to(TransportStatus.CLOSED)(func)
def close() -> None:
if self.is_closed:
return
self.status.set(TransportStatus.CLOSED)
for conn in self.connections:
conn.close()
self.connections.clear()
def add_connection(self, other_trans: TransportLocal[BagType]) -> Tuple[Connection, Connection]:
if self.is_closed:
raise Exception('Can’t use a transport after it’s closed')
this_conn: Connection[BagType]
other_conn: Connection[BagType]
this_conn = Connection(
description=f'conn {self.device_id} to {other_trans.device_id}',
transport=self,
device_id=self.device_id,
methods=self.methods,
send_envelope=lambda conn: ConnectionBase[BagType], env: Envelope[BagType]: other_conn.handle_incoming_envelope(env),
)
other_conn = Connection(
description=f'conn other_trans.device_id to {this.device_id}',
transport: other_trans,
device_id: other_trans.device_id,
methods: other_trans.methods,
send_envelope: lambda conn: ConnectionBase[BagType], env: Envelope[BagType]: this_conn.handle_incoming_envelope(env),
)
@this_conn.on_close
def close_other():
other_conn.close()
self.connections.delete(this_conn)
@other_conn.on_close
def close_this():
this_conn.close()
self.connections.add(this_conn)
other_trans.connections.add(other_conn)
return this_conn, other_conn