koi-net 1.0.0b16__py3-none-any.whl → 1.0.0b18__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.

Potentially problematic release.


This version of koi-net might be problematic. Click here for more details.

koi_net/config.py CHANGED
@@ -13,7 +13,7 @@ class ServerConfig(BaseModel):
13
13
  path: str | None = "/koi-net"
14
14
 
15
15
  @property
16
- def url(self):
16
+ def url(self) -> str:
17
17
  return f"http://{self.host}:{self.port}{self.path or ''}"
18
18
 
19
19
  class KoiNetConfig(BaseModel):
@@ -173,7 +173,7 @@ class NetworkInterface(Generic[ConfigType]):
173
173
  self.request_handler.broadcast_events(node, events=events)
174
174
  return True
175
175
  except httpx.ConnectError:
176
- logger.warning("Broadcast failed, dropping node")
176
+ logger.warning("Broadcast failed")
177
177
  for event in events:
178
178
  self.push_event_to(event, node)
179
179
  return False
@@ -134,6 +134,10 @@ def coordinator_contact(processor: ProcessorInterface, kobj: KnowledgeObject):
134
134
  if KoiNetNode not in node_profile.provides.event:
135
135
  return
136
136
 
137
+ # prevents coordinators from attempting to form a self loop
138
+ if kobj.rid == processor.identity.rid:
139
+ return
140
+
137
141
  # already have an edge established
