python work

This commit is contained in:
John Smith 2023-06-11 21:41:13 -04:00
parent b6c39ef042
commit cd04a8a74c
17 changed files with 7309 additions and 4 deletions

View file

@ -0,0 +1 @@
from .error import *

View file

@ -0,0 +1,11 @@
from abc import ABC, abstractmethod
from .state import VeilidState
class VeilidAPI(ABC):
@abstractmethod
def control(self, args: list[str]) -> str:
pass
@abstractmethod
def get_state(self) -> VeilidState:
pass

View file

@ -0,0 +1,254 @@
from typing import Self, Optional
from enum import StrEnum
class VeilidConfigLogLevel(StrEnum):
OFF = 'Off'
ERROR = 'Error'
WARN = 'Warn'
INFO = 'Info'
DEBUG = 'Debug'
TRACE = 'Trace'
class VeilidConfigCapabilities:
protocol_udp: bool
protocol_connect_tcp: bool
protocol_accept_tcp: bool
protocol_connect_ws: bool
protocol_accept_ws: bool
protocol_connect_wss: bool
protocol_accept_wss: bool
def __init__(self, protocol_udp: bool, protocol_connect_tcp: bool, protocol_accept_tcp: bool,
protocol_connect_ws: bool, protocol_accept_ws: bool, protocol_connect_wss: bool, protocol_accept_wss: bool):
self.protocol_udp = protocol_udp
self.protocol_connect_tcp = protocol_connect_tcp
self.protocol_accept_tcp = protocol_accept_tcp
self.protocol_connect_ws = protocol_connect_ws
self.protocol_accept_ws = protocol_accept_ws
self.protocol_connect_wss = protocol_connect_wss
self.protocol_accept_wss = protocol_accept_wss
@staticmethod
def from_json(j: dict) -> Self:
return VeilidConfigCapabilities(j['protocol_udp'],
j['protocol_connect_tcp'],
j['protocol_accept_tcp'],
j['protocol_connect_ws'],
j['protocol_accept_ws'],
j['protocol_connect_wss'],
j['protocol_accept_wss'])
class VeilidConfigProtectedStore:
allow_insecure_fallback: bool
always_use_insecure_storage: bool
directory: str
delete: bool
device_encryption_key_password: str
new_device_encryption_key_password: Optional[str]
def __init__(self, allow_insecure_fallback: bool, always_use_insecure_storage: bool,
directory: str, delete: bool, device_encryption_key_password: str, new_device_encryption_key_password: Optional[str]):
self.allow_insecure_fallback = allow_insecure_fallback
self.always_use_insecure_storage = always_use_insecure_storage
self.directory = directory
self.delete = delete
self.device_encryption_key_password = device_encryption_key_password
self.new_device_encryption_key_password = new_device_encryption_key_password
@staticmethod
def from_json(j: dict) -> Self:
return VeilidConfigProtectedStore(j['allow_insecure_fallback'], j['always_use_insecure_storage'],
j['directory'], j['delete'], j['device_encryption_key_password'], j['new_device_encryption_key_password'])
class VeilidConfigTableStore:
directory: str
delete: bool
def __init__(self, directory: str, delete: bool):
self.directory = directory
self.delete = delete
@staticmethod
def from_json(j: dict) -> Self:
return VeilidConfigTableStore(j['directory'], j['delete'])
class VeilidConfigBlockStore:
directory: str
delete: bool
def __init__(self, directory: str, delete: bool):
self.directory = directory
self.delete = delete
@staticmethod
def from_json(j: dict) -> Self:
return VeilidConfigBlockStore(j['directory'], j['delete'])
class VeilidConfigRoutingTable:
node_id: list[str]
node_id_secret: list[str]
bootstrap: list[str]
limit_over_attached: int
limit_fully_attached: int
limit_attached_strong: int
limit_attached_good: int
limit_attached_weak: int
def __init__(self, node_id: list[str], node_id_secret: list[str], bootstrap: list[str], limit_over_attached: int,
limit_fully_attached: int, limit_attached_strong: int, limit_attached_good: int, limit_attached_weak: int):
self.node_id = node_id
self.node_id_secret = node_id_secret
self.bootstrap = bootstrap
self.limit_over_attached = limit_over_attached
self.limit_fully_attached = limit_fully_attached
self.limit_attached_strong = limit_attached_strong
self.limit_attached_good = limit_attached_good
self.limit_attached_weak = limit_attached_weak
@staticmethod
def from_json(j: dict) -> Self:
return VeilidConfigRoutingTable(
j['node_id'],
j['node_id_secret'],
j['bootstrap'],
j['limit_over_attached'],
j['limit_fully_attached'],
j['limit_attached_strong'],
j['limit_attached_good'],
j['limit_attached_weak'])
class VeilidConfigRPC:
concurrency: int
queue_size: int
max_timestamp_behind_ms: Optional[int]
max_timestamp_ahead_ms: Optional[int]
timeout_ms: int
max_route_hop_count: int
default_route_hop_count: int
def __init__(self, concurrency: int, queue_size: int, max_timestamp_behind_ms: Optional[int], max_timestamp_ahead_ms: Optional[int],
timeout_ms: int, max_route_hop_count: int, default_route_hop_count: int):
self.concurrency = concurrency
self.queue_size = queue_size
self.max_timestamp_behind_ms = max_timestamp_behind_ms
self.max_timestamp_ahead_ms = max_timestamp_ahead_ms
self.timeout_ms = timeout_ms
self.max_route_hop_count = max_route_hop_count
self.default_route_hop_count = default_route_hop_count
@staticmethod
def from_json(j: dict) -> Self:
return VeilidConfigRPC(
j['concurrency'],
j['queue_size'],
j['max_timestamp_behind_ms'],
j['max_timestamp_ahead_ms'],
j['timeout_ms'],
j['max_route_hop_count'],
j['default_route_hop_count'])
class VeilidConfigNetwork:
connection_initial_timeout_ms: int
connection_inactivity_timeout_ms: int
max_connections_per_ip4: int
max_connections_per_ip6_prefix: int
max_connections_per_ip6_prefix_size: int
max_connection_frequency_per_min: int
client_whitelist_timeout_ms: int
reverse_connection_receipt_time_ms: int
hole_punch_receipt_time_ms: int
routing_table: VeilidConfigRoutingTable
rpc: VeilidConfigRPC
dht: VeilidConfigDHT
upnp: bool
detect_address_changes: bool
restricted_nat_retries: int
tls: VeilidConfigTLS
application: VeilidConfigApplication
protocol: VeilidConfigProtocol
def __init__(self, connection_initial_timeout_ms: int, connection_inactivity_timeout_ms: int,
max_connections_per_ip4: int, max_connections_per_ip6_prefix: int,
max_connections_per_ip6_prefix_size: int, max_connection_frequency_per_min: int,
client_whitelist_timeout_ms: int, reverse_connection_receipt_time_ms: int,
hole_punch_receipt_time_ms: int, routing_table: VeilidConfigRoutingTable,
rpc: VeilidConfigRPC, dht: VeilidConfigDHT, upnp: bool, detect_address_changes: bool,
restricted_nat_retries: int, tls: VeilidConfigTLS, application: VeilidConfigApplication, protocol: VeilidConfigProtocol):
self.connection_initial_timeout_ms = connection_initial_timeout_ms
self.connection_inactivity_timeout_ms = connection_inactivity_timeout_ms
self.max_connections_per_ip4 = max_connections_per_ip4
self.max_connections_per_ip6_prefix = max_connections_per_ip6_prefix
self.max_connections_per_ip6_prefix_size = max_connections_per_ip6_prefix_size
self.max_connection_frequency_per_min = max_connection_frequency_per_min
self.client_whitelist_timeout_ms = client_whitelist_timeout_ms
self.reverse_connection_receipt_time_ms = reverse_connection_receipt_time_ms
self.hole_punch_receipt_time_ms = hole_punch_receipt_time_ms
self.routing_table = routing_table
self.rpc = rpc
self.dht = dht
self.upnp = upnp
self.detect_address_changes = detect_address_changes
self.restricted_nat_retries = restricted_nat_retries
self.tls = tls
self.application = application
self.protocol = protocol
@staticmethod
def from_json(j: dict) -> Self:
return VeilidConfigNetwork(
j['connection_initial_timeout_ms'],
j['connection_inactivity_timeout_ms'],
j['max_connections_per_ip4'],
j['max_connections_per_ip6_prefix'],
j['max_connections_per_ip6_prefix_size'],
j['max_connection_frequency_per_min'],
j['client_whitelist_timeout_ms'],
j['reverse_connection_receipt_time_ms'],
j['hole_punch_receipt_time_ms'],
VeilidConfigRoutingTable.from_json(j['routing_table']),
VeilidConfigRPC.from_json(j['rpc']),
VeilidConfigDHT.from_json(j['dht']),
j['upnp'],
j['detect_address_changes'],
j['restricted_nat_retries'],
VeilidConfigTLS.from_json(j['tls']),
VeilidConfigApplication.from_json(j['application']),
VeilidConfigProtocol.from_json(j['protocol']))
class VeilidConfig:
program_name: str
namespace: str
capabilities: VeilidConfigCapabilities
protected_store: VeilidConfigProtectedStore
table_store: VeilidConfigTableStore
block_store: VeilidConfigBlockStore
network: VeilidConfigNetwork
def __init__(self, program_name: str, namespace: str, capabilities: VeilidConfigCapabilities,
protected_store: VeilidConfigProtectedStore, table_store: VeilidConfigTableStore,
block_store: VeilidConfigBlockStore, network: VeilidConfigNetwork):
self.program_name = program_name
self.namespace = namespace
self.capabilities = capabilities
self.protected_store = protected_store
self.table_store = table_store
self.block_store = block_store
self.network = network
@staticmethod
def from_json(j: dict) -> Self:
return VeilidConfig(j['program_name'], j['namespace'],
VeilidConfigCapabilities.from_json(j['capabilities']),
VeilidConfigProtectedStore.from_json(j['protected_store']),
VeilidConfigTableStore.from_json(j['table_store']),
VeilidConfigBlockStore.from_json(j['block_store']),
VeilidConfigNetwork.from_json(j['network']))

