koi-net 1.1.0b1__py3-none-any.whl → 1.1.0b3__py3-none-any.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.
koi_net/config.py CHANGED
@@ -29,6 +29,7 @@ class KoiNetConfig(BaseModel):
29
29
  cache_directory_path: str = ".rid_cache"
30
30
  event_queues_path: str = "event_queues.json"
31
31
  private_key_pem_path: str = "priv_key.pem"
32
+ polling_interval: int = 5
32
33
 
33
34
  first_contact: NodeContact = Field(default_factory=NodeContact)
34
35
 
koi_net/core.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import logging
2
- import httpx
2
+ from typing import Generic, TypeVar
3
3
  from rid_lib.ext import Cache
4
4
  from .network.resolver import NetworkResolver
5
5
  from .network.event_queue import NetworkEventQueue
@@ -17,14 +17,18 @@ from .secure import Secure
17
17
  from .config import NodeConfig
18
18
  from .context import HandlerContext, ActionContext
19
19
  from .effector import Effector
20
+ from .server import NodeServer
21
+ from .lifecycle import NodeLifecycle
22
+ from .poller import NodePoller
20
23
  from . import default_actions
21
24
 
22
25
  logger = logging.getLogger(__name__)
23
26
 
24
27
 
28
+ T = TypeVar("T", bound=NodeConfig)
25
29
 
26
- class NodeInterface:
27
- config: NodeConfig
30
+ class NodeInterface(Generic[T]):
31
+ config: T
28
32
  cache: Cache
29
33
  identity: NodeIdentity
30
34
  resolver: NetworkResolver
@@ -32,66 +36,81 @@ class NodeInterface:
32
36
  graph: NetworkGraph
33
37
  processor: ProcessorInterface
34
38
  secure: Secure
39
+ server: NodeServer
35
40
 
36
41
  use_kobj_processor_thread: bool
37
42
 
38
43
  def __init__(
39
- self,
40
- config: NodeConfig,
44
+ self,
45
+ config: T,
41
46
  use_kobj_processor_thread: bool = False,
42
-
43
47
  handlers: list[KnowledgeHandler] | None = None,
44
48
 
45
- cache: Cache | None = None,
46
- processor: ProcessorInterface | None = None
49
+ CacheOverride: type[Cache] | None = None,
50
+ NodeIdentityOverride: type[NodeIdentity] | None = None,
51
+ EffectorOverride: type[Effector] | None = None,
52
+ NetworkGraphOverride: type[NetworkGraph] | None = None,
53
+ SecureOverride: type[Secure] | None = None,
54
+ RequestHandlerOverride: type[RequestHandler] | None = None,
55
+ ResponseHandlerOverride: type[ResponseHandler] | None = None,
56
+ NetworkResolverOverride: type[NetworkResolver] | None = None,
57
+ NetworkEventQueueOverride: type[NetworkEventQueue] | None = None,
58
+ ActorOverride: type[Actor] | None = None,
59
+ ActionContextOverride: type[ActionContext] | None = None,
60
+ HandlerContextOverride: type[HandlerContext] | None = None,
61
+ KnowledgePipelineOverride: type[KnowledgePipeline] | None = None,
62
+ ProcessorInterfaceOverride: type[ProcessorInterface] | None = None,
63
+ ErrorHandlerOverride: type[ErrorHandler] | None = None,
64
+ NodeLifecycleOverride: type[NodeLifecycle] | None = None,
65
+ NodeServerOverride: type[NodeServer] | None = None,
66
+ NodePollerOverride: type[NodePoller] | None = None,
47
67
  ):
48
68
  self.config = config