138
142
  if processor.network.graph.get_edge_profile(
139
143
  source=kobj.rid,
@@ -229,9 +229,7 @@ class ProcessorInterface():
229
229
 
230
230
  for node in kobj.network_targets:
231
231
  self.network.push_event_to(kobj.normalized_event, node)
232
- if not self.network.flush_webhook_queue(node):
233
- logger.warning("Dropping unresponsive node")
234
- self.handle(rid=node, event_type=EventType.FORGET)
232
+ self.network.flush_webhook_queue(node)
235
233
 
236
234
  kobj = self.call_handler_chain(HandlerType.Final, kobj)
237
235
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: koi-net
3
- Version: 1.0.0b16
3
+ Version: 1.0.0b18
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>
@@ -150,36 +150,56 @@ Your first decision will be whether to setup a partial or full node:
150
150
  - Partial nodes only need to indicate their type, and optionally the RID types of events they provide.
151
151
  - Full nodes need to indicate their type, the base URL for their KOI-net API, and optionally the RID types of events and state they provide.
152
152
 
153
+ Nodes are configured using the provided `NodeConfig` class. Defaults can be set as shown below, and will automatically load from and save to YAML files. See the `koi_net.config` module for more info.
154
+
153
155
  ### Partial Node
154
156
  ```python
155
157
  from koi_net import NodeInterface
156
158
  from koi_net.protocol.node import NodeProfile, NodeProvides, NodeType
157
-
158
- node = NodeInterface(
159
- name="mypartialnode",
160
- profile=NodeProfile(
161
- node_type=NodeType.PARTIAL,
162
- provides=NodeProvides(
163
- event=[]
159
+ from koi_net.config import NodeConfig, KoiNetConfig
160
+
161
+ class CoordinatorNodeConfig(NodeConfig):
162
+ koi_net: KoiNetConfig | None = Field(default_factory = lambda:
163
+ KoiNetConfig(
164
+ node_name="coordinator",
165
+ node_profile=NodeProfile(
166
+ node_type=NodeType.FULL
167
+ ),
168
+ cache_directory_path=".basic_partial_rid_cache",
169
+ event_queues_path="basic_partial_event_queues.json",
170
+ first_contact="http://127.0.0.1:8000/koi-net"
164
171
  )
165
172
  )
173
+
174
+
175
+ node = NodeInterface(
176
+ config=CoordinatorNodeConfig.load_from_yaml("basical_partial_config.yaml")
166
177
  )
167
178
  ```
168
179
  ### Full Node
169
180
  ```python
170
181
  from koi_net import NodeInterface
171
182
  from koi_net.protocol.node import NodeProfile, NodeProvides, NodeType
183
+ from koi_net.config import NodeConfig, KoiNetConfig
184
+
185
+ class CoordinatorNodeConfig(NodeConfig):
186
+ koi_net: KoiNetConfig | None = Field(default_factory = lambda:
187
+ KoiNetConfig(
188
+ node_name="coordinator",
189
+ node_profile=NodeProfile(
190
+ node_type=NodeType.FULL,
191
+ provides=NodeProvides(
192
+ event=[KoiNetNode, KoiNetEdge],
193
+ state=[KoiNetNode, KoiNetEdge]
194
+ )
195
+ ),
196
+ cache_directory_path=".coordinator_rid_cache",
197
+ event_queues_path="coordinator_event_queues.json"
198
+ )
199
+ )
172
200
 
173
201
  node = NodeInterface(
174
- name="myfullnode",
175
- profile=NodeProfile(
176
- base_url="http://127.0.0.1:8000",
177
- node_type=NodeType.FULL,
178
- provides=NodeProvides(
179
- event=[],
180
- state=[]
181
- )
182
- ),
202
+ config=CoordinatorNodeConfig.load_from_yaml("coordinator_config.yaml"),
183
203
  use_kobj_processor_thread=True
184
204
  )
185
205
  ```
@@ -402,6 +422,7 @@ The default configuration provides four default handlers which will take precede
402
422
  ```python
403
423
  from koi_net import NodeInterface
404
424
  from koi_net.protocol.node import NodeProfile, NodeProvides, NodeType
425
+ from koi_net.config import NodeConfig
405
426
  from koi_net.processor.default_handlers import (
406
427
  basic_rid_handler,
407
428
  basic_manifest_handler,
@@ -410,13 +431,7 @@ from koi_net.processor.default_handlers import (
410
431
  )
411
432
 
412
433
  node = NodeInterface(
413
- name="mypartialnode",
414
- profile=NodeProfile(
415
- node_type=NodeType.PARTIAL,
416
- provides=NodeProvides(
417
- event=[]
418
- )
419
- ),
434
+ config=NodeConfig.load_from_yaml(),
420
435
  handlers=[
421
436
  basic_rid_handler,
422
437
  basic_manifest_handler,
@@ -437,23 +452,21 @@ This section provides high level explanations of the Python implementation. More
437
452
  The node class mostly acts as a container for other classes with more specialized behavior, with special functions that should be called to start up and shut down a node. We'll take a look at each of these components in turn, but here is the class stub:
438
453
  ```python
439
454
  class NodeInterface:
455
+ config: ConfigType
440
456
  cache: Cache
441
457
  identity: NodeIdentity
442
458
  network: NetworkInterface
443
459
  processor: ProcessorInterface
444
- first_contact: str
460
+
445
461
  use_kobj_processor_thread: bool
446
-
462
+
447
463
  def __init__(
448
464
  self,
449
- name: str,
450
- profile: NodeProfile,
451
- identity_file_path: str = "identity.json",
452
- event_queues_file_path: str = "event_queues.json",
453
- cache_directory_path: str = "rid_cache",
465
+ config: ConfigType,
454
466
  use_kobj_processor_thread: bool = False,
455
- first_contact: str | None = None,
467
+
456
468
  handlers: list[KnowledgeHandler] | None = None,
469
+
457
470
  cache: Cache | None = None,
458
471
  network: NetworkInterface | None = None,
459
472
  processor: ProcessorInterface | None = None
@@ -462,7 +475,58 @@ class NodeInterface:
462
475
  def start(self): ...
463
476
  def stop(self): ...
464
477
  ```
465
- As you can see, only a name and profile are required. The other fields allow for additional customization if needed.
478
+ As you can see, only a node config is required, all other fields are optional.
479
+
480
+ ## Node Config
481
+
482
+ The node config class is a mix of configuration groups providing basic shared behavior across nodes through a standard interface. The class is implemented as Pydantic model, but provides functions to load from and save to a YAML file, the expected format within a node repo.
483
+
484
+ ```python
485
+ class ServerConfig(BaseModel):
486
+ host: str | None = "127.0.0.1"
487
+ port: int | None = 8000
488
+ path: str | None = "/koi-net"
489
+
490
+ @property
491
+ def url(self) -> str: ...
492
+
493
+ class KoiNetConfig(BaseModel):
494
+ node_name: str
495
+ node_rid: KoiNetNode | None = None
496
+ node_profile: NodeProfile
497
+
498
+ cache_directory_path: str | None = ".rid_cache"
499
+ event_queues_path: str | None = "event_queues.json"
500
+
501
+ first_contact: str | None = None
502
+
503
+ class EnvConfig(BaseModel):
504
+ ...
505
+
506
+ class NodeConfig(BaseModel):
507
+ server: ServerConfig | None = Field(default_factory=ServerConfig)
508
+ koi_net: KoiNetConfig
509
+
510
+ @classmethod
511
+ def load_from_yaml(
512
+ cls,
513
+ file_path: str = "config.yaml",
514
+ generate_missing: bool = True
515
+ ): ...
516
+
517
+ def save_to_yaml(self): ...
518
+ ```
519
+
520
+ Nodes are expected to create new node config classes inheriting from `NodeConfig`. You may want to set a default KoiNetConfig (see examples) to allow for a default config to be generated if not provided by the user. Environment variables can be handled by inheriting from the `EnvConfig` class and adding new string fields. The value of this field should be equivalent to the environment variable name, for example:
521
+
522
+ ```python
523
+ class SlackEnvConfig(EnvConfig):
524
+ slack_bot_token: str | None = "SLACK_BOT_TOKEN"
525
+ slack_signing_secret: str | None = "SLACK_SIGNING_SECRET"
526
+ slack_app_token: str | None = "SLACK_APP_TOKEN"
527
+ ```
528
+
529
+ This special config class will automatically load in the variables from the current environment, or local `.env` file. Beyond these base config classes, you are free to add your own config groups. See `config.py` in the [koi-net-slack-sensor-node](https://github.com/BlockScience/koi-net-slack-sensor-node/blob/main/slack_sensor_node/config.py) repo for a more complete example.
466
530
 
467
531
  ## Node Identity
468
532
  The `NodeIdentity` class provides easy access to a node's own RID, profile, and bundle. It provides access to the following properties after initialization, accessed with `node.identity`.
@@ -472,7 +536,7 @@ class NodeIdentity:
472
536
  profile: NodeProfile
473
537
  bundle: Bundle
474
538
  ```
475
- This it what is initialized from the required `name` and `profile` fields in the `NodeInterface` constructor. Node RIDs take the form of `orn:koi-net.node:<name>+<uuid>`, and are generated on first use to the identity JSON file along with a the node profile.
539
+ This it what is initialized from the required `name` and `profile` fields in the `NodeConfig` class. Node RIDs take the form of `orn:koi-net.node:<name>+<uuid>`, and are generated on first use to the identity JSON file along with a the node profile.
476
540
 
477
541
  ## Network Interface
478
542
  The `NetworkInterface` class provides access to high level network actions, and contains several other network related classes. It is accessed with `node.network`.
@@ -1,16 +1,16 @@
1
1
  koi_net/__init__.py,sha256=b0Ze0pZmJAuygpWUFHM6Kvqo3DkU_uzmkptv1EpAArw,31
2
- koi_net/config.py,sha256=35RNSOcWxnJzasPAkYabFWcKyDR-2kM1NTrq_fYOkm0,3153
2
+ koi_net/config.py,sha256=TIKb1kFTcEysqwdHp6yCNpcXeS84dlprcb-f0z2jF0Y,3160
3
3
  koi_net/core.py,sha256=IO8kqiNMYVeuNzilq7eHBA7IulsxRjrCbWnIAx6_abA,4406
4
4
  koi_net/identity.py,sha256=muc5vuQ8zUOebhwAB3-ql6W2pgQETiYXXQAFBv8bLyg,1288
5
5
  koi_net/network/__init__.py,sha256=r_RN-q_mDYC-2RAkN-lJoMUX76TXyfEUc_MVKW87z0g,39
6
6
  koi_net/network/graph.py,sha256=dsfPuHUTkCzlj0QeL0e7dgp7-FR5_AGP7eE8EpBPhC0,4710
7
- koi_net/network/interface.py,sha256=CKZACkUxG6Y4GV8XR16lhFLzRpXOw59hx7sFewZ_35w,10466
7
+ koi_net/network/interface.py,sha256=icpl0rzpC5yV86BQBAbjAjK7AWhgCFoyFLm_Fjf1mCI,10451
8
8
  koi_net/network/request_handler.py,sha256=66gjX2x4UnBWZYwKLjp_3WkhL-ekhR3VAyfGviHTcUs,4790
9
9
  koi_net/network/response_handler.py,sha256=CAwici2Etj9ESndERXdtYkMlc4gWHz_xc7jHgY2Qjcg,1830
10
10
  koi_net/processor/__init__.py,sha256=x4fAY0hvQEDcpfdTB3POIzxBQjYAtn0qQazPo1Xm0m4,41
11
- koi_net/processor/default_handlers.py,sha256=f8Yl21lLGMa_oW51bf8sBuunfP9_rmiSu32T-rZ4kUY,8542
11
+ koi_net/processor/default_handlers.py,sha256=dP64lEJ64BJ7H8PhFK-GZI1pv51tVVINV4jAgcOtOhc,8669
12
12
  koi_net/processor/handler.py,sha256=7X6M6PP8m6-xdtsP1y4QO83g_MN5VSszNNikprITK80,2523
13
- koi_net/processor/interface.py,sha256=3ofjBFz3FVjESABXJ1aC_4ESTuLFMHyl5d8uWz5QsFA,13012
13
+ koi_net/processor/interface.py,sha256=Kyw4SQos_1WdcPJJe-j2w4xDIfwtmpF4mfGlkRVRqUI,12876
14
14
  koi_net/processor/knowledge_object.py,sha256=RCgzkILsWm1Jw_NkSu4jTRYA9Ugga6mJ4jqKWwketQs,4090
15
15
  koi_net/protocol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  koi_net/protocol/api_models.py,sha256=DYDKCRD2Uja633bBAyTsaxyb1oF9pX9yQ9NpNAbkczo,1070
@@ -19,7 +19,7 @@ koi_net/protocol/edge.py,sha256=CcmvIY4P1HEBdKNJ4wFRDmwYMRMss24Besmbi7ZRFxQ,427
19
19
  koi_net/protocol/event.py,sha256=HxzLN-iCXPyr2YzrswMIkgZYeUdFbBpa5v98dAB06lQ,1328
20
20
  koi_net/protocol/helpers.py,sha256=8ZkQrjb_G0QEaMIKe9wkFOBonl1bkmemx_pwKMwIiLg,695
21
21
  koi_net/protocol/node.py,sha256=2HhCh3LdBLlY2Z_kXNmKHzpVLKbP_ODob3HjHayFQtM,375
22
- koi_net-1.0.0b16.dist-info/METADATA,sha256=YQ_kvSI7441neMoeU6uy5SMpt1Lo2ZwKx_KsIAbu0WE,34203
23
- koi_net-1.0.0b16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
24
- koi_net-1.0.0b16.dist-info/licenses/LICENSE,sha256=03mgCL5qth2aD9C3F3qNVs4sFJSpK9kjtYCyOwdSp7s,1069
25
- koi_net-1.0.0b16.dist-info/RECORD,,
22
+ koi_net-1.0.0b18.dist-info/METADATA,sha256=Cf5mZOtRY8ymPGziisVLZycO1ZZ1gjr7daCttr7mOW4,37107
23
+ koi_net-1.0.0b18.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
24
+ koi_net-1.0.0b18.dist-info/licenses/LICENSE,sha256=03mgCL5qth2aD9C3F3qNVs4sFJSpK9kjtYCyOwdSp7s,1069
25
+ koi_net-1.0.0b18.dist-info/RECORD,,