View file

@ -0,0 +1,133 @@
from typing import Self
class VeilidAPIError(Exception):
"""Veilid API error exception base class"""
pass
@staticmethod
def from_json(j: dict) -> Self:
match j['kind']:
case 'NotInitialized':
return VeilidAPIErrorNotInitialized()
case 'AlreadyInitialized':
return VeilidAPIErrorAlreadyInitialized()
case 'Timeout':
return VeilidAPIErrorTimeout()
case 'TryAgain':
return VeilidAPIErrorTryAgain()
case 'Shutdown':
return VeilidAPIErrorShutdown()
case 'InvalidTarget':
return VeilidAPIErrorInvalidTarget()
case 'NoConnection':
return VeilidAPIErrorNoConnection(j['message'])
case 'KeyNotFound':
return VeilidAPIErrorKeyNotFound(j['key'])
case 'Internal':
return VeilidAPIErrorInternal(j['message'])
case 'Unimplemented':
return VeilidAPIErrorUnimplemented(j['message'])
case 'ParseError':
return VeilidAPIErrorParseError(j['message'], j['value'])
case 'InvalidArgument':
return VeilidAPIErrorInvalidArgument(j['context'], j['argument'], j['value'])
case 'MissingArgument':
return VeilidAPIErrorMissingArgument(j['context'], j['argument'])
case 'Generic':
return VeilidAPIErrorGeneric(j['message'])
case _:
return VeilidAPIError("Unknown exception type: {}".format(j['kind']))
class VeilidAPIErrorNotInitialized(VeilidAPIError):
"""Veilid was not initialized"""
def __init__(self):
super().__init__("Not initialized")
class VeilidAPIErrorAlreadyInitialized(VeilidAPIError):
"""Veilid was already initialized"""
def __init__(self):
super().__init__("Already initialized")
class VeilidAPIErrorTimeout(VeilidAPIError):
"""Veilid operation timed out"""
def __init__(self):
super().__init__("Timeout")
class VeilidAPIErrorTryAgain(VeilidAPIError):
"""Operation could not be performed at this time, retry again later"""
def __init__(self):
super().__init__("Try again")
class VeilidAPIErrorShutdown(VeilidAPIError):
"""Veilid was already shut down"""
def __init__(self):
super().__init__("Shutdown")
class VeilidAPIErrorInvalidTarget(VeilidAPIError):
"""Target of operation is not valid"""
def __init__(self):
super().__init__("Invalid target")
class VeilidAPIErrorNoConnection(VeilidAPIError):
"""Connection could not be established"""
message: str
def __init__(self, message: str):
super().__init__("No connection")
self.message = message
class VeilidAPIErrorKeyNotFound(VeilidAPIError):
"""Key was not found"""
key: str
def __init__(self, key: str):
super().__init__("Key not found")
self.key = key
class VeilidAPIErrorInternal(VeilidAPIError):
"""Veilid experienced an internal failure"""
message: str
def __init__(self, message: str):
super().__init__("Internal")
self.message = message
class VeilidAPIErrorUnimplemented(VeilidAPIError):
"""Functionality is not yet implemented"""
message: str
def __init__(self, message: str):
super().__init__("Unimplemented")
self.message = message
class VeilidAPIErrorParseError(VeilidAPIError):
"""Value was not in a parseable format"""
message: str
value: str
def __init__(self, message: str, value: str):
super().__init__("Parse error")
self.message = message
self.value = value
class VeilidAPIErrorInvalidArgument(VeilidAPIError):
"""Argument is not valid in this context"""
context: str
argument: str
value: str
def __init__(self, context: str, argument: str, value: str):
super().__init__("Invalid argument")
self.context = context
self.argument = argument
self.value = value
class VeilidAPIErrorMissingArgument(VeilidAPIError):
"""Required argument was missing"""
context: str
argument: str
def __init__(self, context: str, argument: str):
super().__init__("Missing argument")
self.context = context
self.argument = argument
class VeilidAPIErrorGeneric(VeilidAPIError):
"""Generic error message"""
message: str
def __init__(self, message: str):
super().__init__("Generic")
self.message = message

