koi-net 1.1.0b8__py3-none-any.whl → 1.2.0b2__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.

Files changed (48) hide show
  1. koi_net/__init__.py +2 -1
  2. koi_net/assembler.py +82 -0
  3. koi_net/cli/__init__.py +1 -0
  4. koi_net/cli/commands.py +99 -0
  5. koi_net/cli/models.py +41 -0
  6. koi_net/config.py +34 -0
  7. koi_net/context.py +11 -28
  8. koi_net/core.py +63 -179
  9. koi_net/default_actions.py +10 -1
  10. koi_net/effector.py +61 -34
  11. koi_net/handshaker.py +39 -0
  12. koi_net/identity.py +2 -3
  13. koi_net/interfaces/entrypoint.py +5 -0
  14. koi_net/interfaces/worker.py +17 -0
  15. koi_net/lifecycle.py +85 -48
  16. koi_net/logger.py +176 -0
  17. koi_net/network/error_handler.py +18 -16
  18. koi_net/network/event_queue.py +17 -185
  19. koi_net/network/graph.py +15 -10
  20. koi_net/network/poll_event_buffer.py +26 -0
  21. koi_net/network/request_handler.py +54 -47
  22. koi_net/network/resolver.py +18 -21
  23. koi_net/network/response_handler.py +79 -15
  24. koi_net/poller.py +18 -9
  25. koi_net/processor/event_worker.py +117 -0
  26. koi_net/processor/handler.py +4 -2
  27. koi_net/processor/{default_handlers.py → handlers.py} +109 -59
  28. koi_net/processor/knowledge_object.py +19 -7
  29. koi_net/processor/kobj_queue.py +51 -0
  30. koi_net/processor/kobj_worker.py +44 -0
  31. koi_net/processor/{knowledge_pipeline.py → pipeline.py} +31 -53
  32. koi_net/protocol/api_models.py +7 -3
  33. koi_net/protocol/envelope.py +5 -6
  34. koi_net/protocol/model_map.py +61 -0
  35. koi_net/protocol/node.py +3 -3
  36. koi_net/protocol/secure.py +8 -8
  37. koi_net/secure.py +33 -13
  38. koi_net/sentry.py +13 -0
  39. koi_net/server.py +44 -78
  40. koi_net/utils.py +18 -0
  41. {koi_net-1.1.0b8.dist-info → koi_net-1.2.0b2.dist-info}/METADATA +8 -3
  42. koi_net-1.2.0b2.dist-info/RECORD +52 -0
  43. koi_net-1.2.0b2.dist-info/entry_points.txt +2 -0
  44. koi_net/actor.py +0 -60
  45. koi_net/processor/interface.py +0 -101
  46. koi_net-1.1.0b8.dist-info/RECORD +0 -38
  47. {koi_net-1.1.0b8.dist-info → koi_net-1.2.0b2.dist-info}/WHEEL +0 -0
  48. {koi_net-1.1.0b8.dist-info → koi_net-1.2.0b2.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,9 @@
1
- import logging
2
- from typing import Callable
3
- from rid_lib.core import RIDType
1
+ import structlog
4
2
  from rid_lib.types import KoiNetEdge, KoiNetNode
5
3
  from rid_lib.ext import Cache
6
4
  from ..protocol.event import EventType
7
5
  from ..network.request_handler import RequestHandler
8
- from ..network.event_queue import NetworkEventQueue
6
+ from ..network.event_queue import EventQueue
9
7
  from ..network.graph import NetworkGraph
10
8
  from ..identity import NodeIdentity
11
9
  from .handler import (
@@ -15,55 +13,36 @@ from .handler import (
15
13
  StopChain
16
14
  )
17
15
  from .knowledge_object import KnowledgeObject
16
+ from ..context import HandlerContext
18
17
 
19
- from typing import TYPE_CHECKING
20
- if TYPE_CHECKING:
21
- from ..context import HandlerContext
22
-
23
- logger = logging.getLogger(__name__)
18
+ log = structlog.stdlib.get_logger()
24
19
 
25
20
 
26
21
  class KnowledgePipeline:
27
- handler_context: "HandlerContext"
22
+ handler_context: HandlerContext
28
23
  cache: Cache
29
24
  identity: NodeIdentity
30
25
  request_handler: RequestHandler
31
- event_queue: NetworkEventQueue
26
+ event_queue: EventQueue
32
27
  graph: NetworkGraph
33
- handlers: list[KnowledgeHandler]
28
+ knowledge_handlers: list[KnowledgeHandler]
34
29
 
35
30
  def __init__(
36
31
  self,
37
- handler_context: "HandlerContext",
32
+ handler_context: HandlerContext,
38
33
  cache: Cache,
39
34
  request_handler: RequestHandler,
40
- event_queue: NetworkEventQueue,
35
+ event_queue: EventQueue,
41
36
  graph: NetworkGraph,
42
- default_handlers: list[KnowledgeHandler] = []
37
+ knowledge_handlers: list[KnowledgeHandler] = []
43
38
  ):
44
39
  self.handler_context = handler_context
45
40
  self.cache = cache
46
41
  self.request_handler = request_handler
47
42
  self.event_queue = event_queue
48
43
  self.graph = graph
49
- self.handlers = default_handlers
44
+ self.knowledge_handlers = knowledge_handlers
50
45
 
51
- def add_handler(self, handler: KnowledgeHandler):
52
- self.handlers.append(handler)
53
-
54
- def register_handler(
55
- self,
56
- handler_type: HandlerType,
57
- rid_types: list[RIDType] | None = None,
58
- event_types: list[EventType | None] | None = None
59
- ):
60
- """Assigns decorated function as handler for this processor."""
61
- def decorator(func: Callable) -> Callable:
62
- handler = KnowledgeHandler(func, handler_type, rid_types, event_types)
63
- self.add_handler(handler)
64
- return func
65
- return decorator
66
-
67
46
  def call_handler_chain(
68
47
  self,
69
48
  handler_type: HandlerType,
@@ -79,7 +58,7 @@ class KnowledgePipeline:
79
58
  Handlers will only be called in the chain if their handler and RID type match that of the inputted knowledge object.
80
59
  """
81
60
 
82
- for handler in self.handlers:
61
+ for handler in self.knowledge_handlers:
83
62
  if handler_type != handler.handler_type:
84
63
  continue
85
64
 
@@ -89,7 +68,7 @@ class KnowledgePipeline:
89
68
  if handler.event_types and kobj.event_type not in handler.event_types:
90
69
  continue
91
70
 
92
- logger.debug(f"Calling {handler_type} handler '{handler.func.__name__}'")
71
+ log.debug(f"Calling {handler_type} handler '{handler.func.__name__}'")
93
72
 
94
73
  resp = handler.func(
95
74
  ctx=self.handler_context,
@@ -98,7 +77,7 @@ class KnowledgePipeline:
98
77
 
99
78
  # stops handler chain execution
100
79
  if resp is STOP_CHAIN:
101
- logger.debug(f"Handler chain stopped by {handler.func.__name__}")
80
+ log.debug(f"Handler chain stopped by {handler.func.__name__}")
102
81
  return STOP_CHAIN
103
82
  # kobj unmodified
104
83
  elif resp is None:
@@ -106,7 +85,7 @@ class KnowledgePipeline:
106
85
  # kobj modified by handler
107
86
  elif isinstance(resp, KnowledgeObject):
108
87
  kobj = resp
109
- logger.debug(f"Knowledge object modified by {handler.func.__name__}")
88
+ log.debug(f"Knowledge object modified by {handler.func.__name__}")
110
89
  else:
111
90
  raise ValueError(f"Handler {handler.func.__name__} returned invalid response '{resp}'")
112
91
 
@@ -125,36 +104,36 @@ class KnowledgePipeline:
125
104
  The pipeline may be stopped by any point by a single handler returning the `STOP_CHAIN` sentinel. In that case, the process will exit immediately. Further handlers of that type and later handler chains will not be called.
126
105
  """
127
106
 
128
- logger.debug(f"Handling {kobj!r}")
107
+ log.debug(f"Handling {kobj!r}")
129
108
  kobj = self.call_handler_chain(HandlerType.RID, kobj)
130
109
  if kobj is STOP_CHAIN: return
131
110
 
132
111
  if kobj.event_type == EventType.FORGET:
133
112
  bundle = self.cache.read(kobj.rid)
134
113
  if not bundle:
135
- logger.debug("Local bundle not found")
114
+ log.debug("Local bundle not found")
136
115
  return
137
116
 
138
117
  # the bundle (to be deleted) attached to kobj for downstream analysis
139
- logger.debug("Adding local bundle (to be deleted) to knowledge object")
118
+ log.debug("Adding local bundle (to be deleted) to knowledge object")
140
119
  kobj.manifest = bundle.manifest
141
120
  kobj.contents = bundle.contents
142
121
 
143
122
  else:
144
123
  # attempt to retrieve manifest
145
124
  if not kobj.manifest:
146
- logger.debug("Manifest not found")
125
+ log.debug("Manifest not found")
147
126
  if not kobj.source:
148
127
  return
149
128
 
150
- logger.debug("Attempting to fetch remote manifest from source")
129
+ log.debug("Attempting to fetch remote manifest from source")
151
130
  payload = self.request_handler.fetch_manifests(
152
131
  node=kobj.source,
153
132
  rids=[kobj.rid]
154
133
  )
155
134
 
156
135
  if not payload.manifests:
157
- logger.debug("Failed to find manifest")
136
+ log.debug("Failed to find manifest")
158
137
  return
159
138
 
160
139
  kobj.manifest = payload.manifests[0]
@@ -164,24 +143,24 @@ class KnowledgePipeline:
164
143
 
165
144
  # attempt to retrieve bundle
166
145
  if not kobj.bundle:
167
- logger.debug("Bundle not found")
146
+ log.debug("Bundle not found")
168
147
  if kobj.source is None:
169
148
  return
170
149
 
171
- logger.debug("Attempting to fetch remote bundle from source")
150
+ log.debug("Attempting to fetch remote bundle from source")
172
151
  payload = self.request_handler.fetch_bundles(
173
152
  node=kobj.source,
174
153
  rids=[kobj.rid]
175
154
  )
176
155
 
177
156
  if not payload.bundles:
178
- logger.debug("Failed to find bundle")
157
+ log.debug("Failed to find bundle")
179
158
  return
180
159
 
181
160
  bundle = payload.bundles[0]
182
161
 
183
162
  if kobj.manifest != bundle.manifest:
184
- logger.warning("Retrieved bundle contains a different manifest")
163
+ log.warning("Retrieved bundle contains a different manifest")
185
164
 
186
165
  kobj.manifest = bundle.manifest
187
166
  kobj.contents = bundle.contents
@@ -190,31 +169,30 @@ class KnowledgePipeline:
190
169
  if kobj is STOP_CHAIN: return
191
170
 
192
171
  if kobj.normalized_event_type in (EventType.UPDATE, EventType.NEW):
193
- logger.info(f"Writing to cache: {kobj!r}")
172
+ log.info(f"Writing to cache: {kobj!r}")
194
173
  self.cache.write(kobj.bundle)
195
174
 
196
175
  elif kobj.normalized_event_type == EventType.FORGET:
197
- logger.info(f"Deleting from cache: {kobj!r}")
176
+ log.info(f"Deleting from cache: {kobj!r}")
198
177
  self.cache.delete(kobj.rid)
199
178
 
200
179
  else:
201
- logger.debug("Normalized event type was never set, no cache or network operations will occur")
180
+ log.debug("Normalized event type was never set, no cache or network operations will occur")
202
181
  return
203
182
 
204
183
  if type(kobj.rid) in (KoiNetNode, KoiNetEdge):
205
- logger.debug("Change to node or edge, regenerating network graph")
184
+ log.debug("Change to node or edge, regenerating network graph")
206
185
  self.graph.generate()
207
186
 
208
187
  kobj = self.call_handler_chain(HandlerType.Network, kobj)
209
188
  if kobj is STOP_CHAIN: return
210
189
 
211
190
  if kobj.network_targets:
212
- logger.debug(f"Broadcasting event to {len(kobj.network_targets)} network target(s)")
191
+ log.debug(f"Broadcasting event to {len(kobj.network_targets)} network target(s)")
213
192
  else:
214
- logger.debug("No network targets set")
193
+ log.debug("No network targets set")
215
194
 
216
195
  for node in kobj.network_targets:
217
196
  self.event_queue.push_event_to(kobj.normalized_event, node)
218
- self.event_queue.flush_webhook_queue(node)
219
197
 
220
198
  kobj = self.call_handler_chain(HandlerType.Final, kobj)
@@ -1,6 +1,6 @@
1
- """Pydantic models for request and response/payload objects in the KOI-net API."""
1
+ """Pydantic models for request and response objects in the KOI-net API."""
2
2
 
3
- from typing import Literal
3
+ from typing import Annotated, Literal
4
4
  from pydantic import BaseModel, Field
5
5
  from rid_lib import RID, RIDType
6
6
  from rid_lib.ext import Bundle, Manifest
@@ -59,4 +59,8 @@ class ErrorResponse(BaseModel):
59
59
  # TYPES
60
60
 
61
61
  type RequestModels = EventsPayload | PollEvents | FetchRids | FetchManifests | FetchBundles
62
- type ResponseModels = RidsPayload | ManifestsPayload | BundlesPayload | EventsPayload | ErrorResponse
62
+ type ResponseModels = RidsPayload | ManifestsPayload | BundlesPayload | EventsPayload | ErrorResponse
63
+ type ApiModels = Annotated[
64
+ RequestModels | ResponseModels,
65
+ Field(discriminator="type")
66
+ ]
@@ -1,4 +1,4 @@
1
- import logging
1
+ import structlog
2
2
  from typing import Generic, TypeVar
3
3
  from pydantic import BaseModel, ConfigDict
4
4
  from rid_lib.types import KoiNetNode
@@ -6,8 +6,7 @@ from rid_lib.types import KoiNetNode
6
6
  from .secure import PrivateKey, PublicKey
7
7
  from .api_models import RequestModels, ResponseModels
8
8
 
9
-
10
- logger = logging.getLogger(__name__)
9
+ log = structlog.stdlib.get_logger()
11
10
 
12
11
 
13
12
  T = TypeVar("T", bound=RequestModels | ResponseModels)
@@ -28,7 +27,7 @@ class SignedEnvelope(BaseModel, Generic[T]):
28
27
  target_node=self.target_node
29
28
  )
30
29
 
31
- logger.debug(f"Verifying envelope: {unsigned_envelope.model_dump_json(exclude_none=True)}")
30
+ log.debug(f"Verifying envelope: {unsigned_envelope.model_dump_json(exclude_none=True)}")
32
31
 
33
32
  pub_key.verify(
34
33
  self.signature,
@@ -43,8 +42,8 @@ class UnsignedEnvelope(BaseModel, Generic[T]):
43
42
  target_node: KoiNetNode
44
43
 
45
44
  def sign_with(self, priv_key: PrivateKey) -> SignedEnvelope[T]:
46
- logger.debug(f"Signing envelope: {self.model_dump_json(exclude_none=True)}")
47
- logger.debug(f"Type: [{type(self.payload)}]")
45
+ log.debug(f"Signing envelope: {self.model_dump_json(exclude_none=True)}")
46
+ log.debug(f"Type: [{type(self.payload)}]")
48
47
 
49
48
  signature = priv_key.sign(
50
49
  self.model_dump_json(exclude_none=True).encode()
@@ -0,0 +1,61 @@
1
+ from typing import NamedTuple
2
+ from pydantic import BaseModel
3
+ from .envelope import SignedEnvelope
4
+ from .consts import (
5
+ BROADCAST_EVENTS_PATH,
6
+ POLL_EVENTS_PATH,
7
+ FETCH_BUNDLES_PATH,
8
+ FETCH_MANIFESTS_PATH,
9
+ FETCH_RIDS_PATH
10
+ )
11
+ from .api_models import (
12
+ EventsPayload,
13
+ PollEvents,
14
+ FetchBundles,
15
+ BundlesPayload,
16
+ FetchManifests,
17
+ ManifestsPayload,
18
+ FetchRids,
19
+ RidsPayload
20
+ )
21
+
22
+
23
+ class Models(NamedTuple):
24
+ request: type[BaseModel]
25
+ response: type[BaseModel] | None
26
+ request_envelope: type[SignedEnvelope]
27
+ response_envelope: type[SignedEnvelope] | None
28
+
29
+
30
+ API_MODEL_MAP: dict[str, Models] = {
31
+ BROADCAST_EVENTS_PATH: Models(
32
+ request=EventsPayload,
33
+ response=None,
34
+ request_envelope=SignedEnvelope[EventsPayload],
35
+ response_envelope=None
36
+ ),
37
+ POLL_EVENTS_PATH: Models(
38
+ request=PollEvents,
39
+ response=EventsPayload,
40
+ request_envelope=SignedEnvelope[PollEvents],
41
+ response_envelope=SignedEnvelope[EventsPayload]
42
+ ),
43
+ FETCH_BUNDLES_PATH: Models(
44
+ request=FetchBundles,
45
+ response=BundlesPayload,
46
+ request_envelope=SignedEnvelope[FetchBundles],
47
+ response_envelope=SignedEnvelope[BundlesPayload]
48
+ ),
49
+ FETCH_MANIFESTS_PATH: Models(
50
+ request=FetchManifests,
51
+ response=ManifestsPayload,
52
+ request_envelope=SignedEnvelope[FetchManifests],
53
+ response_envelope=SignedEnvelope[ManifestsPayload]
54
+ ),
55
+ FETCH_RIDS_PATH: Models(
56
+ request=FetchRids,
57
+ response=RidsPayload,
58
+ request_envelope=SignedEnvelope[FetchRids],
59
+ response_envelope=SignedEnvelope[RidsPayload]
60
+ )
61
+ }
koi_net/protocol/node.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from enum import StrEnum
2
- from pydantic import BaseModel
2
+ from pydantic import BaseModel, Field
3
3
  from rid_lib import RIDType
4
4
 
5
5
 
@@ -8,8 +8,8 @@ class NodeType(StrEnum):
8
8
  PARTIAL = "PARTIAL"
9
9
 
10
10
  class NodeProvides(BaseModel):
11
- event: list[RIDType] = []
12
- state: list[RIDType] = []
11
+ event: list[RIDType] = Field(default_factory=list)
12
+ state: list[RIDType] = Field(default_factory=list)
13
13
 
14
14
  class NodeProfile(BaseModel):
15
15
  base_url: str | None = None
@@ -1,4 +1,4 @@
1
- import logging
1
+ import structlog
2
2
  from base64 import b64decode, b64encode
3
3
  from cryptography.hazmat.primitives import hashes
4
4
  from cryptography.hazmat.primitives.asymmetric import ec
@@ -9,7 +9,7 @@ from cryptography.hazmat.primitives.asymmetric.utils import (
9
9
  encode_dss_signature
10
10
  )
11
11
 
12
- logger = logging.getLogger(__name__)
12
+ log = structlog.stdlib.get_logger()
13
13
 
14
14
 
15
15
  def der_to_raw_signature(der_signature: bytes, curve=ec.SECP256R1()) -> bytes:
@@ -91,9 +91,9 @@ class PrivateKey:
91
91
 
92
92
  signature = b64encode(raw_signature_bytes).decode()
93
93
 
94
- logger.debug(f"Signing message with [{self.public_key().to_der()}]")
95
- logger.debug(f"hash: {hashed_message}")
96
- logger.debug(f"signature: {signature}")
94
+ log.debug(f"Signing message with [{self.public_key().to_der()}]")
95
+ log.debug(f"hash: {hashed_message}")
96
+ log.debug(f"signature: {signature}")
97
97
 
98
98
  return signature
99
99
 
@@ -144,9 +144,9 @@ class PublicKey:
144
144
  # print()
145
145
  # print(message.decode())
146
146
 
147
- # logger.debug(f"Verifying message with [{self.to_der()}]")
148
- # logger.debug(f"hash: {hashed_message}")
149
- # logger.debug(f"signature: {signature}")
147
+ # log.debug(f"Verifying message with [{self.to_der()}]")
148
+ # log.debug(f"hash: {hashed_message}")
149
+ # log.debug(f"signature: {signature}")
150
150
 
151
151
  raw_signature_bytes = b64decode(signature)
152
152
  der_signature_bytes = raw_to_der_signature(raw_signature_bytes)
koi_net/secure.py CHANGED
@@ -1,13 +1,14 @@
1
- import logging
1
+ import structlog
2
2
  from functools import wraps
3
3
 
4
4
  import cryptography.exceptions
5
- from rid_lib.ext import Bundle
5
+ from rid_lib.ext import Bundle, Cache
6
6
  from rid_lib.ext.utils import sha256_hash
7
+ from rid_lib.types import KoiNetNode
7
8
  from .identity import NodeIdentity
8
9
  from .protocol.envelope import UnsignedEnvelope, SignedEnvelope
9
10
  from .protocol.secure import PublicKey
10
- from .protocol.api_models import EventsPayload
11
+ from .protocol.api_models import ApiModels, EventsPayload
11
12
  from .protocol.event import EventType
12
13
  from .protocol.node import NodeProfile
13
14
  from .protocol.secure import PrivateKey
@@ -17,31 +18,32 @@ from .protocol.errors import (
17
18
  InvalidSignatureError,
18
19
  InvalidTargetError
19
20
  )
20
- from .effector import Effector
21
21
  from .config import NodeConfig
22
22
 
23
- logger = logging.getLogger(__name__)
23
+ log = structlog.stdlib.get_logger()
24
24
 
25
25
 
26
26
  class Secure:
27
+ """Subsystem handling secure protocol logic."""
27
28
  identity: NodeIdentity
28
- effector: Effector
29
+ cache: Cache
29
30
  config: NodeConfig
30
31
  priv_key: PrivateKey
31
32
 
32
33
  def __init__(
33
34
  self,
34
35
  identity: NodeIdentity,
35
- effector: Effector,
36
+ cache: Cache,
36
37
  config: NodeConfig
37
38
  ):
38
39
  self.identity = identity
39
- self.effector = effector
40
+ self.cache = cache
40
41
  self.config = config
41
42
 
42
43
  self.priv_key = self._load_priv_key()
43
44
 
44
45
  def _load_priv_key(self) -> PrivateKey:
46
+ """Loads private key from PEM file path in config."""
45
47
  with open(self.config.koi_net.private_key_pem_path, "r") as f:
46
48
  priv_key_pem = f.read()
47
49
 
@@ -51,6 +53,14 @@ class Secure:
51
53
  )
52
54
 
53
55
  def _handle_unknown_node(self, envelope: SignedEnvelope) -> Bundle | None:
56
+ """Attempts to find node profile in proided envelope.
57
+
58
+ If an unknown node sends an envelope, it may still be able to be
59
+ validated if that envelope contains their node profile. This is
60
+ essential for allowing unknown nodes to handshake and introduce
61
+ themselves. Only an `EventsPayload` contain a `NEW` event for a
62
+ node profile for the source node is permissible.
63
+ """
54
64
  if type(envelope.payload) != EventsPayload:
55
65
  return None
56
66
 
@@ -64,7 +74,10 @@ class Secure:
64
74
  return event.bundle
65
75
  return None
66
76
 
67
- def create_envelope(self, payload, target) -> SignedEnvelope:
77
+ def create_envelope(
78
+ self, payload: ApiModels, target: KoiNetNode
79
+ ) -> SignedEnvelope:
80
+ """Returns signed envelope to target from provided payload."""
68
81
  return UnsignedEnvelope(
69
82
  payload=payload,
70
83
  source_node=self.identity.rid,
@@ -72,8 +85,10 @@ class Secure:
72
85
  ).sign_with(self.priv_key)
73
86
 
74
87
  def validate_envelope(self, envelope: SignedEnvelope):
88
+ """Validates signed envelope from another node."""
89
+
75
90
  node_bundle = (
76
- self.effector.deref(envelope.source_node) or
91
+ self.cache.read(envelope.source_node) or
77
92
  self._handle_unknown_node(envelope)
78
93
  )
79
94
 
@@ -98,17 +113,22 @@ class Secure:
98
113
  raise InvalidTargetError(f"Envelope target {envelope.target_node!r} is not me")
99
114
 
100
115
  def envelope_handler(self, func):
116
+ """Wrapper function validates envelopes for server endpoints.
117
+
118
+ Validates incoming envelope and passes payload to endpoint
119
+ handler. Resulting payload is returned as a signed envelope.
120
+ """
101
121
  @wraps(func)
102
122
  async def wrapper(req: SignedEnvelope, *args, **kwargs) -> SignedEnvelope | None:
103
- logger.info("Validating envelope")
123
+ log.info("Validating envelope")
104
124
 
105
125
  self.validate_envelope(req)
106
- logger.info("Calling endpoint handler")
126
+ log.info("Calling endpoint handler")
107
127
 
108
128
  result = await func(req, *args, **kwargs)
109
129
 
110
130
  if result is not None:
111
- logger.info("Creating response envelope")
131
+ log.info("Creating response envelope")
112
132
  return self.create_envelope(
113
133
  payload=result,
114
134
  target=req.source_node
koi_net/sentry.py ADDED
@@ -0,0 +1,13 @@
1
+ # import sentry_sdk
2
+ # from sentry_sdk.integrations.logging import LoggingIntegration
3
+
4
+ # sentry_sdk.init(
5
+ # dsn="https://7bbafef3c7dbd652506db3cb2aca9f98@o4510149352357888.ingest.us.sentry.io/4510149355765760",
6
+ # # Add data like request headers and IP for users,
7
+ # # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info
8
+ # send_default_pii=True,
9
+ # enable_logs=True,
10
+ # integrations=[
11
+ # LoggingIntegration(sentry_logs_level=None)
12
+ # ]
13
+ # )