ouisync.session
Session API: connects to a running Ouisync service's local control socket.
Includes the bindgen-generated data types, Request/Response tagged unions
and Session/Repository/File API classes, plus the parts bindgen doesn't
generate: connect/close, and the streaming endpoints (handled by hand in
every other binding too).
1"""Session API: connects to a running Ouisync service's local control socket. 2 3Includes the bindgen-generated data types, `Request`/`Response` tagged unions 4and `Session`/`Repository`/`File` API classes, plus the parts bindgen doesn't 5generate: connect/close, and the streaming endpoints (handled by hand in 6every other binding too).""" 7 8import inspect 9import typing 10 11from ._generated import api as _api 12from ._generated.api import * 13from .client import Client as _Client 14from .state_monitor import MonitorId 15 16 17async def connect(config_dir, host: str = "127.0.0.1") -> Session: 18 client = await _Client.connect(config_dir, host) 19 return Session(client) 20 21 22async def close(session: Session): 23 await session._client.close() 24 25 26async def subscribe_to_network_events(session: Session) -> typing.AsyncIterator[NetworkEvent]: 27 async for response in session._client.subscribe(Request_SessionSubscribeToNetwork()): 28 if isinstance(response, Response_NetworkEvent): 29 yield response.value 30 elif isinstance(response, Response_Unit): 31 yield NetworkEvent.PEER_SET_CHANGE 32 33# Re-export everything from the generated api module. 34_all = [] 35 36for name, member in inspect.getmembers(_api): 37 if not inspect.isclass(member): 38 continue 39 40 # Don't re-export private clases 41 if name.startswith('_'): 42 continue 43 44 # Don't re-export "handle" classes as they are used only internally by the API classes (which 45 # are re-exported). 46 if name.endswith('Handle'): 47 continue 48 49 _all.append(name) 50 51# Re-export handwritten classes 52_all.append('MonitorId') 53 54__all__ = _all
122class AccessChange: 123 """How to change access to a repository.""" 124 _variants: ClassVar[dict[str, type]] = {}
How to change access to a repository.
133@dataclass 134class AccessChange_Disable(AccessChange): 135 """Disable access""" 136 _tag: ClassVar[str] = "Disable" 137 _shape: ClassVar[str] = "unit"
Disable access
126@dataclass 127class AccessChange_Enable(AccessChange): 128 """Enable read or write access, optionally with local secret""" 129 _tag: ClassVar[str] = "Enable" 130 _shape: ClassVar[str] = "unnamed" 131 value: SetLocalSecret | None
Enable read or write access, optionally with local secret
54class AccessMode(IntEnum): 55 """Access mode of a repository.""" 56 BLIND = 0 57 """Repository is neither readable not writtable (but can still be synced).""" 58 READ = 1 59 """Repository is readable but not writtable.""" 60 WRITE = 2 61 """Repository is both readable and writable."""
Access mode of a repository.
Repository is neither readable not writtable (but can still be synced).
532@dataclass 533class DirectoryEntry: 534 _shape: ClassVar[str] = "named" 535 name: str 536 entry_type: EntryType
Type of filesystem entry.
250class ErrorCode(IntEnum): 251 OK = 0 252 """No error""" 253 PERMISSION_DENIED = 1 254 """Insuficient permission to perform the intended operation""" 255 INVALID_INPUT = 2 256 """Invalid input parameter""" 257 INVALID_DATA = 3 258 """Invalid data (e.g., malformed incoming message, config file, etc...)""" 259 ALREADY_EXISTS = 4 260 """Entry already exists""" 261 NOT_FOUND = 5 262 """Entry not found""" 263 AMBIGUOUS = 6 264 """Multiple matching entries found""" 265 UNSUPPORTED = 8 266 """The indended operation is not supported""" 267 INTERRUPTED = 9 268 """The operation was interrupted""" 269 CONNECTION_REFUSED = 1025 270 """Failed to establish connection to the server""" 271 CONNECTION_ABORTED = 1026 272 """Connection aborted by the server""" 273 TRANSPORT_ERROR = 1027 274 """Failed to send or receive message""" 275 LISTENER_BIND_ERROR = 1028 276 """Listener failed to bind to the specified address""" 277 LISTENER_ACCEPT_ERROR = 1029 278 """Listener failed to accept client connection""" 279 STORE_ERROR = 2049 280 """Operation on the internal repository store failed""" 281 IS_DIRECTORY = 2050 282 """Entry was expected to not be a directory but it is""" 283 NOT_DIRECTORY = 2051 284 """Entry was expected to be a directory but it isn't""" 285 DIRECTORY_NOT_EMPTY = 2052 286 """Directory was expected to be empty but it isn't""" 287 RESOURCE_BUSY = 2053 288 """File or directory is busy""" 289 RUNTIME_INITIALIZE_ERROR = 4097 290 """Failed to initialize runtime""" 291 CONFIG_ERROR = 4099 292 """Failed to read from or write into the config file""" 293 TLS_CERTIFICATES_NOT_FOUND = 4100 294 """TLS certificated not found""" 295 TLS_CERTIFICATES_INVALID = 4101 296 """TLS certificates failed to load""" 297 TLS_KEYS_NOT_FOUND = 4102 298 """TLS keys not found""" 299 TLS_CONFIG_ERROR = 4103 300 """Failed to create TLS config""" 301 VFS_DRIVER_INSTALL_ERROR = 4104 302 """Failed to install virtual filesystem driver""" 303 VFS_OTHER_ERROR = 4105 304 """Unspecified virtual filesystem error""" 305 SERVICE_ALREADY_RUNNING = 4106 306 """Another instance of the service is already running""" 307 STORE_DIR_UNSPECIFIED = 4107 308 """Store directory is not specified""" 309 MOUNT_DIR_UNSPECIFIED = 4108 310 """Mount directory is not specified""" 311 OTHER = 65535 312 """Unspecified error"""
Insuficient permission to perform the intended operation
Invalid data (e.g., malformed incoming message, config file, etc...)
Failed to establish connection to the server
Listener failed to bind to the specified address
Listener failed to accept client connection
Directory was expected to be empty but it isn't
TLS certificated not found
TLS certificates failed to load
Failed to install virtual filesystem driver
Another instance of the service is already running
3347class File: 3348 def __init__(self, client: Client, handle: FileHandle): 3349 """@private""" 3350 self._client = client 3351 self._handle = handle 3352 3353 async def close( 3354 self, 3355 ): 3356 """Closes the file.""" 3357 request = Request_FileClose( 3358 self._handle, 3359 ) 3360 response = await self._client.invoke(request) 3361 if isinstance(response, Response_Unit): 3362 return 3363 raise UnexpectedResponse() 3364 3365 async def flush( 3366 self, 3367 ): 3368 """Flushes any pending writes to the file.""" 3369 request = Request_FileFlush( 3370 self._handle, 3371 ) 3372 response = await self._client.invoke(request) 3373 if isinstance(response, Response_Unit): 3374 return 3375 raise UnexpectedResponse() 3376 3377 async def get_length( 3378 self, 3379 ) -> int: 3380 """Returns the length of the file in bytes""" 3381 request = Request_FileGetLength( 3382 self._handle, 3383 ) 3384 response = await self._client.invoke(request) 3385 if isinstance(response, Response_U64): 3386 return response.value 3387 raise UnexpectedResponse() 3388 3389 async def get_progress( 3390 self, 3391 ) -> int: 3392 """ 3393 Returns the sync progress of this file, that is, the total byte size of all the blocks of 3394 this file that's already been downloaded. 3395 3396 Note that Ouisync downloads the blocks in random order, so until the file's been completely 3397 downloaded, the already downloaded blocks are not guaranteed to continuous (there might be 3398 gaps). 3399 """ 3400 request = Request_FileGetProgress( 3401 self._handle, 3402 ) 3403 response = await self._client.invoke(request) 3404 if isinstance(response, Response_U64): 3405 return response.value 3406 raise UnexpectedResponse() 3407 3408 async def read( 3409 self, 3410 *, 3411 offset: int, 3412 size: int, 3413 ) -> bytes: 3414 """Reads `size` bytes from the file starting at `offset` bytes from the beginning of the file.""" 3415 request = Request_FileRead( 3416 self._handle, 3417 offset, 3418 size, 3419 ) 3420 response = await self._client.invoke(request) 3421 if isinstance(response, Response_Bytes): 3422 return response.value 3423 raise UnexpectedResponse() 3424 3425 async def truncate( 3426 self, 3427 *, 3428 len: int, 3429 ): 3430 """Truncates the file to the given length.""" 3431 request = Request_FileTruncate( 3432 self._handle, 3433 len, 3434 ) 3435 response = await self._client.invoke(request) 3436 if isinstance(response, Response_Unit): 3437 return 3438 raise UnexpectedResponse() 3439 3440 async def write( 3441 self, 3442 *, 3443 offset: int, 3444 data: bytes, 3445 ): 3446 """Writes the data to the file at the given offset.""" 3447 request = Request_FileWrite( 3448 self._handle, 3449 offset, 3450 data, 3451 ) 3452 response = await self._client.invoke(request) 3453 if isinstance(response, Response_Unit): 3454 return 3455 raise UnexpectedResponse()
3353 async def close( 3354 self, 3355 ): 3356 """Closes the file.""" 3357 request = Request_FileClose( 3358 self._handle, 3359 ) 3360 response = await self._client.invoke(request) 3361 if isinstance(response, Response_Unit): 3362 return 3363 raise UnexpectedResponse()
Closes the file.
3365 async def flush( 3366 self, 3367 ): 3368 """Flushes any pending writes to the file.""" 3369 request = Request_FileFlush( 3370 self._handle, 3371 ) 3372 response = await self._client.invoke(request) 3373 if isinstance(response, Response_Unit): 3374 return 3375 raise UnexpectedResponse()
Flushes any pending writes to the file.
3377 async def get_length( 3378 self, 3379 ) -> int: 3380 """Returns the length of the file in bytes""" 3381 request = Request_FileGetLength( 3382 self._handle, 3383 ) 3384 response = await self._client.invoke(request) 3385 if isinstance(response, Response_U64): 3386 return response.value 3387 raise UnexpectedResponse()
Returns the length of the file in bytes
3389 async def get_progress( 3390 self, 3391 ) -> int: 3392 """ 3393 Returns the sync progress of this file, that is, the total byte size of all the blocks of 3394 this file that's already been downloaded. 3395 3396 Note that Ouisync downloads the blocks in random order, so until the file's been completely 3397 downloaded, the already downloaded blocks are not guaranteed to continuous (there might be 3398 gaps). 3399 """ 3400 request = Request_FileGetProgress( 3401 self._handle, 3402 ) 3403 response = await self._client.invoke(request) 3404 if isinstance(response, Response_U64): 3405 return response.value 3406 raise UnexpectedResponse()
Returns the sync progress of this file, that is, the total byte size of all the blocks of this file that's already been downloaded.
Note that Ouisync downloads the blocks in random order, so until the file's been completely downloaded, the already downloaded blocks are not guaranteed to continuous (there might be gaps).
3408 async def read( 3409 self, 3410 *, 3411 offset: int, 3412 size: int, 3413 ) -> bytes: 3414 """Reads `size` bytes from the file starting at `offset` bytes from the beginning of the file.""" 3415 request = Request_FileRead( 3416 self._handle, 3417 offset, 3418 size, 3419 ) 3420 response = await self._client.invoke(request) 3421 if isinstance(response, Response_Bytes): 3422 return response.value 3423 raise UnexpectedResponse()
Reads size bytes from the file starting at offset bytes from the beginning of the file.
3425 async def truncate( 3426 self, 3427 *, 3428 len: int, 3429 ): 3430 """Truncates the file to the given length.""" 3431 request = Request_FileTruncate( 3432 self._handle, 3433 len, 3434 ) 3435 response = await self._client.invoke(request) 3436 if isinstance(response, Response_Unit): 3437 return 3438 raise UnexpectedResponse()
Truncates the file to the given length.
3440 async def write( 3441 self, 3442 *, 3443 offset: int, 3444 data: bytes, 3445 ): 3446 """Writes the data to the file at the given offset.""" 3447 request = Request_FileWrite( 3448 self._handle, 3449 offset, 3450 data, 3451 ) 3452 response = await self._client.invoke(request) 3453 if isinstance(response, Response_Unit): 3454 return 3455 raise UnexpectedResponse()
Writes the data to the file at the given offset.
63class LocalSecret: 64 """Type of secret to unlock a repository.""" 65 _variants: ClassVar[dict[str, type]] = {}
Type of secret to unlock a repository.
67@dataclass 68class LocalSecret_Password(LocalSecret): 69 """Password provided by the user""" 70 _tag: ClassVar[str] = "Password" 71 _shape: ClassVar[str] = "unnamed" 72 value: Password
Password provided by the user
74@dataclass 75class LocalSecret_SecretKey(LocalSecret): 76 """Secret key generated by secure means (e.g., crypto-secure RNG, KDF, ...)""" 77 _tag: ClassVar[str] = "SecretKey" 78 _shape: ClassVar[str] = "unnamed" 79 value: SecretKey
Secret key generated by secure means (e.g., crypto-secure RNG, KDF, ...)
516@dataclass 517class MetadataEdit: 518 """Edit of a single metadata entry.""" 519 _shape: ClassVar[str] = "named" 520 key: str 521 old_value: str | None 522 new_value: str | None
Edit of a single metadata entry.
245class NatBehavior(IntEnum): 246 ENDPOINT_INDEPENDENT = 0 247 ADDRESS_DEPENDENT = 1 248 ADDRESS_AND_PORT_DEPENDENT = 2
524@dataclass 525class NetworkDefaults: 526 """Default network parameters""" 527 _shape: ClassVar[str] = "named" 528 bind: list[str] 529 port_forwarding_enabled: bool 530 local_discovery_enabled: bool
Default network parameters
149class NetworkEvent(IntEnum): 150 """Network notification event.""" 151 PROTOCOL_VERSION_MISMATCH = 0 152 """ 153 A peer has appeared with higher protocol version than us. Probably means we are using 154 outdated library. This event can be used to notify the user that they should update the app. 155 """ 156 PEER_SET_CHANGE = 1 157 """The set of known peers has changed (e.g., a new peer has been discovered)"""
Network notification event.
A peer has appeared with higher protocol version than us. Probably means we are using outdated library. This event can be used to notify the user that they should update the app.
The set of known peers has changed (e.g., a new peer has been discovered)
3458class NetworkSocket: 3459 def __init__(self, client: Client, handle: NetworkSocketHandle): 3460 """@private""" 3461 self._client = client 3462 self._handle = handle 3463 3464 async def close( 3465 self, 3466 ): 3467 request = Request_NetworkSocketClose( 3468 self._handle, 3469 ) 3470 response = await self._client.invoke(request) 3471 if isinstance(response, Response_Unit): 3472 return 3473 raise UnexpectedResponse() 3474 3475 async def recv_from( 3476 self, 3477 *, 3478 len: int, 3479 ) -> Datagram: 3480 request = Request_NetworkSocketRecvFrom( 3481 self._handle, 3482 len, 3483 ) 3484 response = await self._client.invoke(request) 3485 if isinstance(response, Response_Datagram): 3486 return response.value 3487 raise UnexpectedResponse() 3488 3489 async def send_to( 3490 self, 3491 *, 3492 data: bytes, 3493 addr: str, 3494 ) -> int: 3495 request = Request_NetworkSocketSendTo( 3496 self._handle, 3497 data, 3498 addr, 3499 ) 3500 response = await self._client.invoke(request) 3501 if isinstance(response, Response_U64): 3502 return response.value 3503 raise UnexpectedResponse()
3475 async def recv_from( 3476 self, 3477 *, 3478 len: int, 3479 ) -> Datagram: 3480 request = Request_NetworkSocketRecvFrom( 3481 self._handle, 3482 len, 3483 ) 3484 response = await self._client.invoke(request) 3485 if isinstance(response, Response_Datagram): 3486 return response.value 3487 raise UnexpectedResponse()
3489 async def send_to( 3490 self, 3491 *, 3492 data: bytes, 3493 addr: str, 3494 ) -> int: 3495 request = Request_NetworkSocketSendTo( 3496 self._handle, 3497 data, 3498 addr, 3499 ) 3500 response = await self._client.invoke(request) 3501 if isinstance(response, Response_U64): 3502 return response.value 3503 raise UnexpectedResponse()
3506class NetworkStream: 3507 def __init__(self, client: Client, handle: NetworkStreamHandle): 3508 """@private""" 3509 self._client = client 3510 self._handle = handle 3511 3512 async def close( 3513 self, 3514 ): 3515 """Gracefully closes the given raw byte stream.""" 3516 request = Request_NetworkStreamClose( 3517 self._handle, 3518 ) 3519 response = await self._client.invoke(request) 3520 if isinstance(response, Response_Unit): 3521 return 3522 raise UnexpectedResponse() 3523 3524 async def read_exact( 3525 self, 3526 *, 3527 len: int, 3528 ) -> bytes: 3529 """Reads exactly the given number of bytes from the given raw byte stream.""" 3530 request = Request_NetworkStreamReadExact( 3531 self._handle, 3532 len, 3533 ) 3534 response = await self._client.invoke(request) 3535 if isinstance(response, Response_Bytes): 3536 return response.value 3537 raise UnexpectedResponse() 3538 3539 async def write_all( 3540 self, 3541 *, 3542 buf: bytes, 3543 ): 3544 """Writes the whole buffer to the given raw byte stream.""" 3545 request = Request_NetworkStreamWriteAll( 3546 self._handle, 3547 buf, 3548 ) 3549 response = await self._client.invoke(request) 3550 if isinstance(response, Response_Unit): 3551 return 3552 raise UnexpectedResponse()
3512 async def close( 3513 self, 3514 ): 3515 """Gracefully closes the given raw byte stream.""" 3516 request = Request_NetworkStreamClose( 3517 self._handle, 3518 ) 3519 response = await self._client.invoke(request) 3520 if isinstance(response, Response_Unit): 3521 return 3522 raise UnexpectedResponse()
Gracefully closes the given raw byte stream.
3524 async def read_exact( 3525 self, 3526 *, 3527 len: int, 3528 ) -> bytes: 3529 """Reads exactly the given number of bytes from the given raw byte stream.""" 3530 request = Request_NetworkStreamReadExact( 3531 self._handle, 3532 len, 3533 ) 3534 response = await self._client.invoke(request) 3535 if isinstance(response, Response_Bytes): 3536 return response.value 3537 raise UnexpectedResponse()
Reads exactly the given number of bytes from the given raw byte stream.
3539 async def write_all( 3540 self, 3541 *, 3542 buf: bytes, 3543 ): 3544 """Writes the whole buffer to the given raw byte stream.""" 3545 request = Request_NetworkStreamWriteAll( 3546 self._handle, 3547 buf, 3548 ) 3549 response = await self._client.invoke(request) 3550 if isinstance(response, Response_Unit): 3551 return 3552 raise UnexpectedResponse()
Writes the whole buffer to the given raw byte stream.
314class OuisyncError(Exception): 315 def __init__(self, code: ErrorCode, message: str | None = None, sources: list[str] | None = None): 316 self.code = code 317 self.message = message 318 self.sources = sources or [] 319 super().__init__(message or str(code))
Common base class for all non-exit exceptions.
336class OuisyncError_AlreadyExists(OuisyncError): 337 """Entry already exists""" 338 def __init__(self, message: str | None = None, sources: list[str] | None = None): 339 super().__init__(ErrorCode.ALREADY_EXISTS, message, sources)
Entry already exists
346class OuisyncError_Ambiguous(OuisyncError): 347 """Multiple matching entries found""" 348 def __init__(self, message: str | None = None, sources: list[str] | None = None): 349 super().__init__(ErrorCode.AMBIGUOUS, message, sources)
Multiple matching entries found
416class OuisyncError_ConfigError(OuisyncError): 417 """Failed to read from or write into the config file""" 418 def __init__(self, message: str | None = None, sources: list[str] | None = None): 419 super().__init__(ErrorCode.CONFIG_ERROR, message, sources)
Failed to read from or write into the config file
366class OuisyncError_ConnectionAborted(OuisyncError): 367 """Connection aborted by the server""" 368 def __init__(self, message: str | None = None, sources: list[str] | None = None): 369 super().__init__(ErrorCode.CONNECTION_ABORTED, message, sources)
Connection aborted by the server
361class OuisyncError_ConnectionRefused(OuisyncError): 362 """Failed to establish connection to the server""" 363 def __init__(self, message: str | None = None, sources: list[str] | None = None): 364 super().__init__(ErrorCode.CONNECTION_REFUSED, message, sources)
Failed to establish connection to the server
401class OuisyncError_DirectoryNotEmpty(OuisyncError): 402 """Directory was expected to be empty but it isn't""" 403 def __init__(self, message: str | None = None, sources: list[str] | None = None): 404 super().__init__(ErrorCode.DIRECTORY_NOT_EMPTY, message, sources)
Directory was expected to be empty but it isn't
356class OuisyncError_Interrupted(OuisyncError): 357 """The operation was interrupted""" 358 def __init__(self, message: str | None = None, sources: list[str] | None = None): 359 super().__init__(ErrorCode.INTERRUPTED, message, sources)
The operation was interrupted
331class OuisyncError_InvalidData(OuisyncError): 332 """Invalid data (e.g., malformed incoming message, config file, etc...)""" 333 def __init__(self, message: str | None = None, sources: list[str] | None = None): 334 super().__init__(ErrorCode.INVALID_DATA, message, sources)
Invalid data (e.g., malformed incoming message, config file, etc...)
326class OuisyncError_InvalidInput(OuisyncError): 327 """Invalid input parameter""" 328 def __init__(self, message: str | None = None, sources: list[str] | None = None): 329 super().__init__(ErrorCode.INVALID_INPUT, message, sources)
Invalid input parameter
391class OuisyncError_IsDirectory(OuisyncError): 392 """Entry was expected to not be a directory but it is""" 393 def __init__(self, message: str | None = None, sources: list[str] | None = None): 394 super().__init__(ErrorCode.IS_DIRECTORY, message, sources)
Entry was expected to not be a directory but it is
381class OuisyncError_ListenerAcceptError(OuisyncError): 382 """Listener failed to accept client connection""" 383 def __init__(self, message: str | None = None, sources: list[str] | None = None): 384 super().__init__(ErrorCode.LISTENER_ACCEPT_ERROR, message, sources)
Listener failed to accept client connection
376class OuisyncError_ListenerBindError(OuisyncError): 377 """Listener failed to bind to the specified address""" 378 def __init__(self, message: str | None = None, sources: list[str] | None = None): 379 super().__init__(ErrorCode.LISTENER_BIND_ERROR, message, sources)
Listener failed to bind to the specified address
461class OuisyncError_MountDirUnspecified(OuisyncError): 462 """Mount directory is not specified""" 463 def __init__(self, message: str | None = None, sources: list[str] | None = None): 464 super().__init__(ErrorCode.MOUNT_DIR_UNSPECIFIED, message, sources)
Mount directory is not specified
396class OuisyncError_NotDirectory(OuisyncError): 397 """Entry was expected to be a directory but it isn't""" 398 def __init__(self, message: str | None = None, sources: list[str] | None = None): 399 super().__init__(ErrorCode.NOT_DIRECTORY, message, sources)
Entry was expected to be a directory but it isn't
341class OuisyncError_NotFound(OuisyncError): 342 """Entry not found""" 343 def __init__(self, message: str | None = None, sources: list[str] | None = None): 344 super().__init__(ErrorCode.NOT_FOUND, message, sources)
Entry not found
321class OuisyncError_PermissionDenied(OuisyncError): 322 """Insuficient permission to perform the intended operation""" 323 def __init__(self, message: str | None = None, sources: list[str] | None = None): 324 super().__init__(ErrorCode.PERMISSION_DENIED, message, sources)
Insuficient permission to perform the intended operation
406class OuisyncError_ResourceBusy(OuisyncError): 407 """File or directory is busy""" 408 def __init__(self, message: str | None = None, sources: list[str] | None = None): 409 super().__init__(ErrorCode.RESOURCE_BUSY, message, sources)
File or directory is busy
411class OuisyncError_RuntimeInitializeError(OuisyncError): 412 """Failed to initialize runtime""" 413 def __init__(self, message: str | None = None, sources: list[str] | None = None): 414 super().__init__(ErrorCode.RUNTIME_INITIALIZE_ERROR, message, sources)
Failed to initialize runtime
451class OuisyncError_ServiceAlreadyRunning(OuisyncError): 452 """Another instance of the service is already running""" 453 def __init__(self, message: str | None = None, sources: list[str] | None = None): 454 super().__init__(ErrorCode.SERVICE_ALREADY_RUNNING, message, sources)
Another instance of the service is already running
456class OuisyncError_StoreDirUnspecified(OuisyncError): 457 """Store directory is not specified""" 458 def __init__(self, message: str | None = None, sources: list[str] | None = None): 459 super().__init__(ErrorCode.STORE_DIR_UNSPECIFIED, message, sources)
Store directory is not specified
386class OuisyncError_StoreError(OuisyncError): 387 """Operation on the internal repository store failed""" 388 def __init__(self, message: str | None = None, sources: list[str] | None = None): 389 super().__init__(ErrorCode.STORE_ERROR, message, sources)
Operation on the internal repository store failed
426class OuisyncError_TlsCertificatesInvalid(OuisyncError): 427 """TLS certificates failed to load""" 428 def __init__(self, message: str | None = None, sources: list[str] | None = None): 429 super().__init__(ErrorCode.TLS_CERTIFICATES_INVALID, message, sources)
TLS certificates failed to load
421class OuisyncError_TlsCertificatesNotFound(OuisyncError): 422 """TLS certificated not found""" 423 def __init__(self, message: str | None = None, sources: list[str] | None = None): 424 super().__init__(ErrorCode.TLS_CERTIFICATES_NOT_FOUND, message, sources)
TLS certificated not found
436class OuisyncError_TlsConfigError(OuisyncError): 437 """Failed to create TLS config""" 438 def __init__(self, message: str | None = None, sources: list[str] | None = None): 439 super().__init__(ErrorCode.TLS_CONFIG_ERROR, message, sources)
Failed to create TLS config
431class OuisyncError_TlsKeysNotFound(OuisyncError): 432 """TLS keys not found""" 433 def __init__(self, message: str | None = None, sources: list[str] | None = None): 434 super().__init__(ErrorCode.TLS_KEYS_NOT_FOUND, message, sources)
TLS keys not found
371class OuisyncError_TransportError(OuisyncError): 372 """Failed to send or receive message""" 373 def __init__(self, message: str | None = None, sources: list[str] | None = None): 374 super().__init__(ErrorCode.TRANSPORT_ERROR, message, sources)
Failed to send or receive message
351class OuisyncError_Unsupported(OuisyncError): 352 """The indended operation is not supported""" 353 def __init__(self, message: str | None = None, sources: list[str] | None = None): 354 super().__init__(ErrorCode.UNSUPPORTED, message, sources)
The indended operation is not supported
441class OuisyncError_VfsDriverInstallError(OuisyncError): 442 """Failed to install virtual filesystem driver""" 443 def __init__(self, message: str | None = None, sources: list[str] | None = None): 444 super().__init__(ErrorCode.VFS_DRIVER_INSTALL_ERROR, message, sources)
Failed to install virtual filesystem driver
446class OuisyncError_VfsOtherError(OuisyncError): 447 """Unspecified virtual filesystem error""" 448 def __init__(self, message: str | None = None, sources: list[str] | None = None): 449 super().__init__(ErrorCode.VFS_OTHER_ERROR, message, sources)
Unspecified virtual filesystem error
32@dataclass 33class Password: 34 """ 35 A simple wrapper over String to avoid certain kinds of attack. For more elaboration please see 36 the documentation for the SecretKey structure. 37 """ 38 _shape: ClassVar[str] = "unnamed" 39 value: str 40 def __repr__(self) -> str: 41 return f"{type(self).__name__}(******)"
A simple wrapper over String to avoid certain kinds of attack. For more elaboration please see the documentation for the SecretKey structure.
159@dataclass 160class PeerInfo: 161 """Information about a peer.""" 162 _shape: ClassVar[str] = "named" 163 addr: str 164 source: PeerSource 165 state: PeerState 166 stats: Stats
Information about a peer.
168class PeerSource(IntEnum): 169 """How was the peer discovered.""" 170 USER_PROVIDED = 0 171 """Explicitly added by the user.""" 172 LISTENER = 1 173 """Peer connected to us.""" 174 LOCAL_DISCOVERY = 2 175 """Discovered on the Local Discovery.""" 176 DHT = 3 177 """Discovered on the DHT.""" 178 PEER_EXCHANGE = 4 179 """Discovered on the Peer Exchange."""
How was the peer discovered.
199@dataclass 200class PeerState_Active(PeerState): 201 _tag: ClassVar[str] = "Active" 202 _shape: ClassVar[str] = "named" 203 id: PublicRuntimeId 204 since: typing.Any
227@dataclass 228class Progress: 229 """Progress of a task.""" 230 _shape: ClassVar[str] = "named" 231 value: int 232 total: int
Progress of a task.
538@dataclass 539class QuotaInfo: 540 _shape: ClassVar[str] = "named" 541 quota: StorageSize | None 542 size: StorageSize
2641class Repository: 2642 def __init__(self, client: Client, handle: RepositoryHandle): 2643 """@private""" 2644 self._client = client 2645 self._handle = handle 2646 2647 async def close( 2648 self, 2649 ): 2650 """Closes the repository.""" 2651 request = Request_RepositoryClose( 2652 self._handle, 2653 ) 2654 response = await self._client.invoke(request) 2655 if isinstance(response, Response_Unit): 2656 return 2657 raise UnexpectedResponse() 2658 2659 async def create_directory( 2660 self, 2661 *, 2662 path: str, 2663 ): 2664 """Creates a new directory at the given path in the repository.""" 2665 request = Request_RepositoryCreateDirectory( 2666 self._handle, 2667 path, 2668 ) 2669 response = await self._client.invoke(request) 2670 if isinstance(response, Response_Unit): 2671 return 2672 raise UnexpectedResponse() 2673 2674 async def create_file( 2675 self, 2676 *, 2677 path: str, 2678 ) -> File: 2679 """Creates a new file at the given path in the repository.""" 2680 request = Request_RepositoryCreateFile( 2681 self._handle, 2682 path, 2683 ) 2684 response = await self._client.invoke(request) 2685 if isinstance(response, Response_File): 2686 return File(self._client, response.value) 2687 raise UnexpectedResponse() 2688 2689 async def create_mirror( 2690 self, 2691 *, 2692 host: str, 2693 ): 2694 """ 2695 Creates mirror of this repository on the given cache server host. 2696 2697 Cache servers relay traffic between Ouisync peers and also temporarily store data. They are 2698 useful when direct P2P connection fails (e.g. due to restrictive NAT) and also to allow 2699 syncing when the peers are not online at the same time (they still need to be online within 2700 ~24 hours of each other). 2701 2702 Requires the repository to be opened in write mode. 2703 """ 2704 request = Request_RepositoryCreateMirror( 2705 self._handle, 2706 host, 2707 ) 2708 response = await self._client.invoke(request) 2709 if isinstance(response, Response_Unit): 2710 return 2711 raise UnexpectedResponse() 2712 2713 async def delete( 2714 self, 2715 ): 2716 """Delete the repository""" 2717 request = Request_RepositoryDelete( 2718 self._handle, 2719 ) 2720 response = await self._client.invoke(request) 2721 if isinstance(response, Response_Unit): 2722 return 2723 raise UnexpectedResponse() 2724 2725 async def delete_mirror( 2726 self, 2727 *, 2728 host: str, 2729 ): 2730 """ 2731 Deletes mirror of this repository from the given cache server host. 2732 2733 Requires the repository to be opened in write mode. 2734 """ 2735 request = Request_RepositoryDeleteMirror( 2736 self._handle, 2737 host, 2738 ) 2739 response = await self._client.invoke(request) 2740 if isinstance(response, Response_Unit): 2741 return 2742 raise UnexpectedResponse() 2743 2744 async def export( 2745 self, 2746 *, 2747 output_path: str, 2748 ) -> str: 2749 """Export repository to file""" 2750 request = Request_RepositoryExport( 2751 self._handle, 2752 output_path, 2753 ) 2754 response = await self._client.invoke(request) 2755 if isinstance(response, Response_Path): 2756 return response.value 2757 raise UnexpectedResponse() 2758 2759 async def file_exists( 2760 self, 2761 *, 2762 path: str, 2763 ) -> bool: 2764 request = Request_RepositoryFileExists( 2765 self._handle, 2766 path, 2767 ) 2768 response = await self._client.invoke(request) 2769 if isinstance(response, Response_Bool): 2770 return response.value 2771 raise UnexpectedResponse() 2772 2773 async def get_access_mode( 2774 self, 2775 ) -> AccessMode: 2776 """Returns the access mode (*blind*, *read* or *write*) the repository is currently opened in.""" 2777 request = Request_RepositoryGetAccessMode( 2778 self._handle, 2779 ) 2780 response = await self._client.invoke(request) 2781 if isinstance(response, Response_AccessMode): 2782 return response.value 2783 raise UnexpectedResponse() 2784 2785 async def get_block_expiration( 2786 self, 2787 ) -> int | None: 2788 request = Request_RepositoryGetBlockExpiration( 2789 self._handle, 2790 ) 2791 response = await self._client.invoke(request) 2792 if isinstance(response, Response_Duration): 2793 return response.value 2794 if isinstance(response, Response_None): 2795 return None 2796 raise UnexpectedResponse() 2797 2798 async def get_credentials( 2799 self, 2800 ) -> bytes: 2801 """ 2802 Gets the current credentials of this repository. Can be used to restore access after closing 2803 and reopening the repository. 2804 """ 2805 request = Request_RepositoryGetCredentials( 2806 self._handle, 2807 ) 2808 response = await self._client.invoke(request) 2809 if isinstance(response, Response_Bytes): 2810 return response.value 2811 raise UnexpectedResponse() 2812 2813 async def get_entry_type( 2814 self, 2815 *, 2816 path: str, 2817 ) -> EntryType | None: 2818 """ 2819 Returns the type of repository entry (file, directory, ...) or `None` if the entry doesn't 2820 exist. 2821 """ 2822 request = Request_RepositoryGetEntryType( 2823 self._handle, 2824 path, 2825 ) 2826 response = await self._client.invoke(request) 2827 if isinstance(response, Response_EntryType): 2828 return response.value 2829 if isinstance(response, Response_None): 2830 return None 2831 raise UnexpectedResponse() 2832 2833 async def get_expiration( 2834 self, 2835 ) -> int | None: 2836 request = Request_RepositoryGetExpiration( 2837 self._handle, 2838 ) 2839 response = await self._client.invoke(request) 2840 if isinstance(response, Response_Duration): 2841 return response.value 2842 if isinstance(response, Response_None): 2843 return None 2844 raise UnexpectedResponse() 2845 2846 async def get_info_hash( 2847 self, 2848 ) -> str: 2849 """ 2850 Return the info-hash of the repository formatted as hex string. This can be used as a 2851 globally unique, non-secret identifier of the repository. 2852 """ 2853 request = Request_RepositoryGetInfoHash( 2854 self._handle, 2855 ) 2856 response = await self._client.invoke(request) 2857 if isinstance(response, Response_String): 2858 return response.value 2859 raise UnexpectedResponse() 2860 2861 async def get_metadata( 2862 self, 2863 *, 2864 key: str, 2865 ) -> str | None: 2866 request = Request_RepositoryGetMetadata( 2867 self._handle, 2868 key, 2869 ) 2870 response = await self._client.invoke(request) 2871 if isinstance(response, Response_String): 2872 return response.value 2873 if isinstance(response, Response_None): 2874 return None 2875 raise UnexpectedResponse() 2876 2877 async def get_mount_point( 2878 self, 2879 ) -> str | None: 2880 request = Request_RepositoryGetMountPoint( 2881 self._handle, 2882 ) 2883 response = await self._client.invoke(request) 2884 if isinstance(response, Response_Path): 2885 return response.value 2886 if isinstance(response, Response_None): 2887 return None 2888 raise UnexpectedResponse() 2889 2890 async def get_path( 2891 self, 2892 ) -> str: 2893 request = Request_RepositoryGetPath( 2894 self._handle, 2895 ) 2896 response = await self._client.invoke(request) 2897 if isinstance(response, Response_Path): 2898 return response.value 2899 raise UnexpectedResponse() 2900 2901 async def get_quota( 2902 self, 2903 ) -> QuotaInfo: 2904 request = Request_RepositoryGetQuota( 2905 self._handle, 2906 ) 2907 response = await self._client.invoke(request) 2908 if isinstance(response, Response_QuotaInfo): 2909 return response.value 2910 raise UnexpectedResponse() 2911 2912 async def get_short_name( 2913 self, 2914 ) -> str: 2915 request = Request_RepositoryGetShortName( 2916 self._handle, 2917 ) 2918 response = await self._client.invoke(request) 2919 if isinstance(response, Response_String): 2920 return response.value 2921 raise UnexpectedResponse() 2922 2923 async def get_stats( 2924 self, 2925 ) -> Stats: 2926 request = Request_RepositoryGetStats( 2927 self._handle, 2928 ) 2929 response = await self._client.invoke(request) 2930 if isinstance(response, Response_Stats): 2931 return response.value 2932 raise UnexpectedResponse() 2933 2934 async def get_sync_progress( 2935 self, 2936 ) -> Progress: 2937 """ 2938 Returns the synchronization progress of this repository as the number of bytes already 2939 synced ([Progress.value]) vs. the total size of the repository in bytes ([Progress.total]). 2940 """ 2941 request = Request_RepositoryGetSyncProgress( 2942 self._handle, 2943 ) 2944 response = await self._client.invoke(request) 2945 if isinstance(response, Response_Progress): 2946 return response.value 2947 raise UnexpectedResponse() 2948 2949 async def is_dht_enabled( 2950 self, 2951 ) -> bool: 2952 """Is Bittorrent DHT enabled?""" 2953 request = Request_RepositoryIsDhtEnabled( 2954 self._handle, 2955 ) 2956 response = await self._client.invoke(request) 2957 if isinstance(response, Response_Bool): 2958 return response.value 2959 raise UnexpectedResponse() 2960 2961 async def is_pex_enabled( 2962 self, 2963 ) -> bool: 2964 """Is Peer Exchange enabled?""" 2965 request = Request_RepositoryIsPexEnabled( 2966 self._handle, 2967 ) 2968 response = await self._client.invoke(request) 2969 if isinstance(response, Response_Bool): 2970 return response.value 2971 raise UnexpectedResponse() 2972 2973 async def is_sync_enabled( 2974 self, 2975 ) -> bool: 2976 """Returns whether syncing with other replicas is enabled for this repository.""" 2977 request = Request_RepositoryIsSyncEnabled( 2978 self._handle, 2979 ) 2980 response = await self._client.invoke(request) 2981 if isinstance(response, Response_Bool): 2982 return response.value 2983 raise UnexpectedResponse() 2984 2985 async def mirror_exists( 2986 self, 2987 *, 2988 host: str, 2989 ) -> bool: 2990 """Checks if this repository is mirrored on the given cache server host.""" 2991 request = Request_RepositoryMirrorExists( 2992 self._handle, 2993 host, 2994 ) 2995 response = await self._client.invoke(request) 2996 if isinstance(response, Response_Bool): 2997 return response.value 2998 raise UnexpectedResponse() 2999 3000 async def mount( 3001 self, 3002 ) -> str: 3003 request = Request_RepositoryMount( 3004 self._handle, 3005 ) 3006 response = await self._client.invoke(request) 3007 if isinstance(response, Response_Path): 3008 return response.value 3009 raise UnexpectedResponse() 3010 3011 async def move( 3012 self, 3013 *, 3014 dst: str, 3015 ): 3016 request = Request_RepositoryMove( 3017 self._handle, 3018 dst, 3019 ) 3020 response = await self._client.invoke(request) 3021 if isinstance(response, Response_Unit): 3022 return 3023 raise UnexpectedResponse() 3024 3025 async def move_entry( 3026 self, 3027 *, 3028 src: str, 3029 dst: str, 3030 ): 3031 """Moves an entry (file or directory) from `src` to `dst`.""" 3032 request = Request_RepositoryMoveEntry( 3033 self._handle, 3034 src, 3035 dst, 3036 ) 3037 response = await self._client.invoke(request) 3038 if isinstance(response, Response_Unit): 3039 return 3040 raise UnexpectedResponse() 3041 3042 async def open_file( 3043 self, 3044 *, 3045 path: str, 3046 ) -> File: 3047 """Opens an existing file at the given path in the repository.""" 3048 request = Request_RepositoryOpenFile( 3049 self._handle, 3050 path, 3051 ) 3052 response = await self._client.invoke(request) 3053 if isinstance(response, Response_File): 3054 return File(self._client, response.value) 3055 raise UnexpectedResponse() 3056 3057 async def read_directory( 3058 self, 3059 *, 3060 path: str, 3061 ) -> list[DirectoryEntry]: 3062 """Returns the entries of the directory at the given path in the repository.""" 3063 request = Request_RepositoryReadDirectory( 3064 self._handle, 3065 path, 3066 ) 3067 response = await self._client.invoke(request) 3068 if isinstance(response, Response_DirectoryEntries): 3069 return response.value 3070 raise UnexpectedResponse() 3071 3072 async def remove_directory( 3073 self, 3074 *, 3075 path: str, 3076 recursive: bool = False, 3077 ): 3078 """ 3079 Removes the directory at the given path from the repository. If `recursive` is true it removes 3080 also the contents, otherwise the directory must be empty. 3081 """ 3082 request = Request_RepositoryRemoveDirectory( 3083 self._handle, 3084 path, 3085 recursive, 3086 ) 3087 response = await self._client.invoke(request) 3088 if isinstance(response, Response_Unit): 3089 return 3090 raise UnexpectedResponse() 3091 3092 async def remove_file( 3093 self, 3094 *, 3095 path: str, 3096 ): 3097 """Removes (deletes) the file at the given path from the repository.""" 3098 request = Request_RepositoryRemoveFile( 3099 self._handle, 3100 path, 3101 ) 3102 response = await self._client.invoke(request) 3103 if isinstance(response, Response_Unit): 3104 return 3105 raise UnexpectedResponse() 3106 3107 async def reset_access( 3108 self, 3109 *, 3110 token: str, 3111 ): 3112 request = Request_RepositoryResetAccess( 3113 self._handle, 3114 token, 3115 ) 3116 response = await self._client.invoke(request) 3117 if isinstance(response, Response_Unit): 3118 return 3119 raise UnexpectedResponse() 3120 3121 async def set_access( 3122 self, 3123 *, 3124 read: AccessChange | None = None, 3125 write: AccessChange | None = None, 3126 ): 3127 """ 3128 Sets, unsets or changes local secrets for accessing the repository or disables the given 3129 access mode. 3130 3131 ## Examples 3132 3133 To protect both read and write access with the same password: 3134 3135 ```kotlin 3136 val password = Password("supersecret") 3137 repo.setAccess(read: AccessChange.Enable(password), write: AccessChange.Enable(password)) 3138 ``` 3139 3140 To require password only for writing: 3141 3142 ```kotlin 3143 repo.setAccess(read: AccessChange.Enable(null), write: AccessChange.Enable(password)) 3144 ``` 3145 3146 To competelly disable write access but leave read access as it was. Warning: this operation 3147 is currently irreversibe. 3148 3149 ```kotlin 3150 repo.setAccess(read: null, write: AccessChange.Disable) 3151 ``` 3152 """ 3153 request = Request_RepositorySetAccess( 3154 self._handle, 3155 read, 3156 write, 3157 ) 3158 response = await self._client.invoke(request) 3159 if isinstance(response, Response_Unit): 3160 return 3161 raise UnexpectedResponse() 3162 3163 async def set_access_mode( 3164 self, 3165 *, 3166 access_mode: AccessMode, 3167 local_secret: LocalSecret | None = None, 3168 ): 3169 """ 3170 Switches the repository to the given access mode. 3171 3172 - `access_mode` is the desired access mode to switch to. 3173 - `local_secret` is the local secret protecting the desired access mode. Can be `None` if no 3174 local secret is used. 3175 """ 3176 request = Request_RepositorySetAccessMode( 3177 self._handle, 3178 access_mode, 3179 local_secret, 3180 ) 3181 response = await self._client.invoke(request) 3182 if isinstance(response, Response_Unit): 3183 return 3184 raise UnexpectedResponse() 3185 3186 async def set_block_expiration( 3187 self, 3188 *, 3189 value: int | None = None, 3190 ): 3191 request = Request_RepositorySetBlockExpiration( 3192 self._handle, 3193 value, 3194 ) 3195 response = await self._client.invoke(request) 3196 if isinstance(response, Response_Unit): 3197 return 3198 raise UnexpectedResponse() 3199 3200 async def set_credentials( 3201 self, 3202 *, 3203 credentials: bytes, 3204 ): 3205 """Sets the current credentials of the repository.""" 3206 request = Request_RepositorySetCredentials( 3207 self._handle, 3208 credentials, 3209 ) 3210 response = await self._client.invoke(request) 3211 if isinstance(response, Response_Unit): 3212 return 3213 raise UnexpectedResponse() 3214 3215 async def set_dht_enabled( 3216 self, 3217 *, 3218 enabled: bool = False, 3219 ): 3220 """Enables/disabled Bittorrent DHT (for peer discovery).""" 3221 request = Request_RepositorySetDhtEnabled( 3222 self._handle, 3223 enabled, 3224 ) 3225 response = await self._client.invoke(request) 3226 if isinstance(response, Response_Unit): 3227 return 3228 raise UnexpectedResponse() 3229 3230 async def set_expiration( 3231 self, 3232 *, 3233 value: int | None = None, 3234 ): 3235 request = Request_RepositorySetExpiration( 3236 self._handle, 3237 value, 3238 ) 3239 response = await self._client.invoke(request) 3240 if isinstance(response, Response_Unit): 3241 return 3242 raise UnexpectedResponse() 3243 3244 async def set_metadata( 3245 self, 3246 *, 3247 edits: list[MetadataEdit], 3248 ) -> bool: 3249 request = Request_RepositorySetMetadata( 3250 self._handle, 3251 edits, 3252 ) 3253 response = await self._client.invoke(request) 3254 if isinstance(response, Response_Bool): 3255 return response.value 3256 raise UnexpectedResponse() 3257 3258 async def set_pex_enabled( 3259 self, 3260 *, 3261 enabled: bool = False, 3262 ): 3263 """Enables/disables Peer Exchange (for peer discovery).""" 3264 request = Request_RepositorySetPexEnabled( 3265 self._handle, 3266 enabled, 3267 ) 3268 response = await self._client.invoke(request) 3269 if isinstance(response, Response_Unit): 3270 return 3271 raise UnexpectedResponse() 3272 3273 async def set_quota( 3274 self, 3275 *, 3276 value: StorageSize | None = None, 3277 ): 3278 request = Request_RepositorySetQuota( 3279 self._handle, 3280 value, 3281 ) 3282 response = await self._client.invoke(request) 3283 if isinstance(response, Response_Unit): 3284 return 3285 raise UnexpectedResponse() 3286 3287 async def set_sync_enabled( 3288 self, 3289 *, 3290 enabled: bool = False, 3291 ): 3292 """ 3293 Enabled or disables syncing with other replicas. 3294 3295 Note syncing is initially disabled. 3296 """ 3297 request = Request_RepositorySetSyncEnabled( 3298 self._handle, 3299 enabled, 3300 ) 3301 response = await self._client.invoke(request) 3302 if isinstance(response, Response_Unit): 3303 return 3304 raise UnexpectedResponse() 3305 3306 async def share( 3307 self, 3308 *, 3309 access_mode: AccessMode, 3310 local_secret: LocalSecret | None = None, 3311 ) -> str: 3312 """ 3313 Creates a *share token* to share this repository with other devices. 3314 3315 By default the access mode of the token will be the same as the mode the repo is currently 3316 opened in but it can be escalated with the `local_secret` param or de-escalated with the 3317 `access_mode` param. 3318 3319 - `access_mode`: access mode of the token. Useful to de-escalate the access mode to below of 3320 what the repo is opened in. 3321 - `local_secret`: the local repo secret. If not `None`, the share token's access mode will 3322 be the same as what the secret provides. Useful to escalate the access mode to above of 3323 what the repo is opened in. 3324 """ 3325 request = Request_RepositoryShare( 3326 self._handle, 3327 access_mode, 3328 local_secret, 3329 ) 3330 response = await self._client.invoke(request) 3331 if isinstance(response, Response_ShareToken): 3332 return response.value 3333 raise UnexpectedResponse() 3334 3335 async def unmount( 3336 self, 3337 ): 3338 request = Request_RepositoryUnmount( 3339 self._handle, 3340 ) 3341 response = await self._client.invoke(request) 3342 if isinstance(response, Response_Unit): 3343 return 3344 raise UnexpectedResponse()
2647 async def close( 2648 self, 2649 ): 2650 """Closes the repository.""" 2651 request = Request_RepositoryClose( 2652 self._handle, 2653 ) 2654 response = await self._client.invoke(request) 2655 if isinstance(response, Response_Unit): 2656 return 2657 raise UnexpectedResponse()
Closes the repository.
2659 async def create_directory( 2660 self, 2661 *, 2662 path: str, 2663 ): 2664 """Creates a new directory at the given path in the repository.""" 2665 request = Request_RepositoryCreateDirectory( 2666 self._handle, 2667 path, 2668 ) 2669 response = await self._client.invoke(request) 2670 if isinstance(response, Response_Unit): 2671 return 2672 raise UnexpectedResponse()
Creates a new directory at the given path in the repository.
2674 async def create_file( 2675 self, 2676 *, 2677 path: str, 2678 ) -> File: 2679 """Creates a new file at the given path in the repository.""" 2680 request = Request_RepositoryCreateFile( 2681 self._handle, 2682 path, 2683 ) 2684 response = await self._client.invoke(request) 2685 if isinstance(response, Response_File): 2686 return File(self._client, response.value) 2687 raise UnexpectedResponse()
Creates a new file at the given path in the repository.
2689 async def create_mirror( 2690 self, 2691 *, 2692 host: str, 2693 ): 2694 """ 2695 Creates mirror of this repository on the given cache server host. 2696 2697 Cache servers relay traffic between Ouisync peers and also temporarily store data. They are 2698 useful when direct P2P connection fails (e.g. due to restrictive NAT) and also to allow 2699 syncing when the peers are not online at the same time (they still need to be online within 2700 ~24 hours of each other). 2701 2702 Requires the repository to be opened in write mode. 2703 """ 2704 request = Request_RepositoryCreateMirror( 2705 self._handle, 2706 host, 2707 ) 2708 response = await self._client.invoke(request) 2709 if isinstance(response, Response_Unit): 2710 return 2711 raise UnexpectedResponse()
Creates mirror of this repository on the given cache server host.
Cache servers relay traffic between Ouisync peers and also temporarily store data. They are useful when direct P2P connection fails (e.g. due to restrictive NAT) and also to allow syncing when the peers are not online at the same time (they still need to be online within ~24 hours of each other).
Requires the repository to be opened in write mode.
2713 async def delete( 2714 self, 2715 ): 2716 """Delete the repository""" 2717 request = Request_RepositoryDelete( 2718 self._handle, 2719 ) 2720 response = await self._client.invoke(request) 2721 if isinstance(response, Response_Unit): 2722 return 2723 raise UnexpectedResponse()
Delete the repository
2725 async def delete_mirror( 2726 self, 2727 *, 2728 host: str, 2729 ): 2730 """ 2731 Deletes mirror of this repository from the given cache server host. 2732 2733 Requires the repository to be opened in write mode. 2734 """ 2735 request = Request_RepositoryDeleteMirror( 2736 self._handle, 2737 host, 2738 ) 2739 response = await self._client.invoke(request) 2740 if isinstance(response, Response_Unit): 2741 return 2742 raise UnexpectedResponse()
Deletes mirror of this repository from the given cache server host.
Requires the repository to be opened in write mode.
2744 async def export( 2745 self, 2746 *, 2747 output_path: str, 2748 ) -> str: 2749 """Export repository to file""" 2750 request = Request_RepositoryExport( 2751 self._handle, 2752 output_path, 2753 ) 2754 response = await self._client.invoke(request) 2755 if isinstance(response, Response_Path): 2756 return response.value 2757 raise UnexpectedResponse()
Export repository to file
2759 async def file_exists( 2760 self, 2761 *, 2762 path: str, 2763 ) -> bool: 2764 request = Request_RepositoryFileExists( 2765 self._handle, 2766 path, 2767 ) 2768 response = await self._client.invoke(request) 2769 if isinstance(response, Response_Bool): 2770 return response.value 2771 raise UnexpectedResponse()
2773 async def get_access_mode( 2774 self, 2775 ) -> AccessMode: 2776 """Returns the access mode (*blind*, *read* or *write*) the repository is currently opened in.""" 2777 request = Request_RepositoryGetAccessMode( 2778 self._handle, 2779 ) 2780 response = await self._client.invoke(request) 2781 if isinstance(response, Response_AccessMode): 2782 return response.value 2783 raise UnexpectedResponse()
Returns the access mode (blind, read or write) the repository is currently opened in.
2785 async def get_block_expiration( 2786 self, 2787 ) -> int | None: 2788 request = Request_RepositoryGetBlockExpiration( 2789 self._handle, 2790 ) 2791 response = await self._client.invoke(request) 2792 if isinstance(response, Response_Duration): 2793 return response.value 2794 if isinstance(response, Response_None): 2795 return None 2796 raise UnexpectedResponse()
2798 async def get_credentials( 2799 self, 2800 ) -> bytes: 2801 """ 2802 Gets the current credentials of this repository. Can be used to restore access after closing 2803 and reopening the repository. 2804 """ 2805 request = Request_RepositoryGetCredentials( 2806 self._handle, 2807 ) 2808 response = await self._client.invoke(request) 2809 if isinstance(response, Response_Bytes): 2810 return response.value 2811 raise UnexpectedResponse()
Gets the current credentials of this repository. Can be used to restore access after closing and reopening the repository.
2813 async def get_entry_type( 2814 self, 2815 *, 2816 path: str, 2817 ) -> EntryType | None: 2818 """ 2819 Returns the type of repository entry (file, directory, ...) or `None` if the entry doesn't 2820 exist. 2821 """ 2822 request = Request_RepositoryGetEntryType( 2823 self._handle, 2824 path, 2825 ) 2826 response = await self._client.invoke(request) 2827 if isinstance(response, Response_EntryType): 2828 return response.value 2829 if isinstance(response, Response_None): 2830 return None 2831 raise UnexpectedResponse()
Returns the type of repository entry (file, directory, ...) or None if the entry doesn't
exist.
2833 async def get_expiration( 2834 self, 2835 ) -> int | None: 2836 request = Request_RepositoryGetExpiration( 2837 self._handle, 2838 ) 2839 response = await self._client.invoke(request) 2840 if isinstance(response, Response_Duration): 2841 return response.value 2842 if isinstance(response, Response_None): 2843 return None 2844 raise UnexpectedResponse()
2846 async def get_info_hash( 2847 self, 2848 ) -> str: 2849 """ 2850 Return the info-hash of the repository formatted as hex string. This can be used as a 2851 globally unique, non-secret identifier of the repository. 2852 """ 2853 request = Request_RepositoryGetInfoHash( 2854 self._handle, 2855 ) 2856 response = await self._client.invoke(request) 2857 if isinstance(response, Response_String): 2858 return response.value 2859 raise UnexpectedResponse()
Return the info-hash of the repository formatted as hex string. This can be used as a globally unique, non-secret identifier of the repository.
2861 async def get_metadata( 2862 self, 2863 *, 2864 key: str, 2865 ) -> str | None: 2866 request = Request_RepositoryGetMetadata( 2867 self._handle, 2868 key, 2869 ) 2870 response = await self._client.invoke(request) 2871 if isinstance(response, Response_String): 2872 return response.value 2873 if isinstance(response, Response_None): 2874 return None 2875 raise UnexpectedResponse()
2877 async def get_mount_point( 2878 self, 2879 ) -> str | None: 2880 request = Request_RepositoryGetMountPoint( 2881 self._handle, 2882 ) 2883 response = await self._client.invoke(request) 2884 if isinstance(response, Response_Path): 2885 return response.value 2886 if isinstance(response, Response_None): 2887 return None 2888 raise UnexpectedResponse()
2934 async def get_sync_progress( 2935 self, 2936 ) -> Progress: 2937 """ 2938 Returns the synchronization progress of this repository as the number of bytes already 2939 synced ([Progress.value]) vs. the total size of the repository in bytes ([Progress.total]). 2940 """ 2941 request = Request_RepositoryGetSyncProgress( 2942 self._handle, 2943 ) 2944 response = await self._client.invoke(request) 2945 if isinstance(response, Response_Progress): 2946 return response.value 2947 raise UnexpectedResponse()
Returns the synchronization progress of this repository as the number of bytes already synced ([Progress.value]) vs. the total size of the repository in bytes ([Progress.total]).
2949 async def is_dht_enabled( 2950 self, 2951 ) -> bool: 2952 """Is Bittorrent DHT enabled?""" 2953 request = Request_RepositoryIsDhtEnabled( 2954 self._handle, 2955 ) 2956 response = await self._client.invoke(request) 2957 if isinstance(response, Response_Bool): 2958 return response.value 2959 raise UnexpectedResponse()
Is Bittorrent DHT enabled?
2961 async def is_pex_enabled( 2962 self, 2963 ) -> bool: 2964 """Is Peer Exchange enabled?""" 2965 request = Request_RepositoryIsPexEnabled( 2966 self._handle, 2967 ) 2968 response = await self._client.invoke(request) 2969 if isinstance(response, Response_Bool): 2970 return response.value 2971 raise UnexpectedResponse()
Is Peer Exchange enabled?
2973 async def is_sync_enabled( 2974 self, 2975 ) -> bool: 2976 """Returns whether syncing with other replicas is enabled for this repository.""" 2977 request = Request_RepositoryIsSyncEnabled( 2978 self._handle, 2979 ) 2980 response = await self._client.invoke(request) 2981 if isinstance(response, Response_Bool): 2982 return response.value 2983 raise UnexpectedResponse()
Returns whether syncing with other replicas is enabled for this repository.
2985 async def mirror_exists( 2986 self, 2987 *, 2988 host: str, 2989 ) -> bool: 2990 """Checks if this repository is mirrored on the given cache server host.""" 2991 request = Request_RepositoryMirrorExists( 2992 self._handle, 2993 host, 2994 ) 2995 response = await self._client.invoke(request) 2996 if isinstance(response, Response_Bool): 2997 return response.value 2998 raise UnexpectedResponse()
Checks if this repository is mirrored on the given cache server host.
3025 async def move_entry( 3026 self, 3027 *, 3028 src: str, 3029 dst: str, 3030 ): 3031 """Moves an entry (file or directory) from `src` to `dst`.""" 3032 request = Request_RepositoryMoveEntry( 3033 self._handle, 3034 src, 3035 dst, 3036 ) 3037 response = await self._client.invoke(request) 3038 if isinstance(response, Response_Unit): 3039 return 3040 raise UnexpectedResponse()
Moves an entry (file or directory) from src to dst.
3042 async def open_file( 3043 self, 3044 *, 3045 path: str, 3046 ) -> File: 3047 """Opens an existing file at the given path in the repository.""" 3048 request = Request_RepositoryOpenFile( 3049 self._handle, 3050 path, 3051 ) 3052 response = await self._client.invoke(request) 3053 if isinstance(response, Response_File): 3054 return File(self._client, response.value) 3055 raise UnexpectedResponse()
Opens an existing file at the given path in the repository.
3057 async def read_directory( 3058 self, 3059 *, 3060 path: str, 3061 ) -> list[DirectoryEntry]: 3062 """Returns the entries of the directory at the given path in the repository.""" 3063 request = Request_RepositoryReadDirectory( 3064 self._handle, 3065 path, 3066 ) 3067 response = await self._client.invoke(request) 3068 if isinstance(response, Response_DirectoryEntries): 3069 return response.value 3070 raise UnexpectedResponse()
Returns the entries of the directory at the given path in the repository.
3072 async def remove_directory( 3073 self, 3074 *, 3075 path: str, 3076 recursive: bool = False, 3077 ): 3078 """ 3079 Removes the directory at the given path from the repository. If `recursive` is true it removes 3080 also the contents, otherwise the directory must be empty. 3081 """ 3082 request = Request_RepositoryRemoveDirectory( 3083 self._handle, 3084 path, 3085 recursive, 3086 ) 3087 response = await self._client.invoke(request) 3088 if isinstance(response, Response_Unit): 3089 return 3090 raise UnexpectedResponse()
Removes the directory at the given path from the repository. If recursive is true it removes
also the contents, otherwise the directory must be empty.
3092 async def remove_file( 3093 self, 3094 *, 3095 path: str, 3096 ): 3097 """Removes (deletes) the file at the given path from the repository.""" 3098 request = Request_RepositoryRemoveFile( 3099 self._handle, 3100 path, 3101 ) 3102 response = await self._client.invoke(request) 3103 if isinstance(response, Response_Unit): 3104 return 3105 raise UnexpectedResponse()
Removes (deletes) the file at the given path from the repository.
3121 async def set_access( 3122 self, 3123 *, 3124 read: AccessChange | None = None, 3125 write: AccessChange | None = None, 3126 ): 3127 """ 3128 Sets, unsets or changes local secrets for accessing the repository or disables the given 3129 access mode. 3130 3131 ## Examples 3132 3133 To protect both read and write access with the same password: 3134 3135 ```kotlin 3136 val password = Password("supersecret") 3137 repo.setAccess(read: AccessChange.Enable(password), write: AccessChange.Enable(password)) 3138 ``` 3139 3140 To require password only for writing: 3141 3142 ```kotlin 3143 repo.setAccess(read: AccessChange.Enable(null), write: AccessChange.Enable(password)) 3144 ``` 3145 3146 To competelly disable write access but leave read access as it was. Warning: this operation 3147 is currently irreversibe. 3148 3149 ```kotlin 3150 repo.setAccess(read: null, write: AccessChange.Disable) 3151 ``` 3152 """ 3153 request = Request_RepositorySetAccess( 3154 self._handle, 3155 read, 3156 write, 3157 ) 3158 response = await self._client.invoke(request) 3159 if isinstance(response, Response_Unit): 3160 return 3161 raise UnexpectedResponse()
Sets, unsets or changes local secrets for accessing the repository or disables the given access mode.
Examples
To protect both read and write access with the same password:
val password = Password("supersecret")
repo.setAccess(read: AccessChange.Enable(password), write: AccessChange.Enable(password))
To require password only for writing:
repo.setAccess(read: AccessChange.Enable(null), write: AccessChange.Enable(password))
To competelly disable write access but leave read access as it was. Warning: this operation is currently irreversibe.
repo.setAccess(read: null, write: AccessChange.Disable)
3163 async def set_access_mode( 3164 self, 3165 *, 3166 access_mode: AccessMode, 3167 local_secret: LocalSecret | None = None, 3168 ): 3169 """ 3170 Switches the repository to the given access mode. 3171 3172 - `access_mode` is the desired access mode to switch to. 3173 - `local_secret` is the local secret protecting the desired access mode. Can be `None` if no 3174 local secret is used. 3175 """ 3176 request = Request_RepositorySetAccessMode( 3177 self._handle, 3178 access_mode, 3179 local_secret, 3180 ) 3181 response = await self._client.invoke(request) 3182 if isinstance(response, Response_Unit): 3183 return 3184 raise UnexpectedResponse()
Switches the repository to the given access mode.
access_modeis the desired access mode to switch to.local_secretis the local secret protecting the desired access mode. Can beNoneif no local secret is used.
3186 async def set_block_expiration( 3187 self, 3188 *, 3189 value: int | None = None, 3190 ): 3191 request = Request_RepositorySetBlockExpiration( 3192 self._handle, 3193 value, 3194 ) 3195 response = await self._client.invoke(request) 3196 if isinstance(response, Response_Unit): 3197 return 3198 raise UnexpectedResponse()
3200 async def set_credentials( 3201 self, 3202 *, 3203 credentials: bytes, 3204 ): 3205 """Sets the current credentials of the repository.""" 3206 request = Request_RepositorySetCredentials( 3207 self._handle, 3208 credentials, 3209 ) 3210 response = await self._client.invoke(request) 3211 if isinstance(response, Response_Unit): 3212 return 3213 raise UnexpectedResponse()
Sets the current credentials of the repository.
3215 async def set_dht_enabled( 3216 self, 3217 *, 3218 enabled: bool = False, 3219 ): 3220 """Enables/disabled Bittorrent DHT (for peer discovery).""" 3221 request = Request_RepositorySetDhtEnabled( 3222 self._handle, 3223 enabled, 3224 ) 3225 response = await self._client.invoke(request) 3226 if isinstance(response, Response_Unit): 3227 return 3228 raise UnexpectedResponse()
Enables/disabled Bittorrent DHT (for peer discovery).
3230 async def set_expiration( 3231 self, 3232 *, 3233 value: int | None = None, 3234 ): 3235 request = Request_RepositorySetExpiration( 3236 self._handle, 3237 value, 3238 ) 3239 response = await self._client.invoke(request) 3240 if isinstance(response, Response_Unit): 3241 return 3242 raise UnexpectedResponse()
3244 async def set_metadata( 3245 self, 3246 *, 3247 edits: list[MetadataEdit], 3248 ) -> bool: 3249 request = Request_RepositorySetMetadata( 3250 self._handle, 3251 edits, 3252 ) 3253 response = await self._client.invoke(request) 3254 if isinstance(response, Response_Bool): 3255 return response.value 3256 raise UnexpectedResponse()
3258 async def set_pex_enabled( 3259 self, 3260 *, 3261 enabled: bool = False, 3262 ): 3263 """Enables/disables Peer Exchange (for peer discovery).""" 3264 request = Request_RepositorySetPexEnabled( 3265 self._handle, 3266 enabled, 3267 ) 3268 response = await self._client.invoke(request) 3269 if isinstance(response, Response_Unit): 3270 return 3271 raise UnexpectedResponse()
Enables/disables Peer Exchange (for peer discovery).
3273 async def set_quota( 3274 self, 3275 *, 3276 value: StorageSize | None = None, 3277 ): 3278 request = Request_RepositorySetQuota( 3279 self._handle, 3280 value, 3281 ) 3282 response = await self._client.invoke(request) 3283 if isinstance(response, Response_Unit): 3284 return 3285 raise UnexpectedResponse()
3287 async def set_sync_enabled( 3288 self, 3289 *, 3290 enabled: bool = False, 3291 ): 3292 """ 3293 Enabled or disables syncing with other replicas. 3294 3295 Note syncing is initially disabled. 3296 """ 3297 request = Request_RepositorySetSyncEnabled( 3298 self._handle, 3299 enabled, 3300 ) 3301 response = await self._client.invoke(request) 3302 if isinstance(response, Response_Unit): 3303 return 3304 raise UnexpectedResponse()
Enabled or disables syncing with other replicas.
Note syncing is initially disabled.
573@dataclass 574class Request_Cancel(Request): 575 _tag: ClassVar[str] = "Cancel" 576 _shape: ClassVar[str] = "named" 577 id: MessageId
639@dataclass 640class Request_NetworkSocketSendTo(Request): 641 _tag: ClassVar[str] = "NetworkSocketSendTo" 642 _shape: ClassVar[str] = "named" 643 socket: NetworkSocketHandle 644 data: bytes 645 addr: str
653@dataclass 654class Request_NetworkStreamReadExact(Request): 655 _tag: ClassVar[str] = "NetworkStreamReadExact" 656 _shape: ClassVar[str] = "named" 657 stream: NetworkStreamHandle 658 len: int
660@dataclass 661class Request_NetworkStreamWriteAll(Request): 662 _tag: ClassVar[str] = "NetworkStreamWriteAll" 663 _shape: ClassVar[str] = "named" 664 stream: NetworkStreamHandle 665 buf: bytes
839@dataclass 840class Request_RepositoryMoveEntry(Request): 841 _tag: ClassVar[str] = "RepositoryMoveEntry" 842 _shape: ClassVar[str] = "named" 843 repo: RepositoryHandle 844 src: str 845 dst: str
861@dataclass 862class Request_RepositoryRemoveDirectory(Request): 863 _tag: ClassVar[str] = "RepositoryRemoveDirectory" 864 _shape: ClassVar[str] = "named" 865 repo: RepositoryHandle 866 path: str 867 recursive: bool
883@dataclass 884class Request_RepositorySetAccess(Request): 885 _tag: ClassVar[str] = "RepositorySetAccess" 886 _shape: ClassVar[str] = "named" 887 repo: RepositoryHandle 888 read: AccessChange | None 889 write: AccessChange | None
891@dataclass 892class Request_RepositorySetAccessMode(Request): 893 _tag: ClassVar[str] = "RepositorySetAccessMode" 894 _shape: ClassVar[str] = "named" 895 repo: RepositoryHandle 896 access_mode: AccessMode 897 local_secret: LocalSecret | None
899@dataclass 900class Request_RepositorySetBlockExpiration(Request): 901 _tag: ClassVar[str] = "RepositorySetBlockExpiration" 902 _shape: ClassVar[str] = "named" 903 repo: RepositoryHandle 904 value: int | None
906@dataclass 907class Request_RepositorySetCredentials(Request): 908 _tag: ClassVar[str] = "RepositorySetCredentials" 909 _shape: ClassVar[str] = "named" 910 repo: RepositoryHandle 911 credentials: bytes
913@dataclass 914class Request_RepositorySetDhtEnabled(Request): 915 _tag: ClassVar[str] = "RepositorySetDhtEnabled" 916 _shape: ClassVar[str] = "named" 917 repo: RepositoryHandle 918 enabled: bool
920@dataclass 921class Request_RepositorySetExpiration(Request): 922 _tag: ClassVar[str] = "RepositorySetExpiration" 923 _shape: ClassVar[str] = "named" 924 repo: RepositoryHandle 925 value: int | None
927@dataclass 928class Request_RepositorySetMetadata(Request): 929 _tag: ClassVar[str] = "RepositorySetMetadata" 930 _shape: ClassVar[str] = "named" 931 repo: RepositoryHandle 932 edits: list[MetadataEdit]
934@dataclass 935class Request_RepositorySetPexEnabled(Request): 936 _tag: ClassVar[str] = "RepositorySetPexEnabled" 937 _shape: ClassVar[str] = "named" 938 repo: RepositoryHandle 939 enabled: bool
941@dataclass 942class Request_RepositorySetQuota(Request): 943 _tag: ClassVar[str] = "RepositorySetQuota" 944 _shape: ClassVar[str] = "named" 945 repo: RepositoryHandle 946 value: StorageSize | None
948@dataclass 949class Request_RepositorySetSyncEnabled(Request): 950 _tag: ClassVar[str] = "RepositorySetSyncEnabled" 951 _shape: ClassVar[str] = "named" 952 repo: RepositoryHandle 953 enabled: bool
1008@dataclass 1009class Request_SessionCreateRepository(Request): 1010 _tag: ClassVar[str] = "SessionCreateRepository" 1011 _shape: ClassVar[str] = "named" 1012 path: str 1013 read_secret: SetLocalSecret | None 1014 write_secret: SetLocalSecret | None 1015 token: str | None 1016 sync_enabled: bool 1017 dht_enabled: bool 1018 pex_enabled: bool
1026@dataclass 1027class Request_SessionDeriveSecretKey(Request): 1028 _tag: ClassVar[str] = "SessionDeriveSecretKey" 1029 _shape: ClassVar[str] = "named" 1030 password: Password 1031 salt: PasswordSalt
1160@dataclass 1161class Request_SessionGetStateMonitor(Request): 1162 _tag: ClassVar[str] = "SessionGetStateMonitor" 1163 _shape: ClassVar[str] = "named" 1164 path: list[MonitorId]
1176@dataclass 1177class Request_SessionInitNetwork(Request): 1178 _tag: ClassVar[str] = "SessionInitNetwork" 1179 _shape: ClassVar[str] = "named" 1180 defaults: NetworkDefaults
1235@dataclass 1236class Request_SessionOpenNetworkStream(Request): 1237 _tag: ClassVar[str] = "SessionOpenNetworkStream" 1238 _shape: ClassVar[str] = "named" 1239 addr: str 1240 topic_id: TopicId
1242@dataclass 1243class Request_SessionOpenRepository(Request): 1244 _tag: ClassVar[str] = "SessionOpenRepository" 1245 _shape: ClassVar[str] = "named" 1246 path: str 1247 local_secret: LocalSecret | None
1272@dataclass 1273class Request_SessionSetDefaultQuota(Request): 1274 _tag: ClassVar[str] = "SessionSetDefaultQuota" 1275 _shape: ClassVar[str] = "named" 1276 value: StorageSize | None
1337@dataclass 1338class Request_SessionSubscribeToStateMonitor(Request): 1339 _tag: ClassVar[str] = "SessionSubscribeToStateMonitor" 1340 _shape: ClassVar[str] = "named" 1341 path: list[MonitorId]
1486@dataclass 1487class Response_AccessMode(Response): 1488 _tag: ClassVar[str] = "AccessMode" 1489 _shape: ClassVar[str] = "unnamed" 1490 value: AccessMode
1504@dataclass 1505class Response_Datagram(Response): 1506 _tag: ClassVar[str] = "Datagram" 1507 _shape: ClassVar[str] = "unnamed" 1508 value: Datagram
1510@dataclass 1511class Response_DirectoryEntries(Response): 1512 _tag: ClassVar[str] = "DirectoryEntries" 1513 _shape: ClassVar[str] = "unnamed" 1514 value: list[DirectoryEntry]
1522@dataclass 1523class Response_EntryType(Response): 1524 _tag: ClassVar[str] = "EntryType" 1525 _shape: ClassVar[str] = "unnamed" 1526 value: EntryType
1534@dataclass 1535class Response_NatBehavior(Response): 1536 _tag: ClassVar[str] = "NatBehavior" 1537 _shape: ClassVar[str] = "unnamed" 1538 value: NatBehavior
1540@dataclass 1541class Response_NetworkEvent(Response): 1542 _tag: ClassVar[str] = "NetworkEvent" 1543 _shape: ClassVar[str] = "unnamed" 1544 value: NetworkEvent
1563@dataclass 1564class Response_PasswordSalt(Response): 1565 _tag: ClassVar[str] = "PasswordSalt" 1566 _shape: ClassVar[str] = "unnamed" 1567 value: PasswordSalt
1593@dataclass 1594class Response_PeerInfos(Response): 1595 _tag: ClassVar[str] = "PeerInfos" 1596 _shape: ClassVar[str] = "unnamed" 1597 value: list[PeerInfo]
1599@dataclass 1600class Response_Progress(Response): 1601 _tag: ClassVar[str] = "Progress" 1602 _shape: ClassVar[str] = "unnamed" 1603 value: Progress
1605@dataclass 1606class Response_PublicRuntimeId(Response): 1607 _tag: ClassVar[str] = "PublicRuntimeId" 1608 _shape: ClassVar[str] = "unnamed" 1609 value: PublicRuntimeId
1611@dataclass 1612class Response_QuotaInfo(Response): 1613 _tag: ClassVar[str] = "QuotaInfo" 1614 _shape: ClassVar[str] = "unnamed" 1615 value: QuotaInfo
1629@dataclass 1630class Response_SecretKey(Response): 1631 _tag: ClassVar[str] = "SecretKey" 1632 _shape: ClassVar[str] = "unnamed" 1633 value: SecretKey
1653@dataclass 1654class Response_Stats(Response): 1655 _tag: ClassVar[str] = "Stats" 1656 _shape: ClassVar[str] = "unnamed" 1657 value: Stats
1659@dataclass 1660class Response_StorageSize(Response): 1661 _tag: ClassVar[str] = "StorageSize" 1662 _shape: ClassVar[str] = "unnamed" 1663 value: StorageSize
14@dataclass 15class SecretKey: 16 """ 17 Symmetric encryption/decryption secret key. 18 19 Note: this implementation tries to prevent certain types of attacks by making sure the 20 underlying sensitive key material is always stored at most in one place. This is achieved by 21 putting it on the heap which means it is not moved when the key itself is moved which could 22 otherwise leave a copy of the data in memory. Additionally, the data is behind a `Arc` which 23 means the key can be cheaply cloned without actually cloning the data. Finally, the data is 24 scrambled (overwritten with zeros) when the key is dropped to make sure it does not stay in 25 the memory past its lifetime. 26 """ 27 _shape: ClassVar[str] = "unnamed" 28 value: bytes 29 def __repr__(self) -> str: 30 return f"{type(self).__name__}(******)"
Symmetric encryption/decryption secret key.
Note: this implementation tries to prevent certain types of attacks by making sure the
underlying sensitive key material is always stored at most in one place. This is achieved by
putting it on the heap which means it is not moved when the key itself is moved which could
otherwise leave a copy of the data in memory. Additionally, the data is behind a Arc which
means the key can be cheaply cloned without actually cloning the data. Finally, the data is
scrambled (overwritten with zeros) when the key is dropped to make sure it does not stay in
the memory past its lifetime.
1732class Session: 1733 def __init__(self, client: Client): 1734 """@private""" 1735 self._client = client 1736 1737 async def add_user_provided_peers( 1738 self, 1739 *, 1740 addrs: list[str], 1741 ): 1742 """ 1743 Adds peers to connect to. 1744 1745 Normally peers are discovered automatically (using Bittorrent DHT, Peer exchange or Local 1746 discovery) but this function is useful in case when the discovery is not available for any 1747 reason (e.g. in an isolated network). 1748 1749 Note that peers added with this function are remembered across restarts. To forget peers, 1750 use [Self::session_remove_user_provided_peers]. 1751 """ 1752 request = Request_SessionAddUserProvidedPeers( 1753 addrs, 1754 ) 1755 response = await self._client.invoke(request) 1756 if isinstance(response, Response_Unit): 1757 return 1758 raise UnexpectedResponse() 1759 1760 async def bind_metrics( 1761 self, 1762 *, 1763 addr: str | None = None, 1764 ): 1765 request = Request_SessionBindMetrics( 1766 addr, 1767 ) 1768 response = await self._client.invoke(request) 1769 if isinstance(response, Response_Unit): 1770 return 1771 raise UnexpectedResponse() 1772 1773 async def bind_network( 1774 self, 1775 *, 1776 addrs: list[str], 1777 ): 1778 """ 1779 Binds the network listeners to the specified interfaces. 1780 1781 Up to four listeners can be bound, one for each combination of protocol (TCP or QUIC) and IP 1782 family (IPv4 or IPv6). The format of the interfaces is "PROTO/IP:PORT" where PROTO is "tcp" 1783 or "quic". If IP is IPv6, it needs to be enclosed in square brackets. 1784 1785 If port is `0`, binds to a random port initially but on subsequent starts tries to use the 1786 same port (unless it's already taken). This can be useful to configuring port forwarding. 1787 """ 1788 request = Request_SessionBindNetwork( 1789 addrs, 1790 ) 1791 response = await self._client.invoke(request) 1792 if isinstance(response, Response_Unit): 1793 return 1794 raise UnexpectedResponse() 1795 1796 async def bind_remote_control( 1797 self, 1798 *, 1799 addr: str | None = None, 1800 ) -> int: 1801 request = Request_SessionBindRemoteControl( 1802 addr, 1803 ) 1804 response = await self._client.invoke(request) 1805 if isinstance(response, Response_U16): 1806 return response.value 1807 raise UnexpectedResponse() 1808 1809 async def copy( 1810 self, 1811 *, 1812 src_repo: str | None = None, 1813 src_path: str, 1814 dst_repo: str | None = None, 1815 dst_path: str, 1816 ): 1817 """ 1818 Copy file or directory into, from or between repositories 1819 1820 - `src_repo`: Name of the repository from which file will be copied. 1821 - `src_path`: Path of to the entry to be copied. If `src_repo` is set, the `src_path` is 1822 relative to the corresponding repository root. If `src_repo` is null, `src_path` is 1823 interpreted as path on the local file system. 1824 - `dst_repo`: Name of the repository into which the entry will be copied. 1825 - `dst_path`: Destination entry 1826 """ 1827 request = Request_SessionCopy( 1828 src_repo, 1829 src_path, 1830 dst_repo, 1831 dst_path, 1832 ) 1833 response = await self._client.invoke(request) 1834 if isinstance(response, Response_Unit): 1835 return 1836 raise UnexpectedResponse() 1837 1838 async def create_repository( 1839 self, 1840 *, 1841 path: str, 1842 read_secret: SetLocalSecret | None = None, 1843 write_secret: SetLocalSecret | None = None, 1844 token: str | None = None, 1845 sync_enabled: bool = False, 1846 dht_enabled: bool = False, 1847 pex_enabled: bool = False, 1848 ) -> Repository: 1849 """ 1850 Creates a new repository. 1851 1852 - `path`: path to the repository file or name of the repository. 1853 - `read_secret`: local secret for reading the repository on this device only. Do not share 1854 with peers!. If null, the repo won't be protected and anyone with physical access to the 1855 device will be able to read it. 1856 - `write_secret`: local secret for writing to the repository on this device only. Do not 1857 share with peers! Can be the same as `read_secret` if one wants to use only one secret 1858 for both reading and writing. Separate secrets are useful for plausible deniability. If 1859 both `read_secret` and `write_secret` are `None`, the repo won't be protected and anyone 1860 with physical access to the device will be able to read and write to it. If `read_secret` 1861 is not `None` but `write_secret` is `None`, the repo won't be writable from this device. 1862 - `token`: used to share repositories between devices. If not `None`, this repo will be 1863 linked with the repos with the same token on other devices. See also 1864 [Self::repository_share]. This also determines the maximal access mode the repo can be 1865 opened in. If `None`, it's *write* mode. 1866 """ 1867 request = Request_SessionCreateRepository( 1868 path, 1869 read_secret, 1870 write_secret, 1871 token, 1872 sync_enabled, 1873 dht_enabled, 1874 pex_enabled, 1875 ) 1876 response = await self._client.invoke(request) 1877 if isinstance(response, Response_Repository): 1878 return Repository(self._client, response.value) 1879 raise UnexpectedResponse() 1880 1881 async def delete_repository_by_name( 1882 self, 1883 *, 1884 name: str, 1885 ): 1886 """Delete a repository with the given name.""" 1887 request = Request_SessionDeleteRepositoryByName( 1888 name, 1889 ) 1890 response = await self._client.invoke(request) 1891 if isinstance(response, Response_Unit): 1892 return 1893 raise UnexpectedResponse() 1894 1895 async def derive_secret_key( 1896 self, 1897 *, 1898 password: Password, 1899 salt: PasswordSalt, 1900 ) -> SecretKey: 1901 request = Request_SessionDeriveSecretKey( 1902 password, 1903 salt, 1904 ) 1905 response = await self._client.invoke(request) 1906 if isinstance(response, Response_SecretKey): 1907 return response.value 1908 raise UnexpectedResponse() 1909 1910 async def find_repository( 1911 self, 1912 *, 1913 name: str, 1914 ) -> Repository: 1915 request = Request_SessionFindRepository( 1916 name, 1917 ) 1918 response = await self._client.invoke(request) 1919 if isinstance(response, Response_Repository): 1920 return Repository(self._client, response.value) 1921 raise UnexpectedResponse() 1922 1923 async def generate_password_salt( 1924 self, 1925 ) -> PasswordSalt: 1926 request = Request_SessionGeneratePasswordSalt() 1927 response = await self._client.invoke(request) 1928 if isinstance(response, Response_PasswordSalt): 1929 return response.value 1930 raise UnexpectedResponse() 1931 1932 async def generate_secret_key( 1933 self, 1934 ) -> SecretKey: 1935 request = Request_SessionGenerateSecretKey() 1936 response = await self._client.invoke(request) 1937 if isinstance(response, Response_SecretKey): 1938 return response.value 1939 raise UnexpectedResponse() 1940 1941 async def get_current_protocol_version( 1942 self, 1943 ) -> int: 1944 """ 1945 Returns our Ouisync protocol version. 1946 1947 In order to establish connections with peers, they must use the same protocol version as 1948 us. 1949 1950 See also [Self::session_get_highest_seen_protocol_version] 1951 """ 1952 request = Request_SessionGetCurrentProtocolVersion() 1953 response = await self._client.invoke(request) 1954 if isinstance(response, Response_U64): 1955 return response.value 1956 raise UnexpectedResponse() 1957 1958 async def get_default_block_expiration( 1959 self, 1960 ) -> int | None: 1961 request = Request_SessionGetDefaultBlockExpiration() 1962 response = await self._client.invoke(request) 1963 if isinstance(response, Response_Duration): 1964 return response.value 1965 if isinstance(response, Response_None): 1966 return None 1967 raise UnexpectedResponse() 1968 1969 async def get_default_quota( 1970 self, 1971 ) -> StorageSize | None: 1972 request = Request_SessionGetDefaultQuota() 1973 response = await self._client.invoke(request) 1974 if isinstance(response, Response_StorageSize): 1975 return response.value 1976 if isinstance(response, Response_None): 1977 return None 1978 raise UnexpectedResponse() 1979 1980 async def get_default_repository_expiration( 1981 self, 1982 ) -> int | None: 1983 request = Request_SessionGetDefaultRepositoryExpiration() 1984 response = await self._client.invoke(request) 1985 if isinstance(response, Response_Duration): 1986 return response.value 1987 if isinstance(response, Response_None): 1988 return None 1989 raise UnexpectedResponse() 1990 1991 async def get_dht_routers( 1992 self, 1993 ) -> list[str]: 1994 """ 1995 Returns the current DHT routers (bootstrap nodes). If the routers haven't been changed by 1996 the user yet, returns the default routers. 1997 """ 1998 request = Request_SessionGetDhtRouters() 1999 response = await self._client.invoke(request) 2000 if isinstance(response, Response_Strings): 2001 return response.value 2002 raise UnexpectedResponse() 2003 2004 async def get_external_addr_v4( 2005 self, 2006 ) -> str | None: 2007 request = Request_SessionGetExternalAddrV4() 2008 response = await self._client.invoke(request) 2009 if isinstance(response, Response_SocketAddr): 2010 return response.value 2011 if isinstance(response, Response_None): 2012 return None 2013 raise UnexpectedResponse() 2014 2015 async def get_external_addr_v6( 2016 self, 2017 ) -> str | None: 2018 request = Request_SessionGetExternalAddrV6() 2019 response = await self._client.invoke(request) 2020 if isinstance(response, Response_SocketAddr): 2021 return response.value 2022 if isinstance(response, Response_None): 2023 return None 2024 raise UnexpectedResponse() 2025 2026 async def get_highest_seen_protocol_version( 2027 self, 2028 ) -> int: 2029 """ 2030 Returns the highest protocol version of all known peers. 2031 2032 If this is higher than [our version](Self::session_get_current_protocol_version) it likely 2033 means we are using an outdated version of Ouisync. When a peer with higher protocol version 2034 is found, a [NetworkEvent::ProtocolVersionMismatch] is emitted. 2035 """ 2036 request = Request_SessionGetHighestSeenProtocolVersion() 2037 response = await self._client.invoke(request) 2038 if isinstance(response, Response_U64): 2039 return response.value 2040 raise UnexpectedResponse() 2041 2042 async def get_local_listener_addrs( 2043 self, 2044 ) -> list[str]: 2045 """Returns the listener addresses of this Ouisync instance.""" 2046 request = Request_SessionGetLocalListenerAddrs() 2047 response = await self._client.invoke(request) 2048 if isinstance(response, Response_PeerAddrs): 2049 return response.value 2050 raise UnexpectedResponse() 2051 2052 async def get_metrics_listener_addr( 2053 self, 2054 ) -> str | None: 2055 request = Request_SessionGetMetricsListenerAddr() 2056 response = await self._client.invoke(request) 2057 if isinstance(response, Response_SocketAddr): 2058 return response.value 2059 if isinstance(response, Response_None): 2060 return None 2061 raise UnexpectedResponse() 2062 2063 async def get_mount_root( 2064 self, 2065 ) -> str | None: 2066 request = Request_SessionGetMountRoot() 2067 response = await self._client.invoke(request) 2068 if isinstance(response, Response_Path): 2069 return response.value 2070 if isinstance(response, Response_None): 2071 return None 2072 raise UnexpectedResponse() 2073 2074 async def get_nat_behavior( 2075 self, 2076 ) -> NatBehavior | None: 2077 request = Request_SessionGetNatBehavior() 2078 response = await self._client.invoke(request) 2079 if isinstance(response, Response_NatBehavior): 2080 return response.value 2081 if isinstance(response, Response_None): 2082 return None 2083 raise UnexpectedResponse() 2084 2085 async def get_network_stats( 2086 self, 2087 ) -> Stats: 2088 request = Request_SessionGetNetworkStats() 2089 response = await self._client.invoke(request) 2090 if isinstance(response, Response_Stats): 2091 return response.value 2092 raise UnexpectedResponse() 2093 2094 async def get_peers( 2095 self, 2096 ) -> list[PeerInfo]: 2097 """ 2098 Returns info about all known peers (both discovered and explicitly added). 2099 2100 When the set of known peers changes, a [NetworkEvent::PeerSetChange] is emitted. Calling 2101 this function afterwards returns the new peer info. 2102 """ 2103 request = Request_SessionGetPeers() 2104 response = await self._client.invoke(request) 2105 if isinstance(response, Response_PeerInfos): 2106 return response.value 2107 raise UnexpectedResponse() 2108 2109 async def get_remote_control_listener_addr( 2110 self, 2111 ) -> str | None: 2112 request = Request_SessionGetRemoteControlListenerAddr() 2113 response = await self._client.invoke(request) 2114 if isinstance(response, Response_SocketAddr): 2115 return response.value 2116 if isinstance(response, Response_None): 2117 return None 2118 raise UnexpectedResponse() 2119 2120 async def get_remote_listener_addrs( 2121 self, 2122 *, 2123 host: str, 2124 ) -> list[str]: 2125 """ 2126 Returns the listener addresses of the specified remote Ouisync instance. Works only if the 2127 remote control API is enabled on the remote instance. Typically used with cache servers. 2128 """ 2129 request = Request_SessionGetRemoteListenerAddrs( 2130 host, 2131 ) 2132 response = await self._client.invoke(request) 2133 if isinstance(response, Response_PeerAddrs): 2134 return response.value 2135 raise UnexpectedResponse() 2136 2137 async def get_runtime_id( 2138 self, 2139 ) -> PublicRuntimeId: 2140 """ 2141 Returns the runtime id of this Ouisync instance. 2142 2143 The runtime id is a unique identifier of this instance which is randomly generated every 2144 time Ouisync starts. 2145 """ 2146 request = Request_SessionGetRuntimeId() 2147 response = await self._client.invoke(request) 2148 if isinstance(response, Response_PublicRuntimeId): 2149 return response.value 2150 raise UnexpectedResponse() 2151 2152 async def get_share_token_access_mode( 2153 self, 2154 *, 2155 token: str, 2156 ) -> AccessMode: 2157 """Returns the access mode that the given token grants.""" 2158 request = Request_SessionGetShareTokenAccessMode( 2159 token, 2160 ) 2161 response = await self._client.invoke(request) 2162 if isinstance(response, Response_AccessMode): 2163 return response.value 2164 raise UnexpectedResponse() 2165 2166 async def get_share_token_info_hash( 2167 self, 2168 *, 2169 token: str, 2170 ) -> str: 2171 """ 2172 Return the info-hash of the repository corresponding to the given token, formatted as hex 2173 string. 2174 2175 See also: [repository_get_info_hash] 2176 """ 2177 request = Request_SessionGetShareTokenInfoHash( 2178 token, 2179 ) 2180 response = await self._client.invoke(request) 2181 if isinstance(response, Response_String): 2182 return response.value 2183 raise UnexpectedResponse() 2184 2185 async def get_share_token_suggested_name( 2186 self, 2187 *, 2188 token: str, 2189 ) -> str: 2190 """Returns the suggested name for the repository corresponding to the given token.""" 2191 request = Request_SessionGetShareTokenSuggestedName( 2192 token, 2193 ) 2194 response = await self._client.invoke(request) 2195 if isinstance(response, Response_String): 2196 return response.value 2197 raise UnexpectedResponse() 2198 2199 async def get_state_monitor( 2200 self, 2201 *, 2202 path: list[MonitorId], 2203 ) -> typing.Any | None: 2204 request = Request_SessionGetStateMonitor( 2205 path, 2206 ) 2207 response = await self._client.invoke(request) 2208 if isinstance(response, Response_StateMonitor): 2209 return response.value 2210 if isinstance(response, Response_None): 2211 return None 2212 raise UnexpectedResponse() 2213 2214 async def get_store_dirs( 2215 self, 2216 ) -> list[str]: 2217 request = Request_SessionGetStoreDirs() 2218 response = await self._client.invoke(request) 2219 if isinstance(response, Response_Paths): 2220 return response.value 2221 raise UnexpectedResponse() 2222 2223 async def get_user_provided_peers( 2224 self, 2225 ) -> list[str]: 2226 request = Request_SessionGetUserProvidedPeers() 2227 response = await self._client.invoke(request) 2228 if isinstance(response, Response_PeerAddrs): 2229 return response.value 2230 raise UnexpectedResponse() 2231 2232 async def init_network( 2233 self, 2234 *, 2235 defaults: NetworkDefaults, 2236 ): 2237 """ 2238 Initializes the network according to the stored configuration. If a particular network 2239 parameter is not yet configured, falls back to the given defaults. 2240 """ 2241 request = Request_SessionInitNetwork( 2242 defaults, 2243 ) 2244 response = await self._client.invoke(request) 2245 if isinstance(response, Response_Unit): 2246 return 2247 raise UnexpectedResponse() 2248 2249 async def insert_store_dirs( 2250 self, 2251 *, 2252 paths: list[str], 2253 ): 2254 request = Request_SessionInsertStoreDirs( 2255 paths, 2256 ) 2257 response = await self._client.invoke(request) 2258 if isinstance(response, Response_Unit): 2259 return 2260 raise UnexpectedResponse() 2261 2262 async def is_local_dht_enabled( 2263 self, 2264 ) -> bool: 2265 """Checks whether local DHT is enabled.""" 2266 request = Request_SessionIsLocalDhtEnabled() 2267 response = await self._client.invoke(request) 2268 if isinstance(response, Response_Bool): 2269 return response.value 2270 raise UnexpectedResponse() 2271 2272 async def is_local_discovery_enabled( 2273 self, 2274 ) -> bool: 2275 """Is local discovery enabled?""" 2276 request = Request_SessionIsLocalDiscoveryEnabled() 2277 response = await self._client.invoke(request) 2278 if isinstance(response, Response_Bool): 2279 return response.value 2280 raise UnexpectedResponse() 2281 2282 async def is_pex_recv_enabled( 2283 self, 2284 ) -> bool: 2285 """Checks whether accepting peers discovered on the peer exchange is enabled.""" 2286 request = Request_SessionIsPexRecvEnabled() 2287 response = await self._client.invoke(request) 2288 if isinstance(response, Response_Bool): 2289 return response.value 2290 raise UnexpectedResponse() 2291 2292 async def is_pex_send_enabled( 2293 self, 2294 ) -> bool: 2295 request = Request_SessionIsPexSendEnabled() 2296 response = await self._client.invoke(request) 2297 if isinstance(response, Response_Bool): 2298 return response.value 2299 raise UnexpectedResponse() 2300 2301 async def is_port_forwarding_enabled( 2302 self, 2303 ) -> bool: 2304 """Is port forwarding (UPnP) enabled?""" 2305 request = Request_SessionIsPortForwardingEnabled() 2306 response = await self._client.invoke(request) 2307 if isinstance(response, Response_Bool): 2308 return response.value 2309 raise UnexpectedResponse() 2310 2311 async def list_repositories( 2312 self, 2313 ) -> dict[str, Repository]: 2314 request = Request_SessionListRepositories() 2315 response = await self._client.invoke(request) 2316 if isinstance(response, Response_Repositories): 2317 return {k: Repository(self._client, v) for k, v in response.value.items()} 2318 raise UnexpectedResponse() 2319 2320 async def mirror_exists( 2321 self, 2322 *, 2323 token: str, 2324 host: str, 2325 ) -> bool: 2326 request = Request_SessionMirrorExists( 2327 token, 2328 host, 2329 ) 2330 response = await self._client.invoke(request) 2331 if isinstance(response, Response_Bool): 2332 return response.value 2333 raise UnexpectedResponse() 2334 2335 async def open_network_socket_v4( 2336 self, 2337 ) -> NetworkSocket | None: 2338 """ 2339 Opens a side channel to the underlying IPv4 UDP socket. The side channel is used to 2340 send/receive raw UDP datagrams on the same socket that the sync protocol uses. This is 2341 useful to share the socket between different protocols for hole punching. 2342 2343 Returns `None` if QUIC IPv4 endpoint isn't bound (see [Self::session_bind_network]). 2344 """ 2345 request = Request_SessionOpenNetworkSocketV4() 2346 response = await self._client.invoke(request) 2347 if isinstance(response, Response_NetworkSocket): 2348 return NetworkSocket(self._client, response.value) 2349 if isinstance(response, Response_None): 2350 return None 2351 raise UnexpectedResponse() 2352 2353 async def open_network_socket_v6( 2354 self, 2355 ) -> NetworkSocket | None: 2356 """ 2357 Opens a side channel to the underlying IPv6 UDP socket. The side channel is used to 2358 send/receive raw UDP datagrams on the same socket that the sync protocol uses. This is 2359 useful to share the socket between different protocols for hole punching. 2360 2361 Returns `None` if QUIC IPv6 endpoint isn't bound (see [Self::session_bind_network]). 2362 """ 2363 request = Request_SessionOpenNetworkSocketV6() 2364 response = await self._client.invoke(request) 2365 if isinstance(response, Response_NetworkSocket): 2366 return NetworkSocket(self._client, response.value) 2367 if isinstance(response, Response_None): 2368 return None 2369 raise UnexpectedResponse() 2370 2371 async def open_network_stream( 2372 self, 2373 *, 2374 addr: str, 2375 topic_id: TopicId, 2376 ) -> NetworkStream: 2377 """Opens a raw byte streams to the given peer, bound to the given topic.""" 2378 request = Request_SessionOpenNetworkStream( 2379 addr, 2380 topic_id, 2381 ) 2382 response = await self._client.invoke(request) 2383 if isinstance(response, Response_NetworkStream): 2384 return NetworkStream(self._client, response.value) 2385 raise UnexpectedResponse() 2386 2387 async def open_repository( 2388 self, 2389 *, 2390 path: str, 2391 local_secret: LocalSecret | None = None, 2392 ) -> Repository: 2393 """ 2394 Opens an existing repository. 2395 2396 - `path`: path to the local file the repo is stored in. 2397 - `local_secret`: a local secret. See the `read_secret` and `write_secret` params in 2398 [Self::session_create_repository] for more details. If this repo uses local secret 2399 (s), this determines the access mode the repo is opened in: `read_secret` opens it 2400 in *read* mode, `write_secret` opens it in *write* mode and no secret or wrong secret 2401 opens it in *blind* mode. If this repo doesn't use local secret(s), the repo is opened in 2402 the maximal mode specified when the repo was created. 2403 """ 2404 request = Request_SessionOpenRepository( 2405 path, 2406 local_secret, 2407 ) 2408 response = await self._client.invoke(request) 2409 if isinstance(response, Response_Repository): 2410 return Repository(self._client, response.value) 2411 raise UnexpectedResponse() 2412 2413 async def pin_dht( 2414 self, 2415 ): 2416 """ 2417 Pin the DHT to ensure it starts and remains running even when there are no active DHT 2418 lookups and no DHT-enabled repositories. This is useful to prevent the DHT restarting 2419 between the lookups (which could be slow). 2420 """ 2421 request = Request_SessionPinDht() 2422 response = await self._client.invoke(request) 2423 if isinstance(response, Response_Unit): 2424 return 2425 raise UnexpectedResponse() 2426 2427 async def remove_store_dirs( 2428 self, 2429 *, 2430 paths: list[str], 2431 ): 2432 request = Request_SessionRemoveStoreDirs( 2433 paths, 2434 ) 2435 response = await self._client.invoke(request) 2436 if isinstance(response, Response_Unit): 2437 return 2438 raise UnexpectedResponse() 2439 2440 async def remove_user_provided_peers( 2441 self, 2442 *, 2443 addrs: list[str], 2444 ): 2445 """Removes peers previously added with [Self::session_add_user_provided_peers].""" 2446 request = Request_SessionRemoveUserProvidedPeers( 2447 addrs, 2448 ) 2449 response = await self._client.invoke(request) 2450 if isinstance(response, Response_Unit): 2451 return 2452 raise UnexpectedResponse() 2453 2454 async def set_default_block_expiration( 2455 self, 2456 *, 2457 value: int | None = None, 2458 ): 2459 request = Request_SessionSetDefaultBlockExpiration( 2460 value, 2461 ) 2462 response = await self._client.invoke(request) 2463 if isinstance(response, Response_Unit): 2464 return 2465 raise UnexpectedResponse() 2466 2467 async def set_default_quota( 2468 self, 2469 *, 2470 value: StorageSize | None = None, 2471 ): 2472 request = Request_SessionSetDefaultQuota( 2473 value, 2474 ) 2475 response = await self._client.invoke(request) 2476 if isinstance(response, Response_Unit): 2477 return 2478 raise UnexpectedResponse() 2479 2480 async def set_default_repository_expiration( 2481 self, 2482 *, 2483 value: int | None = None, 2484 ): 2485 request = Request_SessionSetDefaultRepositoryExpiration( 2486 value, 2487 ) 2488 response = await self._client.invoke(request) 2489 if isinstance(response, Response_Unit): 2490 return 2491 raise UnexpectedResponse() 2492 2493 async def set_dht_routers( 2494 self, 2495 *, 2496 routers: list[str], 2497 ): 2498 """ 2499 Changes the DHT routers (bootstrap nodes), rebootstraps the DHTs and restart any ongoing 2500 lookups. If this is not called, a default set of routers is used. Each router is specified 2501 as hostname + port or ip address + port. 2502 """ 2503 request = Request_SessionSetDhtRouters( 2504 routers, 2505 ) 2506 response = await self._client.invoke(request) 2507 if isinstance(response, Response_Unit): 2508 return 2509 raise UnexpectedResponse() 2510 2511 async def set_local_dht_enabled( 2512 self, 2513 *, 2514 enabled: bool = False, 2515 ): 2516 """ 2517 Set whether DHT on the local network or localhost is allowed. By default this is `false` 2518 because DHT is a global discovery mechanism and finding a local peer on it is unexpected 2519 (and could indicate malice). However, is some situations it's still useful to enable it 2520 (typically for testing). 2521 2522 Note: this option is currently experimental and unstable (semver extempt). It's possible it 2523 will be removed in the future. 2524 """ 2525 request = Request_SessionSetLocalDhtEnabled( 2526 enabled, 2527 ) 2528 response = await self._client.invoke(request) 2529 if isinstance(response, Response_Unit): 2530 return 2531 raise UnexpectedResponse() 2532 2533 async def set_local_discovery_enabled( 2534 self, 2535 *, 2536 enabled: bool = False, 2537 ): 2538 """Enables/disables local discovery.""" 2539 request = Request_SessionSetLocalDiscoveryEnabled( 2540 enabled, 2541 ) 2542 response = await self._client.invoke(request) 2543 if isinstance(response, Response_Unit): 2544 return 2545 raise UnexpectedResponse() 2546 2547 async def set_mount_root( 2548 self, 2549 *, 2550 path: str | None = None, 2551 ): 2552 request = Request_SessionSetMountRoot( 2553 path, 2554 ) 2555 response = await self._client.invoke(request) 2556 if isinstance(response, Response_Unit): 2557 return 2558 raise UnexpectedResponse() 2559 2560 async def set_pex_recv_enabled( 2561 self, 2562 *, 2563 enabled: bool = False, 2564 ): 2565 request = Request_SessionSetPexRecvEnabled( 2566 enabled, 2567 ) 2568 response = await self._client.invoke(request) 2569 if isinstance(response, Response_Unit): 2570 return 2571 raise UnexpectedResponse() 2572 2573 async def set_pex_send_enabled( 2574 self, 2575 *, 2576 enabled: bool = False, 2577 ): 2578 request = Request_SessionSetPexSendEnabled( 2579 enabled, 2580 ) 2581 response = await self._client.invoke(request) 2582 if isinstance(response, Response_Unit): 2583 return 2584 raise UnexpectedResponse() 2585 2586 async def set_port_forwarding_enabled( 2587 self, 2588 *, 2589 enabled: bool = False, 2590 ): 2591 """Enables/disables port forwarding (UPnP).""" 2592 request = Request_SessionSetPortForwardingEnabled( 2593 enabled, 2594 ) 2595 response = await self._client.invoke(request) 2596 if isinstance(response, Response_Unit): 2597 return 2598 raise UnexpectedResponse() 2599 2600 async def set_store_dirs( 2601 self, 2602 *, 2603 paths: list[str], 2604 ): 2605 request = Request_SessionSetStoreDirs( 2606 paths, 2607 ) 2608 response = await self._client.invoke(request) 2609 if isinstance(response, Response_Unit): 2610 return 2611 raise UnexpectedResponse() 2612 2613 async def unpin_dht( 2614 self, 2615 ): 2616 """ 2617 Unpin the DHT. If the DHT is not pinned and there are no more active DHT lookups and no 2618 DHT-enabled repositories, the DHT shuts down. 2619 """ 2620 request = Request_SessionUnpinDht() 2621 response = await self._client.invoke(request) 2622 if isinstance(response, Response_Unit): 2623 return 2624 raise UnexpectedResponse() 2625 2626 async def validate_share_token( 2627 self, 2628 *, 2629 token: str, 2630 ) -> str: 2631 """Checks whether the given string is a valid share token.""" 2632 request = Request_SessionValidateShareToken( 2633 token, 2634 ) 2635 response = await self._client.invoke(request) 2636 if isinstance(response, Response_ShareToken): 2637 return response.value 2638 raise UnexpectedResponse()
1737 async def add_user_provided_peers( 1738 self, 1739 *, 1740 addrs: list[str], 1741 ): 1742 """ 1743 Adds peers to connect to. 1744 1745 Normally peers are discovered automatically (using Bittorrent DHT, Peer exchange or Local 1746 discovery) but this function is useful in case when the discovery is not available for any 1747 reason (e.g. in an isolated network). 1748 1749 Note that peers added with this function are remembered across restarts. To forget peers, 1750 use [Self::session_remove_user_provided_peers]. 1751 """ 1752 request = Request_SessionAddUserProvidedPeers( 1753 addrs, 1754 ) 1755 response = await self._client.invoke(request) 1756 if isinstance(response, Response_Unit): 1757 return 1758 raise UnexpectedResponse()
Adds peers to connect to.
Normally peers are discovered automatically (using Bittorrent DHT, Peer exchange or Local discovery) but this function is useful in case when the discovery is not available for any reason (e.g. in an isolated network).
Note that peers added with this function are remembered across restarts. To forget peers, use [Self::session_remove_user_provided_peers].
1773 async def bind_network( 1774 self, 1775 *, 1776 addrs: list[str], 1777 ): 1778 """ 1779 Binds the network listeners to the specified interfaces. 1780 1781 Up to four listeners can be bound, one for each combination of protocol (TCP or QUIC) and IP 1782 family (IPv4 or IPv6). The format of the interfaces is "PROTO/IP:PORT" where PROTO is "tcp" 1783 or "quic". If IP is IPv6, it needs to be enclosed in square brackets. 1784 1785 If port is `0`, binds to a random port initially but on subsequent starts tries to use the 1786 same port (unless it's already taken). This can be useful to configuring port forwarding. 1787 """ 1788 request = Request_SessionBindNetwork( 1789 addrs, 1790 ) 1791 response = await self._client.invoke(request) 1792 if isinstance(response, Response_Unit): 1793 return 1794 raise UnexpectedResponse()
Binds the network listeners to the specified interfaces.
Up to four listeners can be bound, one for each combination of protocol (TCP or QUIC) and IP family (IPv4 or IPv6). The format of the interfaces is "PROTO/IP:PORT" where PROTO is "tcp" or "quic". If IP is IPv6, it needs to be enclosed in square brackets.
If port is 0, binds to a random port initially but on subsequent starts tries to use the
same port (unless it's already taken). This can be useful to configuring port forwarding.
1796 async def bind_remote_control( 1797 self, 1798 *, 1799 addr: str | None = None, 1800 ) -> int: 1801 request = Request_SessionBindRemoteControl( 1802 addr, 1803 ) 1804 response = await self._client.invoke(request) 1805 if isinstance(response, Response_U16): 1806 return response.value 1807 raise UnexpectedResponse()
1809 async def copy( 1810 self, 1811 *, 1812 src_repo: str | None = None, 1813 src_path: str, 1814 dst_repo: str | None = None, 1815 dst_path: str, 1816 ): 1817 """ 1818 Copy file or directory into, from or between repositories 1819 1820 - `src_repo`: Name of the repository from which file will be copied. 1821 - `src_path`: Path of to the entry to be copied. If `src_repo` is set, the `src_path` is 1822 relative to the corresponding repository root. If `src_repo` is null, `src_path` is 1823 interpreted as path on the local file system. 1824 - `dst_repo`: Name of the repository into which the entry will be copied. 1825 - `dst_path`: Destination entry 1826 """ 1827 request = Request_SessionCopy( 1828 src_repo, 1829 src_path, 1830 dst_repo, 1831 dst_path, 1832 ) 1833 response = await self._client.invoke(request) 1834 if isinstance(response, Response_Unit): 1835 return 1836 raise UnexpectedResponse()
Copy file or directory into, from or between repositories
src_repo: Name of the repository from which file will be copied.src_path: Path of to the entry to be copied. Ifsrc_repois set, thesrc_pathis relative to the corresponding repository root. Ifsrc_repois null,src_pathis interpreted as path on the local file system.dst_repo: Name of the repository into which the entry will be copied.dst_path: Destination entry
1838 async def create_repository( 1839 self, 1840 *, 1841 path: str, 1842 read_secret: SetLocalSecret | None = None, 1843 write_secret: SetLocalSecret | None = None, 1844 token: str | None = None, 1845 sync_enabled: bool = False, 1846 dht_enabled: bool = False, 1847 pex_enabled: bool = False, 1848 ) -> Repository: 1849 """ 1850 Creates a new repository. 1851 1852 - `path`: path to the repository file or name of the repository. 1853 - `read_secret`: local secret for reading the repository on this device only. Do not share 1854 with peers!. If null, the repo won't be protected and anyone with physical access to the 1855 device will be able to read it. 1856 - `write_secret`: local secret for writing to the repository on this device only. Do not 1857 share with peers! Can be the same as `read_secret` if one wants to use only one secret 1858 for both reading and writing. Separate secrets are useful for plausible deniability. If 1859 both `read_secret` and `write_secret` are `None`, the repo won't be protected and anyone 1860 with physical access to the device will be able to read and write to it. If `read_secret` 1861 is not `None` but `write_secret` is `None`, the repo won't be writable from this device. 1862 - `token`: used to share repositories between devices. If not `None`, this repo will be 1863 linked with the repos with the same token on other devices. See also 1864 [Self::repository_share]. This also determines the maximal access mode the repo can be 1865 opened in. If `None`, it's *write* mode. 1866 """ 1867 request = Request_SessionCreateRepository( 1868 path, 1869 read_secret, 1870 write_secret, 1871 token, 1872 sync_enabled, 1873 dht_enabled, 1874 pex_enabled, 1875 ) 1876 response = await self._client.invoke(request) 1877 if isinstance(response, Response_Repository): 1878 return Repository(self._client, response.value) 1879 raise UnexpectedResponse()
Creates a new repository.
path: path to the repository file or name of the repository.read_secret: local secret for reading the repository on this device only. Do not share with peers!. If null, the repo won't be protected and anyone with physical access to the device will be able to read it.write_secret: local secret for writing to the repository on this device only. Do not share with peers! Can be the same asread_secretif one wants to use only one secret for both reading and writing. Separate secrets are useful for plausible deniability. If bothread_secretandwrite_secretareNone, the repo won't be protected and anyone with physical access to the device will be able to read and write to it. Ifread_secretis notNonebutwrite_secretisNone, the repo won't be writable from this device.token: used to share repositories between devices. If notNone, this repo will be linked with the repos with the same token on other devices. See also [Self::repository_share]. This also determines the maximal access mode the repo can be opened in. IfNone, it's write mode.
1881 async def delete_repository_by_name( 1882 self, 1883 *, 1884 name: str, 1885 ): 1886 """Delete a repository with the given name.""" 1887 request = Request_SessionDeleteRepositoryByName( 1888 name, 1889 ) 1890 response = await self._client.invoke(request) 1891 if isinstance(response, Response_Unit): 1892 return 1893 raise UnexpectedResponse()
Delete a repository with the given name.
1895 async def derive_secret_key( 1896 self, 1897 *, 1898 password: Password, 1899 salt: PasswordSalt, 1900 ) -> SecretKey: 1901 request = Request_SessionDeriveSecretKey( 1902 password, 1903 salt, 1904 ) 1905 response = await self._client.invoke(request) 1906 if isinstance(response, Response_SecretKey): 1907 return response.value 1908 raise UnexpectedResponse()
1910 async def find_repository( 1911 self, 1912 *, 1913 name: str, 1914 ) -> Repository: 1915 request = Request_SessionFindRepository( 1916 name, 1917 ) 1918 response = await self._client.invoke(request) 1919 if isinstance(response, Response_Repository): 1920 return Repository(self._client, response.value) 1921 raise UnexpectedResponse()
1941 async def get_current_protocol_version( 1942 self, 1943 ) -> int: 1944 """ 1945 Returns our Ouisync protocol version. 1946 1947 In order to establish connections with peers, they must use the same protocol version as 1948 us. 1949 1950 See also [Self::session_get_highest_seen_protocol_version] 1951 """ 1952 request = Request_SessionGetCurrentProtocolVersion() 1953 response = await self._client.invoke(request) 1954 if isinstance(response, Response_U64): 1955 return response.value 1956 raise UnexpectedResponse()
Returns our Ouisync protocol version.
In order to establish connections with peers, they must use the same protocol version as us.
See also [Self::session_get_highest_seen_protocol_version]
1958 async def get_default_block_expiration( 1959 self, 1960 ) -> int | None: 1961 request = Request_SessionGetDefaultBlockExpiration() 1962 response = await self._client.invoke(request) 1963 if isinstance(response, Response_Duration): 1964 return response.value 1965 if isinstance(response, Response_None): 1966 return None 1967 raise UnexpectedResponse()
1969 async def get_default_quota( 1970 self, 1971 ) -> StorageSize | None: 1972 request = Request_SessionGetDefaultQuota() 1973 response = await self._client.invoke(request) 1974 if isinstance(response, Response_StorageSize): 1975 return response.value 1976 if isinstance(response, Response_None): 1977 return None 1978 raise UnexpectedResponse()
1980 async def get_default_repository_expiration( 1981 self, 1982 ) -> int | None: 1983 request = Request_SessionGetDefaultRepositoryExpiration() 1984 response = await self._client.invoke(request) 1985 if isinstance(response, Response_Duration): 1986 return response.value 1987 if isinstance(response, Response_None): 1988 return None 1989 raise UnexpectedResponse()
1991 async def get_dht_routers( 1992 self, 1993 ) -> list[str]: 1994 """ 1995 Returns the current DHT routers (bootstrap nodes). If the routers haven't been changed by 1996 the user yet, returns the default routers. 1997 """ 1998 request = Request_SessionGetDhtRouters() 1999 response = await self._client.invoke(request) 2000 if isinstance(response, Response_Strings): 2001 return response.value 2002 raise UnexpectedResponse()
Returns the current DHT routers (bootstrap nodes). If the routers haven't been changed by the user yet, returns the default routers.
2004 async def get_external_addr_v4( 2005 self, 2006 ) -> str | None: 2007 request = Request_SessionGetExternalAddrV4() 2008 response = await self._client.invoke(request) 2009 if isinstance(response, Response_SocketAddr): 2010 return response.value 2011 if isinstance(response, Response_None): 2012 return None 2013 raise UnexpectedResponse()
2015 async def get_external_addr_v6( 2016 self, 2017 ) -> str | None: 2018 request = Request_SessionGetExternalAddrV6() 2019 response = await self._client.invoke(request) 2020 if isinstance(response, Response_SocketAddr): 2021 return response.value 2022 if isinstance(response, Response_None): 2023 return None 2024 raise UnexpectedResponse()
2026 async def get_highest_seen_protocol_version( 2027 self, 2028 ) -> int: 2029 """ 2030 Returns the highest protocol version of all known peers. 2031 2032 If this is higher than [our version](Self::session_get_current_protocol_version) it likely 2033 means we are using an outdated version of Ouisync. When a peer with higher protocol version 2034 is found, a [NetworkEvent::ProtocolVersionMismatch] is emitted. 2035 """ 2036 request = Request_SessionGetHighestSeenProtocolVersion() 2037 response = await self._client.invoke(request) 2038 if isinstance(response, Response_U64): 2039 return response.value 2040 raise UnexpectedResponse()
Returns the highest protocol version of all known peers.
If this is higher than our version it likely means we are using an outdated version of Ouisync. When a peer with higher protocol version is found, a [NetworkEvent::ProtocolVersionMismatch] is emitted.
2042 async def get_local_listener_addrs( 2043 self, 2044 ) -> list[str]: 2045 """Returns the listener addresses of this Ouisync instance.""" 2046 request = Request_SessionGetLocalListenerAddrs() 2047 response = await self._client.invoke(request) 2048 if isinstance(response, Response_PeerAddrs): 2049 return response.value 2050 raise UnexpectedResponse()
Returns the listener addresses of this Ouisync instance.
2052 async def get_metrics_listener_addr( 2053 self, 2054 ) -> str | None: 2055 request = Request_SessionGetMetricsListenerAddr() 2056 response = await self._client.invoke(request) 2057 if isinstance(response, Response_SocketAddr): 2058 return response.value 2059 if isinstance(response, Response_None): 2060 return None 2061 raise UnexpectedResponse()
2063 async def get_mount_root( 2064 self, 2065 ) -> str | None: 2066 request = Request_SessionGetMountRoot() 2067 response = await self._client.invoke(request) 2068 if isinstance(response, Response_Path): 2069 return response.value 2070 if isinstance(response, Response_None): 2071 return None 2072 raise UnexpectedResponse()
2074 async def get_nat_behavior( 2075 self, 2076 ) -> NatBehavior | None: 2077 request = Request_SessionGetNatBehavior() 2078 response = await self._client.invoke(request) 2079 if isinstance(response, Response_NatBehavior): 2080 return response.value 2081 if isinstance(response, Response_None): 2082 return None 2083 raise UnexpectedResponse()
2094 async def get_peers( 2095 self, 2096 ) -> list[PeerInfo]: 2097 """ 2098 Returns info about all known peers (both discovered and explicitly added). 2099 2100 When the set of known peers changes, a [NetworkEvent::PeerSetChange] is emitted. Calling 2101 this function afterwards returns the new peer info. 2102 """ 2103 request = Request_SessionGetPeers() 2104 response = await self._client.invoke(request) 2105 if isinstance(response, Response_PeerInfos): 2106 return response.value 2107 raise UnexpectedResponse()
Returns info about all known peers (both discovered and explicitly added).
When the set of known peers changes, a [NetworkEvent::PeerSetChange] is emitted. Calling this function afterwards returns the new peer info.
2109 async def get_remote_control_listener_addr( 2110 self, 2111 ) -> str | None: 2112 request = Request_SessionGetRemoteControlListenerAddr() 2113 response = await self._client.invoke(request) 2114 if isinstance(response, Response_SocketAddr): 2115 return response.value 2116 if isinstance(response, Response_None): 2117 return None 2118 raise UnexpectedResponse()
2120 async def get_remote_listener_addrs( 2121 self, 2122 *, 2123 host: str, 2124 ) -> list[str]: 2125 """ 2126 Returns the listener addresses of the specified remote Ouisync instance. Works only if the 2127 remote control API is enabled on the remote instance. Typically used with cache servers. 2128 """ 2129 request = Request_SessionGetRemoteListenerAddrs( 2130 host, 2131 ) 2132 response = await self._client.invoke(request) 2133 if isinstance(response, Response_PeerAddrs): 2134 return response.value 2135 raise UnexpectedResponse()
Returns the listener addresses of the specified remote Ouisync instance. Works only if the remote control API is enabled on the remote instance. Typically used with cache servers.
2137 async def get_runtime_id( 2138 self, 2139 ) -> PublicRuntimeId: 2140 """ 2141 Returns the runtime id of this Ouisync instance. 2142 2143 The runtime id is a unique identifier of this instance which is randomly generated every 2144 time Ouisync starts. 2145 """ 2146 request = Request_SessionGetRuntimeId() 2147 response = await self._client.invoke(request) 2148 if isinstance(response, Response_PublicRuntimeId): 2149 return response.value 2150 raise UnexpectedResponse()
Returns the runtime id of this Ouisync instance.
The runtime id is a unique identifier of this instance which is randomly generated every time Ouisync starts.
2199 async def get_state_monitor( 2200 self, 2201 *, 2202 path: list[MonitorId], 2203 ) -> typing.Any | None: 2204 request = Request_SessionGetStateMonitor( 2205 path, 2206 ) 2207 response = await self._client.invoke(request) 2208 if isinstance(response, Response_StateMonitor): 2209 return response.value 2210 if isinstance(response, Response_None): 2211 return None 2212 raise UnexpectedResponse()
2232 async def init_network( 2233 self, 2234 *, 2235 defaults: NetworkDefaults, 2236 ): 2237 """ 2238 Initializes the network according to the stored configuration. If a particular network 2239 parameter is not yet configured, falls back to the given defaults. 2240 """ 2241 request = Request_SessionInitNetwork( 2242 defaults, 2243 ) 2244 response = await self._client.invoke(request) 2245 if isinstance(response, Response_Unit): 2246 return 2247 raise UnexpectedResponse()
Initializes the network according to the stored configuration. If a particular network parameter is not yet configured, falls back to the given defaults.
2262 async def is_local_dht_enabled( 2263 self, 2264 ) -> bool: 2265 """Checks whether local DHT is enabled.""" 2266 request = Request_SessionIsLocalDhtEnabled() 2267 response = await self._client.invoke(request) 2268 if isinstance(response, Response_Bool): 2269 return response.value 2270 raise UnexpectedResponse()
Checks whether local DHT is enabled.
2272 async def is_local_discovery_enabled( 2273 self, 2274 ) -> bool: 2275 """Is local discovery enabled?""" 2276 request = Request_SessionIsLocalDiscoveryEnabled() 2277 response = await self._client.invoke(request) 2278 if isinstance(response, Response_Bool): 2279 return response.value 2280 raise UnexpectedResponse()
Is local discovery enabled?
2282 async def is_pex_recv_enabled( 2283 self, 2284 ) -> bool: 2285 """Checks whether accepting peers discovered on the peer exchange is enabled.""" 2286 request = Request_SessionIsPexRecvEnabled() 2287 response = await self._client.invoke(request) 2288 if isinstance(response, Response_Bool): 2289 return response.value 2290 raise UnexpectedResponse()
Checks whether accepting peers discovered on the peer exchange is enabled.
2301 async def is_port_forwarding_enabled( 2302 self, 2303 ) -> bool: 2304 """Is port forwarding (UPnP) enabled?""" 2305 request = Request_SessionIsPortForwardingEnabled() 2306 response = await self._client.invoke(request) 2307 if isinstance(response, Response_Bool): 2308 return response.value 2309 raise UnexpectedResponse()
Is port forwarding (UPnP) enabled?
2311 async def list_repositories( 2312 self, 2313 ) -> dict[str, Repository]: 2314 request = Request_SessionListRepositories() 2315 response = await self._client.invoke(request) 2316 if isinstance(response, Response_Repositories): 2317 return {k: Repository(self._client, v) for k, v in response.value.items()} 2318 raise UnexpectedResponse()
2320 async def mirror_exists( 2321 self, 2322 *, 2323 token: str, 2324 host: str, 2325 ) -> bool: 2326 request = Request_SessionMirrorExists( 2327 token, 2328 host, 2329 ) 2330 response = await self._client.invoke(request) 2331 if isinstance(response, Response_Bool): 2332 return response.value 2333 raise UnexpectedResponse()
2335 async def open_network_socket_v4( 2336 self, 2337 ) -> NetworkSocket | None: 2338 """ 2339 Opens a side channel to the underlying IPv4 UDP socket. The side channel is used to 2340 send/receive raw UDP datagrams on the same socket that the sync protocol uses. This is 2341 useful to share the socket between different protocols for hole punching. 2342 2343 Returns `None` if QUIC IPv4 endpoint isn't bound (see [Self::session_bind_network]). 2344 """ 2345 request = Request_SessionOpenNetworkSocketV4() 2346 response = await self._client.invoke(request) 2347 if isinstance(response, Response_NetworkSocket): 2348 return NetworkSocket(self._client, response.value) 2349 if isinstance(response, Response_None): 2350 return None 2351 raise UnexpectedResponse()
Opens a side channel to the underlying IPv4 UDP socket. The side channel is used to send/receive raw UDP datagrams on the same socket that the sync protocol uses. This is useful to share the socket between different protocols for hole punching.
Returns None if QUIC IPv4 endpoint isn't bound (see [Self::session_bind_network]).
2353 async def open_network_socket_v6( 2354 self, 2355 ) -> NetworkSocket | None: 2356 """ 2357 Opens a side channel to the underlying IPv6 UDP socket. The side channel is used to 2358 send/receive raw UDP datagrams on the same socket that the sync protocol uses. This is 2359 useful to share the socket between different protocols for hole punching. 2360 2361 Returns `None` if QUIC IPv6 endpoint isn't bound (see [Self::session_bind_network]). 2362 """ 2363 request = Request_SessionOpenNetworkSocketV6() 2364 response = await self._client.invoke(request) 2365 if isinstance(response, Response_NetworkSocket): 2366 return NetworkSocket(self._client, response.value) 2367 if isinstance(response, Response_None): 2368 return None 2369 raise UnexpectedResponse()
Opens a side channel to the underlying IPv6 UDP socket. The side channel is used to send/receive raw UDP datagrams on the same socket that the sync protocol uses. This is useful to share the socket between different protocols for hole punching.
Returns None if QUIC IPv6 endpoint isn't bound (see [Self::session_bind_network]).
2371 async def open_network_stream( 2372 self, 2373 *, 2374 addr: str, 2375 topic_id: TopicId, 2376 ) -> NetworkStream: 2377 """Opens a raw byte streams to the given peer, bound to the given topic.""" 2378 request = Request_SessionOpenNetworkStream( 2379 addr, 2380 topic_id, 2381 ) 2382 response = await self._client.invoke(request) 2383 if isinstance(response, Response_NetworkStream): 2384 return NetworkStream(self._client, response.value) 2385 raise UnexpectedResponse()
Opens a raw byte streams to the given peer, bound to the given topic.
2387 async def open_repository( 2388 self, 2389 *, 2390 path: str, 2391 local_secret: LocalSecret | None = None, 2392 ) -> Repository: 2393 """ 2394 Opens an existing repository. 2395 2396 - `path`: path to the local file the repo is stored in. 2397 - `local_secret`: a local secret. See the `read_secret` and `write_secret` params in 2398 [Self::session_create_repository] for more details. If this repo uses local secret 2399 (s), this determines the access mode the repo is opened in: `read_secret` opens it 2400 in *read* mode, `write_secret` opens it in *write* mode and no secret or wrong secret 2401 opens it in *blind* mode. If this repo doesn't use local secret(s), the repo is opened in 2402 the maximal mode specified when the repo was created. 2403 """ 2404 request = Request_SessionOpenRepository( 2405 path, 2406 local_secret, 2407 ) 2408 response = await self._client.invoke(request) 2409 if isinstance(response, Response_Repository): 2410 return Repository(self._client, response.value) 2411 raise UnexpectedResponse()
Opens an existing repository.
path: path to the local file the repo is stored in.local_secret: a local secret. See theread_secretandwrite_secretparams in [Self::session_create_repository] for more details. If this repo uses local secret (s), this determines the access mode the repo is opened in:read_secretopens it in read mode,write_secretopens it in write mode and no secret or wrong secret opens it in blind mode. If this repo doesn't use local secret(s), the repo is opened in the maximal mode specified when the repo was created.
2413 async def pin_dht( 2414 self, 2415 ): 2416 """ 2417 Pin the DHT to ensure it starts and remains running even when there are no active DHT 2418 lookups and no DHT-enabled repositories. This is useful to prevent the DHT restarting 2419 between the lookups (which could be slow). 2420 """ 2421 request = Request_SessionPinDht() 2422 response = await self._client.invoke(request) 2423 if isinstance(response, Response_Unit): 2424 return 2425 raise UnexpectedResponse()
Pin the DHT to ensure it starts and remains running even when there are no active DHT lookups and no DHT-enabled repositories. This is useful to prevent the DHT restarting between the lookups (which could be slow).
2440 async def remove_user_provided_peers( 2441 self, 2442 *, 2443 addrs: list[str], 2444 ): 2445 """Removes peers previously added with [Self::session_add_user_provided_peers].""" 2446 request = Request_SessionRemoveUserProvidedPeers( 2447 addrs, 2448 ) 2449 response = await self._client.invoke(request) 2450 if isinstance(response, Response_Unit): 2451 return 2452 raise UnexpectedResponse()
Removes peers previously added with [Self::session_add_user_provided_peers].
2454 async def set_default_block_expiration( 2455 self, 2456 *, 2457 value: int | None = None, 2458 ): 2459 request = Request_SessionSetDefaultBlockExpiration( 2460 value, 2461 ) 2462 response = await self._client.invoke(request) 2463 if isinstance(response, Response_Unit): 2464 return 2465 raise UnexpectedResponse()
2467 async def set_default_quota( 2468 self, 2469 *, 2470 value: StorageSize | None = None, 2471 ): 2472 request = Request_SessionSetDefaultQuota( 2473 value, 2474 ) 2475 response = await self._client.invoke(request) 2476 if isinstance(response, Response_Unit): 2477 return 2478 raise UnexpectedResponse()
2480 async def set_default_repository_expiration( 2481 self, 2482 *, 2483 value: int | None = None, 2484 ): 2485 request = Request_SessionSetDefaultRepositoryExpiration( 2486 value, 2487 ) 2488 response = await self._client.invoke(request) 2489 if isinstance(response, Response_Unit): 2490 return 2491 raise UnexpectedResponse()
2493 async def set_dht_routers( 2494 self, 2495 *, 2496 routers: list[str], 2497 ): 2498 """ 2499 Changes the DHT routers (bootstrap nodes), rebootstraps the DHTs and restart any ongoing 2500 lookups. If this is not called, a default set of routers is used. Each router is specified 2501 as hostname + port or ip address + port. 2502 """ 2503 request = Request_SessionSetDhtRouters( 2504 routers, 2505 ) 2506 response = await self._client.invoke(request) 2507 if isinstance(response, Response_Unit): 2508 return 2509 raise UnexpectedResponse()
Changes the DHT routers (bootstrap nodes), rebootstraps the DHTs and restart any ongoing lookups. If this is not called, a default set of routers is used. Each router is specified as hostname + port or ip address + port.
2511 async def set_local_dht_enabled( 2512 self, 2513 *, 2514 enabled: bool = False, 2515 ): 2516 """ 2517 Set whether DHT on the local network or localhost is allowed. By default this is `false` 2518 because DHT is a global discovery mechanism and finding a local peer on it is unexpected 2519 (and could indicate malice). However, is some situations it's still useful to enable it 2520 (typically for testing). 2521 2522 Note: this option is currently experimental and unstable (semver extempt). It's possible it 2523 will be removed in the future. 2524 """ 2525 request = Request_SessionSetLocalDhtEnabled( 2526 enabled, 2527 ) 2528 response = await self._client.invoke(request) 2529 if isinstance(response, Response_Unit): 2530 return 2531 raise UnexpectedResponse()
Set whether DHT on the local network or localhost is allowed. By default this is false
because DHT is a global discovery mechanism and finding a local peer on it is unexpected
(and could indicate malice). However, is some situations it's still useful to enable it
(typically for testing).
Note: this option is currently experimental and unstable (semver extempt). It's possible it will be removed in the future.
2533 async def set_local_discovery_enabled( 2534 self, 2535 *, 2536 enabled: bool = False, 2537 ): 2538 """Enables/disables local discovery.""" 2539 request = Request_SessionSetLocalDiscoveryEnabled( 2540 enabled, 2541 ) 2542 response = await self._client.invoke(request) 2543 if isinstance(response, Response_Unit): 2544 return 2545 raise UnexpectedResponse()
Enables/disables local discovery.
2560 async def set_pex_recv_enabled( 2561 self, 2562 *, 2563 enabled: bool = False, 2564 ): 2565 request = Request_SessionSetPexRecvEnabled( 2566 enabled, 2567 ) 2568 response = await self._client.invoke(request) 2569 if isinstance(response, Response_Unit): 2570 return 2571 raise UnexpectedResponse()
2573 async def set_pex_send_enabled( 2574 self, 2575 *, 2576 enabled: bool = False, 2577 ): 2578 request = Request_SessionSetPexSendEnabled( 2579 enabled, 2580 ) 2581 response = await self._client.invoke(request) 2582 if isinstance(response, Response_Unit): 2583 return 2584 raise UnexpectedResponse()
2586 async def set_port_forwarding_enabled( 2587 self, 2588 *, 2589 enabled: bool = False, 2590 ): 2591 """Enables/disables port forwarding (UPnP).""" 2592 request = Request_SessionSetPortForwardingEnabled( 2593 enabled, 2594 ) 2595 response = await self._client.invoke(request) 2596 if isinstance(response, Response_Unit): 2597 return 2598 raise UnexpectedResponse()
Enables/disables port forwarding (UPnP).
2613 async def unpin_dht( 2614 self, 2615 ): 2616 """ 2617 Unpin the DHT. If the DHT is not pinned and there are no more active DHT lookups and no 2618 DHT-enabled repositories, the DHT shuts down. 2619 """ 2620 request = Request_SessionUnpinDht() 2621 response = await self._client.invoke(request) 2622 if isinstance(response, Response_Unit): 2623 return 2624 raise UnexpectedResponse()
Unpin the DHT. If the DHT is not pinned and there are no more active DHT lookups and no DHT-enabled repositories, the DHT shuts down.
86class SetLocalSecret: 87 """Used to set or change the read or write local secret of a repository.""" 88 _variants: ClassVar[dict[str, type]] = {}
Used to set or change the read or write local secret of a repository.
97@dataclass 98class SetLocalSecret_KeyAndSalt(SetLocalSecret): 99 """ 100 Use to directly (without doing password hashing) set the `SecretKey` and `PasswordSalt` for 101 read or write access. 102 """ 103 _tag: ClassVar[str] = "KeyAndSalt" 104 _shape: ClassVar[str] = "named" 105 key: SecretKey 106 salt: PasswordSalt
Use to directly (without doing password hashing) set the SecretKey and PasswordSalt for
read or write access.
90@dataclass 91class SetLocalSecret_Password(SetLocalSecret): 92 """Password provided by the user""" 93 _tag: ClassVar[str] = "Password" 94 _shape: ClassVar[str] = "unnamed" 95 value: Password
Password provided by the user
218@dataclass 219class Stats: 220 """Network traffic statistics.""" 221 _shape: ClassVar[str] = "named" 222 bytes_tx: int 223 bytes_rx: int 224 throughput_tx: int 225 throughput_rx: int
Network traffic statistics.
48@dataclass 49class StorageSize: 50 """Strongly typed storage size.""" 51 _shape: ClassVar[str] = "named" 52 bytes: int
Strongly typed storage size.
234@dataclass 235class TopicId: 236 """ 237 Identified of a network stream topic. 238 239 When two connected peers open a stream with the same topic id, they can communicate over it with 240 each other. 241 """ 242 _shape: ClassVar[str] = "unnamed" 243 value: bytes
Identified of a network stream topic.
When two connected peers open a stream with the same topic id, they can communicate over it with each other.
3555class UnexpectedResponse(OuisyncError): 3556 def __init__(self): 3557 super().__init__(ErrorCode.INVALID_DATA, "unexpected response")
Common base class for all non-exit exceptions.
5@dataclass(frozen=True, order=True) 6class MonitorId: 7 name: str 8 disambiguator: int 9 10 @staticmethod 11 def parse(raw: str) -> "MonitorId": 12 name, _, disambiguator = raw.rpartition(":") 13 return MonitorId(name, int(disambiguator)) 14 15 def __str__(self) -> str: 16 return f"{self.name}:{self.disambiguator}"