-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
python: Backport the v8 Connection class to the v7 branch.
- Loading branch information
Showing
16 changed files
with
1,105 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# Copyright (c) 2017-2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
""" | ||
Utilities for working with ledger offsets. | ||
This API is _not_ public! | ||
""" | ||
from __future__ import annotations | ||
|
||
from typing import Any, Optional, Union | ||
|
||
__all__ = [ | ||
"LedgerOffsetRange", | ||
"UNTIL_END", | ||
"FROM_BEGINNING_UNTIL_FOREVER", | ||
"from_offset_until_forever", | ||
] | ||
|
||
|
||
class End: | ||
""" | ||
Marker object that denotes the current end of the ledger. | ||
""" | ||
|
||
def __hash__(self): | ||
return 0 | ||
|
||
def __repr__(self): | ||
return "END" | ||
|
||
|
||
END = End() | ||
|
||
|
||
class LedgerOffsetRange: | ||
""" | ||
Denotes an offset range on a ledger. This API is _not_ considered public. | ||
The gRPC Ledger API and HTTP JSON API do not expose ledger offsets with the same semantics, | ||
so this class actually represents the commonality between these two interfaces. | ||
""" | ||
|
||
def __init__(self, begin: Union[None, str], end: Union[None, End], /): | ||
""" | ||
Initialize a :class:`LedgerOffsetRange`. | ||
:param begin: | ||
The start of the stream. If ``None``, then read from the beginning of the ledger. | ||
Otherwise, must be a legal ledger offset. | ||
:param end: | ||
The end of the stream. If ``None``, then keep reading from the stream forever; if | ||
``END``, then terminate when reaching the _current_ end of stream. Note that offsets | ||
are *not* allowed here, as the HTTP JSON API does not provide a mechanism for reading | ||
*to* a specific transaction offset. | ||
""" | ||
self.begin = begin | ||
self.end = end | ||
|
||
def __eq__(self, other: Any) -> bool: | ||
return ( | ||
isinstance(other, LedgerOffsetRange) | ||
and self.begin == other.begin | ||
and self.end == other.end | ||
) | ||
|
||
def __hash__(self): | ||
return hash(self.begin) ^ hash(self.end) | ||
|
||
|
||
UNTIL_END = LedgerOffsetRange(None, END) | ||
FROM_BEGINNING_UNTIL_FOREVER = LedgerOffsetRange(None, None) | ||
|
||
|
||
def from_offset_until_forever(offset: Optional[str]) -> LedgerOffsetRange: | ||
return LedgerOffsetRange(offset, None) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Copyright (c) 2017-2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
__all__ = ["CallbackReturnWarning", "ProtocolWarning"] | ||
|
||
|
||
class CallbackReturnWarning(Warning): | ||
""" | ||
Raised when a user callback on a stream returns a value. These objects have no meaning and are | ||
ignored by dazl. | ||
This warning is raised primarily because older versions of dazl interpreted returning commands | ||
from a callback as a request to send commands to the underlying ledger, and this is not | ||
supported in newer APIs. | ||
""" | ||
|
||
|
||
class ProtocolWarning(Warning): | ||
""" | ||
Warnings that are raised when dazl detects incompatibilities between the Ledger API server-side | ||
implementation and dazl. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,15 @@ | ||
# Copyright (c) 2017-2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
from ..config import Config | ||
from .conn_aio import Connection | ||
|
||
__all__ = ["connect", "Connection"] | ||
|
||
|
||
def connect(**kwargs): | ||
""" | ||
Connect to a gRPC Ledger API implementation and return a connection that uses asyncio. | ||
""" | ||
config = Config.create(**kwargs) | ||
return Connection(config) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Copyright (c) 2017-2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
from os import PathLike | ||
from typing import Collection, Optional, Union | ||
|
||
from ...prim import Party, TimeDeltaLike | ||
from .conn_aio import Connection | ||
|
||
__all__ = ["connect", "Connection"] | ||
|
||
# TODO: Figure out clever ways to make this function's type signature easier to maintain while | ||
# preserving its ease of use to callers. | ||
def connect( | ||
url: str, | ||
*, | ||
read_as: "Union[None, Party, Collection[Party]]" = None, | ||
act_as: "Union[None, Party, Collection[Party]]" = None, | ||
admin: "Optional[bool]" = False, | ||
ledger_id: "Optional[str]" = None, | ||
application_name: "Optional[str]" = None, | ||
oauth_token: "Optional[str]" = None, | ||
ca: "Optional[bytes]" = None, | ||
ca_file: "Optional[PathLike]" = None, | ||
cert: "Optional[bytes]" = None, | ||
cert_file: "Optional[PathLike]" = None, | ||
cert_key: "Optional[bytes]" = None, | ||
cert_key_file: "Optional[PathLike]" = None, | ||
connect_timeout: "Optional[TimeDeltaLike]" = None, | ||
enable_http_proxy: "bool" = True, | ||
) -> Connection: ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Copyright (c) 2017-2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
from typing import List, Tuple, Union, cast | ||
from urllib.parse import urlparse | ||
|
||
from grpc import ( | ||
AuthMetadataContext, | ||
AuthMetadataPlugin, | ||
AuthMetadataPluginCallback, | ||
ChannelCredentials, | ||
composite_channel_credentials, | ||
metadata_call_credentials, | ||
ssl_channel_credentials, | ||
) | ||
from grpc.aio import Channel, insecure_channel, secure_channel # type: ignore | ||
|
||
from ..config import Config | ||
|
||
__all__ = ["create_channel"] | ||
|
||
|
||
def create_channel(config: "Config") -> "Channel": | ||
""" | ||
Create a :class:`Channel` for the specified configuration. | ||
""" | ||
u = urlparse(config.url.url) | ||
|
||
options = [ | ||
("grpc.max_send_message_length", -1), | ||
("grpc.max_receive_message_length", -1), | ||
] | ||
if not config.url.use_http_proxy: | ||
options.append(("grpc.enable_http_proxy", 0)) | ||
|
||
if (u.scheme in ("https", "grpcs")) or config.ssl: | ||
credentials = ssl_channel_credentials( | ||
root_certificates=config.ssl.ca, | ||
private_key=config.ssl.cert_key, | ||
certificate_chain=config.ssl.cert, | ||
) | ||
if config.access.token: | ||
# The grpc Credential objects do not actually define a formal interface, and are | ||
# used interchangeably in the code. | ||
# | ||
# Additionally there are some incorrect rules in the grpc-stubs typing rules that force | ||
# us to work around the type system. | ||
credentials = cast( | ||
ChannelCredentials, | ||
composite_channel_credentials( | ||
credentials, metadata_call_credentials(GrpcAuth(config)) | ||
), | ||
) | ||
return secure_channel(u.netloc, credentials, options) | ||
else: | ||
return insecure_channel(u.netloc, options) | ||
|
||
|
||
class GrpcAuth(AuthMetadataPlugin): | ||
def __init__(self, config: "Config"): | ||
self._config = config | ||
|
||
def __call__(self, context: "AuthMetadataContext", callback: "AuthMetadataPluginCallback"): | ||
# This overly verbose type signature is here to satisfy mypy and grpc-stubs | ||
options = [] # type: List[Tuple[str, Union[str, bytes]]] | ||
|
||
# TODO: Add support here for refresh tokens | ||
token = self._config.access.token | ||
if token: | ||
options.append(("Authorization", "Bearer " + self._config.access.token)) | ||
|
||
callback(tuple(options), None) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.