xoscar 0.9.0__cp312-cp312-macosx_10_13_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xoscar/__init__.py +61 -0
- xoscar/_utils.cpython-312-darwin.so +0 -0
- xoscar/_utils.pxd +36 -0
- xoscar/_utils.pyx +246 -0
- xoscar/_version.py +693 -0
- xoscar/aio/__init__.py +16 -0
- xoscar/aio/base.py +86 -0
- xoscar/aio/file.py +59 -0
- xoscar/aio/lru.py +228 -0
- xoscar/aio/parallelism.py +39 -0
- xoscar/api.py +527 -0
- xoscar/backend.py +67 -0
- xoscar/backends/__init__.py +14 -0
- xoscar/backends/allocate_strategy.py +160 -0
- xoscar/backends/communication/__init__.py +30 -0
- xoscar/backends/communication/base.py +315 -0
- xoscar/backends/communication/core.py +69 -0
- xoscar/backends/communication/dummy.py +253 -0
- xoscar/backends/communication/errors.py +20 -0
- xoscar/backends/communication/socket.py +444 -0
- xoscar/backends/communication/ucx.py +538 -0
- xoscar/backends/communication/utils.py +97 -0
- xoscar/backends/config.py +157 -0
- xoscar/backends/context.py +437 -0
- xoscar/backends/core.py +352 -0
- xoscar/backends/indigen/__init__.py +16 -0
- xoscar/backends/indigen/__main__.py +19 -0
- xoscar/backends/indigen/backend.py +51 -0
- xoscar/backends/indigen/driver.py +26 -0
- xoscar/backends/indigen/fate_sharing.py +221 -0
- xoscar/backends/indigen/pool.py +515 -0
- xoscar/backends/indigen/shared_memory.py +548 -0
- xoscar/backends/message.cpython-312-darwin.so +0 -0
- xoscar/backends/message.pyi +255 -0
- xoscar/backends/message.pyx +646 -0
- xoscar/backends/pool.py +1630 -0
- xoscar/backends/router.py +285 -0
- xoscar/backends/test/__init__.py +16 -0
- xoscar/backends/test/backend.py +38 -0
- xoscar/backends/test/pool.py +233 -0
- xoscar/batch.py +256 -0
- xoscar/collective/__init__.py +27 -0
- xoscar/collective/backend/__init__.py +13 -0
- xoscar/collective/backend/nccl_backend.py +160 -0
- xoscar/collective/common.py +102 -0
- xoscar/collective/core.py +737 -0
- xoscar/collective/process_group.py +687 -0
- xoscar/collective/utils.py +41 -0
- xoscar/collective/xoscar_pygloo.cpython-312-darwin.so +0 -0
- xoscar/collective/xoscar_pygloo.pyi +239 -0
- xoscar/constants.py +23 -0
- xoscar/context.cpython-312-darwin.so +0 -0
- xoscar/context.pxd +21 -0
- xoscar/context.pyx +368 -0
- xoscar/core.cpython-312-darwin.so +0 -0
- xoscar/core.pxd +51 -0
- xoscar/core.pyx +664 -0
- xoscar/debug.py +188 -0
- xoscar/driver.py +42 -0
- xoscar/errors.py +63 -0
- xoscar/libcpp.pxd +31 -0
- xoscar/metrics/__init__.py +21 -0
- xoscar/metrics/api.py +288 -0
- xoscar/metrics/backends/__init__.py +13 -0
- xoscar/metrics/backends/console/__init__.py +13 -0
- xoscar/metrics/backends/console/console_metric.py +82 -0
- xoscar/metrics/backends/metric.py +149 -0
- xoscar/metrics/backends/prometheus/__init__.py +13 -0
- xoscar/metrics/backends/prometheus/prometheus_metric.py +70 -0
- xoscar/nvutils.py +717 -0
- xoscar/profiling.py +260 -0
- xoscar/serialization/__init__.py +20 -0
- xoscar/serialization/aio.py +141 -0
- xoscar/serialization/core.cpython-312-darwin.so +0 -0
- xoscar/serialization/core.pxd +28 -0
- xoscar/serialization/core.pyi +57 -0
- xoscar/serialization/core.pyx +944 -0
- xoscar/serialization/cuda.py +111 -0
- xoscar/serialization/exception.py +48 -0
- xoscar/serialization/mlx.py +67 -0
- xoscar/serialization/numpy.py +82 -0
- xoscar/serialization/pyfury.py +37 -0
- xoscar/serialization/scipy.py +72 -0
- xoscar/serialization/torch.py +180 -0
- xoscar/utils.py +522 -0
- xoscar/virtualenv/__init__.py +34 -0
- xoscar/virtualenv/core.py +268 -0
- xoscar/virtualenv/platform.py +56 -0
- xoscar/virtualenv/utils.py +100 -0
- xoscar/virtualenv/uv.py +321 -0
- xoscar-0.9.0.dist-info/METADATA +230 -0
- xoscar-0.9.0.dist-info/RECORD +94 -0
- xoscar-0.9.0.dist-info/WHEEL +6 -0
- xoscar-0.9.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Copyright 2022-2023 XProbe Inc.
|
|
2
|
+
# derived from copyright 1999-2021 Alibaba Group Holding Ltd.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from abc import ABC, abstractmethod
|
|
17
|
+
from random import choice
|
|
18
|
+
from typing import Dict, Optional, Tuple
|
|
19
|
+
|
|
20
|
+
from ..core import ActorRef
|
|
21
|
+
from ..errors import NoIdleSlot
|
|
22
|
+
from ..utils import implements
|
|
23
|
+
from .config import ActorPoolConfig
|
|
24
|
+
from .message import _MessageBase
|
|
25
|
+
|
|
26
|
+
allocated_value = Tuple["AllocateStrategy", Optional[_MessageBase]]
|
|
27
|
+
allocated_values = Dict[Optional[ActorRef], allocated_value]
|
|
28
|
+
allocated_type = Dict[str, allocated_values]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AllocateStrategy(ABC):
|
|
32
|
+
__slots__ = ()
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def get_allocated_address(
|
|
36
|
+
self, config: ActorPoolConfig, allocated: allocated_type
|
|
37
|
+
) -> str:
|
|
38
|
+
"""
|
|
39
|
+
Get external address where the actor allocated to.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
config: ActorPoolConfig
|
|
44
|
+
Actor pool config.
|
|
45
|
+
allocated:
|
|
46
|
+
Already allocated of actor and its strategy.
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
allocated_address: str
|
|
51
|
+
External address to allocate.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class AddressSpecified(AllocateStrategy):
|
|
56
|
+
__slots__ = ("address",)
|
|
57
|
+
|
|
58
|
+
def __init__(self, address):
|
|
59
|
+
self.address = address
|
|
60
|
+
|
|
61
|
+
@implements(AllocateStrategy.get_allocated_address)
|
|
62
|
+
def get_allocated_address(
|
|
63
|
+
self, config: ActorPoolConfig, allocated: allocated_type
|
|
64
|
+
) -> str:
|
|
65
|
+
return self.address
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class MainPool(AllocateStrategy):
|
|
69
|
+
__slots__ = ()
|
|
70
|
+
|
|
71
|
+
@implements(AllocateStrategy.get_allocated_address)
|
|
72
|
+
def get_allocated_address(
|
|
73
|
+
self, config: ActorPoolConfig, allocated: allocated_type
|
|
74
|
+
) -> str:
|
|
75
|
+
# allocate to main process
|
|
76
|
+
main_process_index = config.get_process_indexes()[0]
|
|
77
|
+
return config.get_external_address(main_process_index)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Random(AllocateStrategy):
|
|
81
|
+
__slots__ = ()
|
|
82
|
+
|
|
83
|
+
@implements(AllocateStrategy.get_allocated_address)
|
|
84
|
+
def get_allocated_address(
|
|
85
|
+
self, config: ActorPoolConfig, allocated: allocated_type
|
|
86
|
+
) -> str:
|
|
87
|
+
return choice(config.get_external_addresses())
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class RandomSubPool(AllocateStrategy):
|
|
91
|
+
__slots__ = ()
|
|
92
|
+
|
|
93
|
+
@implements(AllocateStrategy.get_allocated_address)
|
|
94
|
+
def get_allocated_address(
|
|
95
|
+
self, config: ActorPoolConfig, allocated: allocated_type
|
|
96
|
+
) -> str:
|
|
97
|
+
return choice(config.get_external_addresses()[1:])
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class ProcessIndex(AllocateStrategy):
|
|
101
|
+
__slots__ = ("process_index",)
|
|
102
|
+
|
|
103
|
+
def __init__(self, process_index: int):
|
|
104
|
+
self.process_index = process_index
|
|
105
|
+
|
|
106
|
+
@implements(AllocateStrategy.get_allocated_address)
|
|
107
|
+
def get_allocated_address(
|
|
108
|
+
self, config: ActorPoolConfig, allocated: allocated_type
|
|
109
|
+
) -> str:
|
|
110
|
+
actual_process_index = config.get_process_indexes()[self.process_index]
|
|
111
|
+
return config.get_pool_config(actual_process_index)["external_address"][0]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class RandomLabel(AllocateStrategy):
|
|
115
|
+
__slots__ = ("label",)
|
|
116
|
+
|
|
117
|
+
def __init__(self, label):
|
|
118
|
+
self.label = label
|
|
119
|
+
|
|
120
|
+
@implements(AllocateStrategy.get_allocated_address)
|
|
121
|
+
def get_allocated_address(
|
|
122
|
+
self, config: ActorPoolConfig, allocated: allocated_type
|
|
123
|
+
) -> str:
|
|
124
|
+
return choice(config.get_external_addresses(label=self.label))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class IdleLabel(AllocateStrategy):
|
|
128
|
+
__slots__ = "label", "mark"
|
|
129
|
+
|
|
130
|
+
def __init__(self, label, mark):
|
|
131
|
+
self.label = label
|
|
132
|
+
self.mark = mark
|
|
133
|
+
|
|
134
|
+
def __hash__(self):
|
|
135
|
+
return hash((type(self), self.label, self.mark))
|
|
136
|
+
|
|
137
|
+
def __eq__(self, other):
|
|
138
|
+
return (
|
|
139
|
+
isinstance(other, IdleLabel)
|
|
140
|
+
and self.label == other.label
|
|
141
|
+
and self.mark == other.mark
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
@implements(AllocateStrategy.get_allocated_address)
|
|
145
|
+
def get_allocated_address(
|
|
146
|
+
self, config: ActorPoolConfig, allocated: allocated_type
|
|
147
|
+
) -> str:
|
|
148
|
+
addresses = config.get_external_addresses(label=self.label)
|
|
149
|
+
for addr in addresses:
|
|
150
|
+
occupied = False
|
|
151
|
+
for strategy, _ in allocated.get(addr, dict()).values():
|
|
152
|
+
if strategy == self:
|
|
153
|
+
occupied = True
|
|
154
|
+
break
|
|
155
|
+
if not occupied:
|
|
156
|
+
return addr
|
|
157
|
+
raise NoIdleSlot(
|
|
158
|
+
f"No idle slot for creating actor "
|
|
159
|
+
f"with label {self.label}, mark {self.mark}"
|
|
160
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Copyright 2022-2023 XProbe Inc.
|
|
2
|
+
# derived from copyright 1999-2021 Alibaba Group Holding Ltd.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from .base import Channel, ChannelType, Client, Server
|
|
17
|
+
from .core import gen_local_address, get_client_type, get_server_type
|
|
18
|
+
from .dummy import DummyChannel, DummyClient, DummyServer
|
|
19
|
+
from .socket import (
|
|
20
|
+
SocketChannel,
|
|
21
|
+
SocketClient,
|
|
22
|
+
SocketServer,
|
|
23
|
+
UnixSocketClient,
|
|
24
|
+
UnixSocketServer,
|
|
25
|
+
)
|
|
26
|
+
from .ucx import ( # noqa: F401 # pylint: disable=unused-import
|
|
27
|
+
UCXChannel,
|
|
28
|
+
UCXClient,
|
|
29
|
+
UCXServer,
|
|
30
|
+
)
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# Copyright 2022-2023 XProbe Inc.
|
|
2
|
+
# derived from copyright 1999-2021 Alibaba Group Holding Ltd.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from typing import Any, Callable, Coroutine, Type
|
|
21
|
+
|
|
22
|
+
from ...utils import classproperty, implements
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class ChannelType:
|
|
27
|
+
local = 0 # for local communication
|
|
28
|
+
ipc = 1 # inproc
|
|
29
|
+
remote = 2 # remote
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Channel(ABC):
|
|
33
|
+
"""
|
|
34
|
+
Channel is used to do data exchange between server and client.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
__slots__ = "local_address", "dest_address", "compression"
|
|
38
|
+
|
|
39
|
+
name: str | None = None
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
local_address: str | None = None,
|
|
44
|
+
dest_address: str | None = None,
|
|
45
|
+
compression: str | None = None,
|
|
46
|
+
):
|
|
47
|
+
self.local_address = local_address
|
|
48
|
+
self.dest_address = dest_address
|
|
49
|
+
self.compression = compression
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
async def send(self, message: Any):
|
|
53
|
+
"""
|
|
54
|
+
Send data to dest. There should be only one send for one recv, otherwise recv messages
|
|
55
|
+
may overlap.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
message:
|
|
60
|
+
data that sent to dest.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
async def recv(self):
|
|
65
|
+
"""
|
|
66
|
+
Receive data that sent from dest.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
@abstractmethod
|
|
70
|
+
async def close(self):
|
|
71
|
+
"""
|
|
72
|
+
Close channel.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
@abstractmethod
|
|
77
|
+
def closed(self) -> bool:
|
|
78
|
+
"""
|
|
79
|
+
This channel is closed or not.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
closed:
|
|
84
|
+
If the channel is closed.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
@abstractmethod
|
|
89
|
+
def type(self) -> int:
|
|
90
|
+
"""
|
|
91
|
+
Channel is used for, can be dummy, ipc or remote.
|
|
92
|
+
|
|
93
|
+
Returns
|
|
94
|
+
-------
|
|
95
|
+
channel_type: int
|
|
96
|
+
type that can be dummy, ipc or remote.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def info(self) -> dict:
|
|
101
|
+
return {
|
|
102
|
+
"name": self.name,
|
|
103
|
+
"compression": self.compression,
|
|
104
|
+
"type": self.type,
|
|
105
|
+
"local_address": self.local_address,
|
|
106
|
+
"dest_address": self.dest_address,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Server(ABC):
|
|
111
|
+
__slots__ = "address", "channel_handler"
|
|
112
|
+
|
|
113
|
+
scheme: str | None = None
|
|
114
|
+
|
|
115
|
+
def __init__(
|
|
116
|
+
self,
|
|
117
|
+
address: str,
|
|
118
|
+
channel_handler: Callable[[Channel], Coroutine] | None = None,
|
|
119
|
+
):
|
|
120
|
+
self.address = address
|
|
121
|
+
self.channel_handler = channel_handler
|
|
122
|
+
|
|
123
|
+
@classproperty
|
|
124
|
+
@abstractmethod
|
|
125
|
+
def client_type(self) -> Type["Client"]:
|
|
126
|
+
"""
|
|
127
|
+
Return the corresponding client type.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
client_type: type
|
|
132
|
+
client type.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
@property
|
|
136
|
+
@abstractmethod
|
|
137
|
+
def channel_type(self) -> int:
|
|
138
|
+
"""
|
|
139
|
+
Channel type, can be dummy, ipc or remote.
|
|
140
|
+
|
|
141
|
+
Returns
|
|
142
|
+
-------
|
|
143
|
+
channel_type: int
|
|
144
|
+
type that can be dummy, ipc or remote.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
@abstractmethod
|
|
149
|
+
async def create(config: dict) -> "Server":
|
|
150
|
+
"""
|
|
151
|
+
Create a server instance according to configuration.
|
|
152
|
+
|
|
153
|
+
Parameters
|
|
154
|
+
----------
|
|
155
|
+
config: dict
|
|
156
|
+
configuration about creating a channel.
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
server: Server
|
|
161
|
+
a server that waiting for connections from clients.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
@abstractmethod
|
|
165
|
+
async def start(self):
|
|
166
|
+
"""
|
|
167
|
+
Used for listening to port or similar stuff.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
@abstractmethod
|
|
171
|
+
async def join(self, timeout=None):
|
|
172
|
+
"""
|
|
173
|
+
Wait forever until timeout.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
@abstractmethod
|
|
177
|
+
async def on_connected(self, *args, **kwargs):
|
|
178
|
+
"""
|
|
179
|
+
Return a channel when new client connected.
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
channel: Channel
|
|
184
|
+
channel for communication
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
@abstractmethod
|
|
188
|
+
async def stop(self):
|
|
189
|
+
"""
|
|
190
|
+
Stop the server.
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
@abstractmethod
|
|
195
|
+
def stopped(self) -> bool:
|
|
196
|
+
"""
|
|
197
|
+
If this server is stopped or not.
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
if_stopped: bool
|
|
202
|
+
This server is stopped or not.
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def info(self) -> dict:
|
|
207
|
+
return {
|
|
208
|
+
"name": self.scheme,
|
|
209
|
+
"address": self.address,
|
|
210
|
+
"channel_type": self.channel_type,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@classmethod
|
|
214
|
+
def parse_config(cls, config: dict) -> dict:
|
|
215
|
+
# skip parsing config by default
|
|
216
|
+
return dict()
|
|
217
|
+
|
|
218
|
+
async def __aenter__(self):
|
|
219
|
+
await self.start()
|
|
220
|
+
return self
|
|
221
|
+
|
|
222
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
223
|
+
await self.stop()
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class Client(ABC):
|
|
227
|
+
__slots__ = "local_address", "dest_address", "channel"
|
|
228
|
+
|
|
229
|
+
scheme: str | None = None
|
|
230
|
+
|
|
231
|
+
def __init__(
|
|
232
|
+
self, local_address: str | None, dest_address: str | None, channel: Channel
|
|
233
|
+
):
|
|
234
|
+
self.local_address = local_address
|
|
235
|
+
self.dest_address = dest_address
|
|
236
|
+
self.channel = channel
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def channel_type(self) -> int:
|
|
240
|
+
"""
|
|
241
|
+
Channel type, can be dummy, ipc or remote.
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
channel_type: int
|
|
246
|
+
type that can be dummy, ipc or remote.
|
|
247
|
+
"""
|
|
248
|
+
return self.channel.type
|
|
249
|
+
|
|
250
|
+
@staticmethod
|
|
251
|
+
@abstractmethod
|
|
252
|
+
async def connect(
|
|
253
|
+
dest_address: str, local_address: str | None = None, **kwargs
|
|
254
|
+
) -> "Client":
|
|
255
|
+
"""
|
|
256
|
+
Create a client that is able to connect to some server.
|
|
257
|
+
|
|
258
|
+
Parameters
|
|
259
|
+
----------
|
|
260
|
+
dest_address: str
|
|
261
|
+
Destination server address that to connect to.
|
|
262
|
+
local_address: str
|
|
263
|
+
local address.
|
|
264
|
+
|
|
265
|
+
Returns
|
|
266
|
+
-------
|
|
267
|
+
client: Client
|
|
268
|
+
Client that holds a channel to communicate.
|
|
269
|
+
"""
|
|
270
|
+
|
|
271
|
+
@classmethod
|
|
272
|
+
def parse_config(cls, config: dict) -> dict:
|
|
273
|
+
# skip parsing config by default
|
|
274
|
+
return dict()
|
|
275
|
+
|
|
276
|
+
@implements(Channel.send)
|
|
277
|
+
async def send(self, message):
|
|
278
|
+
return await self.channel.send(message)
|
|
279
|
+
|
|
280
|
+
@implements(Channel.recv)
|
|
281
|
+
async def recv(self):
|
|
282
|
+
return await self.channel.recv()
|
|
283
|
+
|
|
284
|
+
async def close(self):
|
|
285
|
+
"""
|
|
286
|
+
Close connection.
|
|
287
|
+
"""
|
|
288
|
+
await self.channel.close()
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
def closed(self) -> bool:
|
|
292
|
+
"""
|
|
293
|
+
This client is closed or not.
|
|
294
|
+
|
|
295
|
+
Returns
|
|
296
|
+
-------
|
|
297
|
+
closed: bool
|
|
298
|
+
If the client is closed.
|
|
299
|
+
"""
|
|
300
|
+
return self.channel.closed
|
|
301
|
+
|
|
302
|
+
@property
|
|
303
|
+
def info(self) -> dict:
|
|
304
|
+
return {
|
|
305
|
+
"local_address": self.local_address,
|
|
306
|
+
"dest_address": self.dest_address,
|
|
307
|
+
"channel_name": self.channel.name,
|
|
308
|
+
"channel_type": self.channel_type,
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async def __aenter__(self):
|
|
312
|
+
return self
|
|
313
|
+
|
|
314
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
315
|
+
await self.close()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copyright 2022-2023 XProbe Inc.
|
|
2
|
+
# derived from copyright 1999-2021 Alibaba Group Holding Ltd.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Type
|
|
19
|
+
from urllib.parse import urlparse
|
|
20
|
+
|
|
21
|
+
from .base import Client, Server
|
|
22
|
+
|
|
23
|
+
_scheme_to_client_types: dict[str, Type[Client]] = dict()
|
|
24
|
+
_scheme_to_server_types: dict[str, Type[Server]] = dict()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def register_client(client_type: Type[Client]):
|
|
28
|
+
_scheme_to_client_types[client_type.scheme] = client_type # type: ignore
|
|
29
|
+
return client_type
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def register_server(server_type: Type[Server]):
|
|
33
|
+
_scheme_to_server_types[server_type.scheme] = server_type # type: ignore
|
|
34
|
+
return server_type
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _check_scheme(scheme: str | None, types: dict):
|
|
38
|
+
if scheme == "":
|
|
39
|
+
scheme = None
|
|
40
|
+
if scheme not in types: # pragma: no cover
|
|
41
|
+
raise ValueError(
|
|
42
|
+
f"address illegal, address scheme "
|
|
43
|
+
f"should be one of "
|
|
44
|
+
f'{", ".join(types)}, '
|
|
45
|
+
f"got {scheme}"
|
|
46
|
+
)
|
|
47
|
+
return scheme
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_scheme(address: str) -> str | None:
|
|
51
|
+
if "://" not in address:
|
|
52
|
+
scheme = None
|
|
53
|
+
else:
|
|
54
|
+
scheme = urlparse(address).scheme
|
|
55
|
+
return scheme
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_client_type(address: str) -> Type[Client]:
|
|
59
|
+
scheme = _check_scheme(get_scheme(address), _scheme_to_client_types)
|
|
60
|
+
return _scheme_to_client_types[scheme]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_server_type(address: str) -> Type[Server]:
|
|
64
|
+
scheme = _check_scheme(get_scheme(address), _scheme_to_server_types)
|
|
65
|
+
return _scheme_to_server_types[scheme]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def gen_local_address(process_index: int) -> str:
|
|
69
|
+
return f"dummy://{process_index}"
|