49
- self.cache = cache or Cache(
69
+ self.cache = (CacheOverride or Cache)(
50
70
  directory_path=self.config.koi_net.cache_directory_path
51
71
  )
52
-
53
- self.identity = NodeIdentity(config=self.config)
54
-
55
- self.effector = Effector(cache=self.cache)
56
72
 
57
- self.graph = NetworkGraph(
58
- cache=self.cache,
73
+ self.identity = (NodeIdentityOverride or NodeIdentity)(config=self.config)
74
+ self.effector = (EffectorOverride or Effector)(cache=self.cache)
75
+
76
+ self.graph = (NetworkGraphOverride or NetworkGraph)(
77
+ cache=self.cache,
59
78
  identity=self.identity
60
79
  )
61
-
62
- self.secure = Secure(
63
- identity=self.identity,
64
- effector=self.effector,
80
+
81
+ self.secure = (SecureOverride or Secure)(
82
+ identity=self.identity,
83
+ effector=self.effector,
65
84
  config=self.config
66
85
  )
67
-
68
- self.request_handler = RequestHandler(
69
- effector=self.effector,
86
+
87
+ self.request_handler = (RequestHandlerOverride or RequestHandler)(
88
+ effector=self.effector,
70
89
  identity=self.identity,
71
90
  secure=self.secure
72
91
  )
73
-
74
- self.response_handler = ResponseHandler(self.cache, self.effector)
75
-
76
- self.resolver = NetworkResolver(
92
+
93
+ self.response_handler = (ResponseHandlerOverride or ResponseHandler)(self.cache, self.effector)
94
+
95
+ self.resolver = (NetworkResolverOverride or NetworkResolver)(
77
96
  config=self.config,
78
- cache=self.cache,
97
+ cache=self.cache,
79
98
  identity=self.identity,
80
99
  graph=self.graph,
81
100
  request_handler=self.request_handler,
82
101
  effector=self.effector
83
102
  )
84
-
85
- self.event_queue = NetworkEventQueue(
103
+
104
+ self.event_queue = (NetworkEventQueueOverride or NetworkEventQueue)(
86
105
  config=self.config,
87
- cache=self.cache,
106
+ cache=self.cache,
88
107
  identity=self.identity,
89
108
  graph=self.graph,
90
109
  request_handler=self.request_handler,
91
110
  effector=self.effector
92
111
  )
93
112
 
94
- self.actor = Actor(
113
+ self.actor = (ActorOverride or Actor)(
95
114
  identity=self.identity,
96
115
  effector=self.effector,
97
116
  event_queue=self.event_queue
@@ -106,12 +125,12 @@ class NodeInterface:
106
125
 
107
126
  self.use_kobj_processor_thread = use_kobj_processor_thread
108
127
 
109
- self.action_context = ActionContext(
128
+ self.action_context = (ActionContextOverride or ActionContext)(
110
129
  identity=self.identity,
111
130
  effector=self.effector
112
131
  )
113
132
 
114
- self.handler_context = HandlerContext(
133
+ self.handler_context = (HandlerContextOverride or HandlerContext)(
115
134
  identity=self.identity,
116
135
  cache=self.cache,
117
136
  event_queue=self.event_queue,
@@ -120,7 +139,7 @@ class NodeInterface:
120
139
  effector=self.effector
121
140
  )
122
141
 
123
- self.pipeline = KnowledgePipeline(
142
+ self.pipeline = (KnowledgePipelineOverride or KnowledgePipeline)(
124
143
  handler_context=self.handler_context,
125
144
  cache=self.cache,
126
145
  request_handler=self.request_handler,
@@ -129,12 +148,12 @@ class NodeInterface:
129
148
  default_handlers=handlers
130
149
  )
131
150
 
132
- self.processor = processor or ProcessorInterface(
151
+ self.processor = (ProcessorInterfaceOverride or ProcessorInterface)(
133
152
  pipeline=self.pipeline,
134
153
  use_kobj_processor_thread=self.use_kobj_processor_thread
135
154
  )
136
155
 
137
- self.error_handler = ErrorHandler(
156
+ self.error_handler = (ErrorHandlerOverride or ErrorHandler)(
138
157
  processor=self.processor,
139
158
  actor=self.actor
140
159
  )
@@ -146,47 +165,30 @@ class NodeInterface:
146
165
  self.effector.set_processor(self.processor)
147
166
  self.effector.set_resolver(self.resolver)
148
167
  self.effector.set_action_context(self.action_context)
149
-
150
-
151
- def start(self) -> None:
152
- """Starts a node, call this method first.
153
-
154
- Starts the processor thread (if enabled). Loads event queues into memory. Generates network graph from nodes and edges in cache. Processes any state changes of node bundle. Initiates handshake with first contact (if provided) if node doesn't have any neighbors.
155
- """
156
- if self.use_kobj_processor_thread:
157
- logger.info("Starting processor worker thread")
158
- self.processor.worker_thread.start()
159
-
160
- # self.network._load_event_queues()
161
- self.graph.generate()
162
-
163
- # refresh to reflect changes (if any) in config.yaml
164
- self.effector.deref(self.identity.rid, refresh_cache=True)
165
-
166
- logger.debug("Waiting for kobj queue to empty")
167
- if self.use_kobj_processor_thread:
168
- self.processor.kobj_queue.join()
169
- else:
170
- self.processor.flush_kobj_queue()
171
- logger.debug("Done")
172
-
173
- if not self.graph.get_neighbors() and self.config.koi_net.first_contact.rid:
174
- logger.debug(f"I don't have any neighbors, reaching out to first contact {self.config.koi_net.first_contact.rid!r}")
175
-
176
- self.actor.handshake_with(self.config.koi_net.first_contact.rid)
177
-
178
-
179
- def stop(self):
180
- """Stops a node, call this method last.
181
168
 
182
- Finishes processing knowledge object queue. Saves event queues to storage.
183
- """
184
- logger.info("Stopping node...")
169
+ self.lifecycle = (NodeLifecycleOverride or NodeLifecycle)(
170
+ config=self.config,
171
+ identity=self.identity,
172
+ graph=self.graph,
173
+ processor=self.processor,
174
+ effector=self.effector,
175
+ actor=self.actor,
176
+ use_kobj_processor_thread=use_kobj_processor_thread
177
+ )
185
178
 
186
- if self.use_kobj_processor_thread:
187
- logger.info(f"Waiting for kobj queue to empty ({self.processor.kobj_queue.unfinished_tasks} tasks remaining)")
188
- self.processor.kobj_queue.join()
189
- else:
190
- self.processor.flush_kobj_queue()
179
+ # if self.config.koi_net.node_profile.node_type == NodeType.FULL:
180
+ self.server = (NodeServerOverride or NodeServer)(
181
+ config=self.config,
182
+ lifecycle=self.lifecycle,
183
+ secure=self.secure,
184
+ processor=self.processor,
185
+ event_queue=self.event_queue,
186
+ response_handler=self.response_handler
187
+ )
191
188
 
192
- # self.network._save_event_queues()
189
+ self.poller = (NodePollerOverride or NodePoller)(
190
+ processor=self.processor,
191
+ lifecycle=self.lifecycle,
192
+ resolver=self.resolver,
193
+ config=self.config
194
+ )
koi_net/lifecycle.py ADDED
@@ -0,0 +1,76 @@
1
+ import logging
2
+
3
+ from .network.behavior import Actor
4
+ from .effector import Effector
5
+ from .config import NodeConfig
6
+ from .processor.interface import ProcessorInterface
7
+ from .network.graph import NetworkGraph
8
+ from .identity import NodeIdentity
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class NodeLifecycle:
14
+ config: NodeConfig
15
+ graph: NetworkGraph
16
+ processor: ProcessorInterface
17
+ effector: Effector
18
+ actor: Actor
19
+
20
+ def __init__(
21
+ self,
22
+ config: NodeConfig,
23
+ identity: NodeIdentity,
24
+ graph: NetworkGraph,
25
+ processor: ProcessorInterface,
26
+ effector: Effector,
27
+ actor: Actor,
28
+ use_kobj_processor_thread: bool
29
+ ):
30
+ self.config = config
31
+ self.identity = identity
32
+ self.graph = graph
33
+ self.processor = processor
34
+ self.effector = effector
35
+ self.actor = actor
36
+ self.use_kobj_processor_thread = use_kobj_processor_thread
37
+
38
+ def start(self) -> None:
39
+ """Starts a node, call this method first.
40
+
41
+ Starts the processor thread (if enabled). Loads event queues into memory. Generates network graph from nodes and edges in cache. Processes any state changes of node bundle. Initiates handshake with first contact (if provided) if node doesn't have any neighbors.
42
+ """
43
+ if self.use_kobj_processor_thread:
44
+ logger.info("Starting processor worker thread")
45
+ self.processor.worker_thread.start()
46
+
47
+ self.graph.generate()
48
+
49
+ # refresh to reflect changes (if any) in config.yaml
50
+ self.effector.deref(self.identity.rid, refresh_cache=True)
51
+
52
+ logger.debug("Waiting for kobj queue to empty")
53
+ if self.use_kobj_processor_thread:
54
+ self.processor.kobj_queue.join()
55
+ else:
56
+ self.processor.flush_kobj_queue()
57
+ logger.debug("Done")
58
+
59
+ if not self.graph.get_neighbors() and self.config.koi_net.first_contact.rid:
60
+ logger.debug(f"I don't have any neighbors, reaching out to first contact {self.config.koi_net.first_contact.rid!r}")
61
+
62
+ self.actor.handshake_with(self.config.koi_net.first_contact.rid)
63
+
64
+
65
+ def stop(self):
66
+ """Stops a node, call this method last.
67
+
68
+ Finishes processing knowledge object queue. Saves event queues to storage.
69
+ """
70
+ logger.info("Stopping node...")
71
+
72
+ if self.use_kobj_processor_thread:
73
+ logger.info(f"Waiting for kobj queue to empty ({self.processor.kobj_queue.unfinished_tasks} tasks remaining)")
74
+ self.processor.kobj_queue.join()
75
+ else:
76
+ self.processor.flush_kobj_queue()
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  from rid_lib import RID
3
+ from rid_lib.types import KoiNetNode
3
4
  from rid_lib.ext import Manifest, Cache
4
5
  from rid_lib.ext.bundle import Bundle
5
6
 
@@ -30,13 +31,13 @@ class ResponseHandler:
30
31
  self.cache = cache
31
32
  self.effector = effector
32
33
 
33
- def fetch_rids(self, req: FetchRids) -> RidsPayload:
34
+ def fetch_rids(self, req: FetchRids, source: KoiNetNode) -> RidsPayload:
34
35
  logger.info(f"Request to fetch rids, allowed types {req.rid_types}")
35
36
  rids = self.cache.list_rids(req.rid_types)
36
37
 
37
38
  return RidsPayload(rids=rids)
38
39
 
39
- def fetch_manifests(self, req: FetchManifests) -> ManifestsPayload:
40
+ def fetch_manifests(self, req: FetchManifests, source: KoiNetNode) -> ManifestsPayload:
40
41
  logger.info(f"Request to fetch manifests, allowed types {req.rid_types}, rids {req.rids}")
41
42
 
42
43
  manifests: list[Manifest] = []
@@ -51,7 +52,7 @@ class ResponseHandler:
51
52
 
52
53
  return ManifestsPayload(manifests=manifests, not_found=not_found)
53
54
 
54
- def fetch_bundles(self, req: FetchBundles) -> BundlesPayload:
55
+ def fetch_bundles(self, req: FetchBundles, source: KoiNetNode) -> BundlesPayload:
55
56
  logger.info(f"Request to fetch bundles, requested rids {req.rids}")
56
57
 
57
58
  bundles: list[Bundle] = []
koi_net/poller.py ADDED
@@ -0,0 +1,47 @@
1
+
2
+ import time
3
+ import logging
4
+ from .processor.interface import ProcessorInterface
5
+ from .lifecycle import NodeLifecycle
6
+ from .network.resolver import NetworkResolver
7
+ from .config import NodeConfig
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class NodePoller:
13
+ def __init__(
14
+ self,
15
+ processor: ProcessorInterface,
16
+ lifecycle: NodeLifecycle,
17
+ resolver: NetworkResolver,
18
+ config: NodeConfig
19
+ ):
20
+ self.processor = processor
21
+ self.lifecycle = lifecycle
22
+ self.resolver = resolver
23
+ self.config = config
24
+
25
+ def poll(self):
26
+ neighbors = self.resolver.poll_neighbors()
27
+ for node_rid in neighbors:
28
+ for event in neighbors[node_rid]:
29
+ self.processor.handle(event=event, source=node_rid)
30
+ self.processor.flush_kobj_queue()
31
+
32
+ def run(self):
33
+ try:
34
+ self.lifecycle.start()
35
+ while True:
36
+ start_time = time.time()
37
+ self.poll()
38
+ elapsed = time.time() - start_time
39
+ sleep_time = self.config.koi_net.polling_interval - elapsed
40
+ if sleep_time > 0:
41
+ time.sleep(sleep_time)
42
+
43
+ except KeyboardInterrupt:
44
+ logger.info("Polling interrupted by user.")
45
+
46
+ finally:
47
+ self.lifecycle.stop()
koi_net/server.py ADDED
@@ -0,0 +1,128 @@
1
+ import logging
2
+ import uvicorn
3
+ from contextlib import asynccontextmanager
4
+ from fastapi import FastAPI, APIRouter
5
+ from fastapi.responses import JSONResponse
6
+ from .network.event_queue import NetworkEventQueue
7
+ from .network.response_handler import ResponseHandler
8
+ from .processor.interface import ProcessorInterface
9
+ from .protocol.api_models import (
10
+ PollEvents,
11
+ FetchRids,
12
+ FetchManifests,
13
+ FetchBundles,
14
+ EventsPayload,
15
+ RidsPayload,
16
+ ManifestsPayload,
17
+ BundlesPayload,
18
+ ErrorResponse
19
+ )
20
+ from .protocol.errors import ProtocolError
21
+ from .protocol.envelope import SignedEnvelope
22
+ from .protocol.consts import (
23
+ BROADCAST_EVENTS_PATH,
24
+ POLL_EVENTS_PATH,
25
+ FETCH_RIDS_PATH,
26
+ FETCH_MANIFESTS_PATH,
27
+ FETCH_BUNDLES_PATH
28
+ )
29
+ from .secure import Secure
30
+ from .lifecycle import NodeLifecycle
31
+ from .config import NodeConfig
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ class NodeServer:
37
+ lifecycle: NodeLifecycle
38
+
39
+ def __init__(
40
+ self,
41
+ config: NodeConfig,
42
+ lifecycle: NodeLifecycle,
43
+ secure: Secure,
44
+ processor: ProcessorInterface,
45
+ event_queue: NetworkEventQueue,
46
+ response_handler: ResponseHandler
47
+ ):
48
+ self.config = config
49
+ self.lifecycle = lifecycle
50
+ self.secure = secure
51
+ self.processor = processor
52
+ self.event_queue = event_queue
53
+ self.response_handler = response_handler
54
+ self._build_app()
55
+
56
+ def _build_app(self):
57
+ self.app = FastAPI(
58
+ lifespan=self.lifespan,
59
+ title="KOI-net Protocol API",
60
+ version="1.0.0"
61
+ )
62
+
63
+ self.router = APIRouter(prefix="/koi-net")
64
+ self.app.add_exception_handler(ProtocolError, self.protocol_error_handler)
65
+
66
+ def _add_endpoint(path, func):
67
+ self.router.add_api_route(
68
+ path=path,
69
+ endpoint=self.secure.envelope_handler(func),
70
+ methods=["POST"]
71
+ )
72
+
73
+ _add_endpoint(BROADCAST_EVENTS_PATH, self.broadcast_events)
74
+ _add_endpoint(POLL_EVENTS_PATH, self.poll_events)
75
+ _add_endpoint(FETCH_RIDS_PATH, self.fetch_rids)
76
+ _add_endpoint(FETCH_MANIFESTS_PATH, self.fetch_manifests)
77
+ _add_endpoint(FETCH_BUNDLES_PATH, self.fetch_bundles)
78
+
79
+ self.app.include_router(self.router)
80
+
81
+ def run(self):
82
+ uvicorn.run(
83
+ app=self.app,
84
+ host=self.config.server.host,
85
+ port=self.config.server.port
86
+ )
87
+
88
+ @asynccontextmanager
89
+ async def lifespan(self, app: FastAPI):
90
+ self.lifecycle.start()
91
+ yield
92
+ self.lifecycle.stop()
93
+
94
+ def protocol_error_handler(self, request, exc: ProtocolError):
95
+ logger.info(f"caught protocol error: {exc}")
96
+ resp = ErrorResponse(error=exc.error_type)
97
+ logger.info(f"returning error response: {resp}")
98
+ return JSONResponse(
99
+ status_code=400,
100
+ content=resp.model_dump(mode="json")
101
+ )
102
+
103
+ async def broadcast_events(self, req: SignedEnvelope[EventsPayload]):
104
+ logger.info(f"Request to {BROADCAST_EVENTS_PATH}, received {len(req.payload.events)} event(s)")
105
+ for event in req.payload.events:
106
+ self.processor.handle(event=event, source=req.source_node)
107
+
108
+ async def poll_events(
109
+ self, req: SignedEnvelope[PollEvents]
110
+ ) -> SignedEnvelope[EventsPayload] | ErrorResponse:
111
+ logger.info(f"Request to {POLL_EVENTS_PATH}")
112
+ events = self.event_queue.flush_poll_queue(req.source_node)
113
+ return EventsPayload(events=events)
114
+
115
+ async def fetch_rids(
116
+ self, req: SignedEnvelope[FetchRids]
117
+ ) -> SignedEnvelope[RidsPayload] | ErrorResponse:
118
+ return self.response_handler.fetch_rids(req.payload, req.source_node)
119
+
120
+ async def fetch_manifests(
121
+ self, req: SignedEnvelope[FetchManifests]
122
+ ) -> SignedEnvelope[ManifestsPayload] | ErrorResponse:
123
+ return self.response_handler.fetch_manifests(req.payload, req.source_node)
124
+
125
+ async def fetch_bundles(
126
+ self, req: SignedEnvelope[FetchBundles]
127
+ ) -> SignedEnvelope[BundlesPayload] | ErrorResponse:
128
+ return self.response_handler.fetch_bundles(req.payload, req.source_node)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koi-net
3
- Version: 1.1.0b1
3
+ Version: 1.1.0b3
4
4
  Summary: Implementation of KOI-net protocol in Python
5
5
  Project-URL: Homepage, https://github.com/BlockScience/koi-net/
6
6
  Author-email: Luke Miller <luke@block.science>
@@ -28,19 +28,19 @@ License: MIT License
28
28
  License-File: LICENSE
29
29
  Requires-Python: >=3.10
30
30
  Requires-Dist: cryptography>=45.0.3
31
+ Requires-Dist: fastapi>=0.115.12
31
32
  Requires-Dist: httpx>=0.28.1
32
33
  Requires-Dist: networkx>=3.4.2
33
34
  Requires-Dist: pydantic>=2.10.6
34
35
  Requires-Dist: python-dotenv>=1.1.0
35
36
  Requires-Dist: rid-lib>=3.2.7
36
37
  Requires-Dist: ruamel-yaml>=0.18.10
38
+ Requires-Dist: uvicorn>=0.34.2
37
39
  Provides-Extra: dev
38
40
  Requires-Dist: build; extra == 'dev'
39
41
  Requires-Dist: twine>=6.0; extra == 'dev'
40
42
  Provides-Extra: examples
41
- Requires-Dist: fastapi; extra == 'examples'
42
43
  Requires-Dist: rich; extra == 'examples'
43
- Requires-Dist: uvicorn; extra == 'examples'
44
44
  Description-Content-Type: text/markdown
45
45
 
46
46
  # KOI-net
@@ -1,11 +1,14 @@
1
1
  koi_net/__init__.py,sha256=b0Ze0pZmJAuygpWUFHM6Kvqo3DkU_uzmkptv1EpAArw,31
2
- koi_net/config.py,sha256=Zu6iVPQ1yar9OMZQp-Ez0eYRIoCeDq69eTQyYplQqQc,4057
2
+ koi_net/config.py,sha256=47XbQ59GRYFi4rlsoWKlnzMQATcnK70i3qmKTZAGOQk,4087
3
3
  koi_net/context.py,sha256=JmbpCzusXFq_NCXiUp5Z56N6vpBdYMUK8eOs7ogO68A,1428
4
- koi_net/core.py,sha256=QIYRlvi5BFxaQKYrbI8CGs2yZxf-U6PeJlYBaG6HsLQ,6474
4
+ koi_net/core.py,sha256=jF3xhIhaKrClutmumHO6MjOlA_L5UNU1BUOsxFuHQAI,7068
5
5
  koi_net/default_actions.py,sha256=TkQR9oj9CpO37Gb5bZLmFNl-Q8n3OxGiX4dvxQR7SaA,421
6
6
  koi_net/effector.py,sha256=gSyZgRxQ91X04UL261e2pXWUfBHnQTGtjSHpc2JufxA,4097
7
7
  koi_net/identity.py,sha256=FvIWksGTqwM7HCevIwmo_6l-t-2tnYkaaR4CanZatL4,569
8
+ koi_net/lifecycle.py,sha256=-J5y4i0JdernatLTed8hQbkK26Cs6rm1kZqlx3aQzZA,2727
9
+ koi_net/poller.py,sha256=ZvQcZ0RQhViXVhbIpdTZb7_ql3nG0mTcdBamneZKLpA,1361
8
10
  koi_net/secure.py,sha256=cGNF2assqCaYq0i0fhQBm7aREoAdpY-XVypDsE1ALaU,3970
11
+ koi_net/server.py,sha256=5BVVrgn69r_HMC3c4npWywPsjBDqUnHFWLKdtnfRTbA,4250
9
12
  koi_net/network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
13
  koi_net/network/behavior.py,sha256=NZLvWlrxR0uWriE3ZzCXmocUVccQthy7Xx8E_8KBwsg,1208
11
14
  koi_net/network/error_handler.py,sha256=CrmCpBY2oj4nl7uXrIYusUHDKxPZ1HDuQAtiBSZarRI,1623
@@ -13,7 +16,7 @@ koi_net/network/event_queue.py,sha256=QV1dLOe-H85fNJVkc-e0ZRsUpHTkFcMLMbp3WU5gRN
13
16
  koi_net/network/graph.py,sha256=NLstBsPa9By0luxcTjThnqVd3hxfQdFwn8tWgJ6u4l4,4144
14
17
  koi_net/network/request_handler.py,sha256=77SHLO92gVHTusUXWo89KgjRnxU9vLG_Qi8HxTFtFBg,6376
15
18
  koi_net/network/resolver.py,sha256=coIp4M6k0-8sUfAy4h2NMx_7zCNroWlCHKOj3AXZVhc,5412
16
- koi_net/network/response_handler.py,sha256=tEfzSZWXKCRwUlXhM8Qp3Y6BKTQ4abfi-MrSaatlITI,1980
19
+ koi_net/network/response_handler.py,sha256=__R_EvEpjaMz3PCDvkNgWF_EAHe2nePGk-zK_cT4C4g,2077
17
20
  koi_net/processor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
21
  koi_net/processor/default_handlers.py,sha256=SX1eP740W9LeG-IEoBOmsNrKJfOEDDuEQUSwnJEG_8w,8954
19
22
  koi_net/processor/handler.py,sha256=_loaHjgVGVUxtCQdvAY9dQ0iqiq5co7wB2tK-usuv3Y,2355
@@ -29,7 +32,7 @@ koi_net/protocol/errors.py,sha256=A83QiYe_fJdxW2lsNsLCujWxDr5sk1UmYYd3TGbSNJA,60
29
32
  koi_net/protocol/event.py,sha256=eGgihEj1gliLoQRk8pVB2q_was0AGo-PbT3Hqnpn3oU,1379
30
33
  koi_net/protocol/node.py,sha256=7GQzHORFr9cP4BqJgir6EGSWCskL-yqmvJksIiLfcWU,409
31
34
  koi_net/protocol/secure.py,sha256=Reem9Z4le4uWXM9uczNOdmgVBg8p4YQav-7_c3pZ1CQ,3366
32
- koi_net-1.1.0b1.dist-info/METADATA,sha256=pHwaqM6wXoQpOUINUBlLlmCnSv3nEHF-EbL5x42jf3s,37142
33
- koi_net-1.1.0b1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
34
- koi_net-1.1.0b1.dist-info/licenses/LICENSE,sha256=03mgCL5qth2aD9C3F3qNVs4sFJSpK9kjtYCyOwdSp7s,1069
35
- koi_net-1.1.0b1.dist-info/RECORD,,
35
+ koi_net-1.1.0b3.dist-info/METADATA,sha256=LEE8Js4IHoORcyZ7Hoy6kgggQxwbaYCurbs0AEmnQUs,37118
36
+ koi_net-1.1.0b3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
37
+ koi_net-1.1.0b3.dist-info/licenses/LICENSE,sha256=03mgCL5qth2aD9C3F3qNVs4sFJSpK9kjtYCyOwdSp7s,1069
38
+ koi_net-1.1.0b3.dist-info/RECORD,,