View file

@ -0,0 +1,4 @@
class Request:
def __init__(self, id: int):
self.id = id

View file

@ -0,0 +1,205 @@
from typing import Self, Optional
from enum import StrEnum
from .types import Timestamp, TimestampDuration, ByteCount
from .config import VeilidConfig
class AttachmentState(StrEnum):
DETACHED = 'Detached'
ATTACHING = 'Attaching'
ATTACHED_WEAK = 'AttachedWeak'
ATTACHED_GOOD = 'AttachedGood'
ATTACHED_STRONG = 'AttachedStrong'
FULLY_ATTACHED = 'FullyAttached'
OVER_ATTACHED = 'OverAttached'
DETACHING = 'Detaching'
class VeilidStateAttachment:
state: AttachmentState
public_internet_ready: bool
local_network_ready: bool
def __init__(self, state: AttachmentState, public_internet_ready: bool, local_network_ready: bool):
self.state = state
self.public_internet_ready = public_internet_ready
self.local_network_ready = local_network_ready
@staticmethod
def from_json(j: dict) -> Self:
return VeilidStateAttachment(
AttachmentState(j['state']),
j['public_internet_ready'],
j['local_network_ready'])
class RPCStats:
messages_sent: int
messages_rcvd: int
questions_in_flight: int
last_question_ts: Optional[Timestamp]
last_seen_ts: Optional[Timestamp]
first_consecutive_seen_ts: Optional[Timestamp]
recent_lost_answers: int
failed_to_send: int
def __init__(self, messages_sent: int, messages_rcvd: int, questions_in_flight: int,
last_question_ts: Optional[Timestamp], last_seen_ts: Optional[Timestamp],
first_consecutive_seen_ts: Optional[Timestamp], recent_lost_answers: int, failed_to_send: int):
self.messages_sent = messages_sent
self.messages_rcvd = messages_rcvd
self.questions_in_flight = questions_in_flight
self.last_question_ts = last_question_ts
self.last_seen_ts = last_seen_ts
self.first_consecutive_seen_ts = first_consecutive_seen_ts
self.recent_lost_answers = recent_lost_answers
self.failed_to_send = failed_to_send
@staticmethod
def from_json(j: dict) -> Self:
return RPCStats(
j['messages_sent'],
j['messages_rcvd'],
j['questions_in_flight'],
None if j['last_question_ts'] is None else Timestamp(j['last_question_ts']),
None if j['last_seen_ts'] is None else Timestamp(j['last_seen_ts']),
None if j['first_consecutive_seen_ts'] is None else Timestamp(j['first_consecutive_seen_ts']),
j['recent_lost_answers'],
j['failed_to_send'])
class LatencyStats:
fastest: TimestampDuration
average: TimestampDuration
slowest: TimestampDuration
def __init__(self, fastest: TimestampDuration, average: TimestampDuration, slowest: TimestampDuration):
self.fastest = fastest
self.average = average
self.slowest = slowest
@staticmethod
def from_json(j: dict) -> Self:
return LatencyStats(
TimestampDuration(j['fastest']),
TimestampDuration(j['average']),
TimestampDuration(j['slowest']))
class TransferStats:
total: ByteCount
maximum: ByteCount
average: ByteCount
minimum: ByteCount
def __init__(self, total: ByteCount, maximum: ByteCount, average: ByteCount, minimum: ByteCount):
self.total = total
self.maximum = maximum
self.average = average
self.minimum = minimum
@staticmethod
def from_json(j: dict) -> Self:
return TransferStats(
ByteCount(j['total']),
ByteCount(j['maximum']),
ByteCount(j['average']),
ByteCount(j['minimum']))
class TransferStatsDownUp:
down: TransferStats
up: TransferStats
def __init__(self, down: TransferStats, up: TransferStats):
self.down = down
self.up = up
@staticmethod
def from_json(j: dict) -> Self:
return TransferStatsDownUp(
TransferStats.from_json(j['down']),
TransferStats.from_json(j['up']))
class PeerStats:
time_added: Timestamp
rpc_stats: RPCStats
latency: Optional[LatencyStats]
transfer: TransferStatsDownUp
def __init__(self, time_added: Timestamp, rpc_stats: RPCStats, latency: Optional[LatencyStats], transfer: TransferStatsDownUp):
self.time_added = time_added
self.rpc_stats = rpc_stats
self.latency = latency
self.transfer = transfer
@staticmethod
def from_json(j: dict) -> Self:
return PeerStats(
j['time_added'],
RPCStats.from_json(j['rpc_stats']),
None if j['latency'] is None else LatencyStats.from_json(j['latency']),
TransferStatsDownUp.from_json(j['transfer']))
class PeerTableData:
node_ids: list[str]
peer_address: str
peer_stats: PeerStats
def __init__(self, node_ids: list[str], peer_address: str, peer_stats: PeerStats):
self.node_ids = node_ids
self.peer_address = peer_address
self.peer_stats = peer_stats
@staticmethod
def from_json(j: dict) -> Self:
return PeerTableData(
j['node_ids'],
j['peer_address'],
PeerStats.from_json(j['peer_stats']))
class VeilidStateNetwork:
started: bool
bps_down: ByteCount
bps_up: ByteCount
peers: list[PeerTableData]
def __init__(self, started: bool, bps_down: ByteCount, bps_up: ByteCount, peers: list[PeerTableData]):
self.started = started
self.bps_down = bps_down
self.bps_up = bps_up
self.peers = peers
@staticmethod
def from_json(j: dict) -> Self:
return VeilidStateNetwork(
j['started'],
ByteCount(j['bps_down']),
ByteCount(j['bps_up']),
map(lambda x: PeerTableData.from_json(x), j['peers']))
class VeilidStateConfig:
config: VeilidConfig
def __init__(self, config: VeilidConfig):
self.config = config
@staticmethod
def from_json(j: dict) -> Self:
return VeilidStateConfig(
j['config'])
class VeilidState:
attachment: VeilidStateAttachment
network: VeilidStateNetwork
config: VeilidStateConfig
def __init__(self, attachment: VeilidStateAttachment, network: VeilidStateNetwork, config: VeilidStateConfig):
self.attachment = attachment
self.network = network
self.config = config
@staticmethod
def from_json(j: dict) -> Self:
return VeilidState(
VeilidStateAttachment.from_json(j['attachment']),
VeilidStateNetwork.from_json(j['network']),
VeilidStateConfig.from_json(j['config']))

View file

@ -0,0 +1,10 @@
import time
class Timestamp(int):
pass
class TimestampDuration(int):
pass
class ByteCount(int):
pass