bedger 0.0.5__py3-none-any.whl → 0.0.7__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 bedger might be problematic. Click here for more details.
- bedger/edge/client.py +104 -0
- bedger/edge/entities/__init__.py +3 -2
- bedger/edge/entities/device_event.py +44 -0
- bedger/edge/entities/severity.py +0 -1
- bedger/edge/errors.py +91 -5
- bedger-0.0.7.dist-info/METADATA +13 -0
- bedger-0.0.7.dist-info/RECORD +12 -0
- {bedger-0.0.5.dist-info → bedger-0.0.7.dist-info}/WHEEL +1 -1
- bedger/edge/connection.py +0 -123
- bedger/edge/entities/message.py +0 -32
- bedger-0.0.5.dist-info/METADATA +0 -105
- bedger-0.0.5.dist-info/RECORD +0 -12
- {bedger-0.0.5.dist-info → bedger-0.0.7.dist-info}/LICENSE +0 -0
bedger/edge/client.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import socket
|
|
4
|
+
import logging
|
|
5
|
+
from http.client import HTTPConnection
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .config import Config
|
|
9
|
+
from .entities.device_event import DeviceEvent
|
|
10
|
+
from . import entities
|
|
11
|
+
from .errors import (
|
|
12
|
+
ConnectionError,
|
|
13
|
+
SendError,
|
|
14
|
+
HTTPRequestError,
|
|
15
|
+
JSONSerializationError,
|
|
16
|
+
map_socket_error,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger("bedger.edge.client")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class UnixSocketHTTPConnection(HTTPConnection):
|
|
23
|
+
"""HTTPConnection subclass that communicates via UNIX domain sockets."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, unix_socket_path: str):
|
|
26
|
+
super().__init__("localhost") # dummy host
|
|
27
|
+
self.unix_socket_path = unix_socket_path
|
|
28
|
+
|
|
29
|
+
def connect(self):
|
|
30
|
+
"""Override to connect to a UNIX socket instead of TCP."""
|
|
31
|
+
try:
|
|
32
|
+
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
33
|
+
self.sock.connect(self.unix_socket_path)
|
|
34
|
+
except Exception as e:
|
|
35
|
+
raise map_socket_error(e, self.unix_socket_path)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Client:
|
|
39
|
+
"""
|
|
40
|
+
Bedger Edge Client that communicates with the local agent's HTTP API
|
|
41
|
+
over a UNIX socket. Matches BedgerConnection interface.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, config: Config = Config()):
|
|
45
|
+
self._config = config
|
|
46
|
+
self._connection: UnixSocketHTTPConnection | None = None
|
|
47
|
+
|
|
48
|
+
def __enter__(self) -> Client:
|
|
49
|
+
self._connect()
|
|
50
|
+
return self
|
|
51
|
+
|
|
52
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
53
|
+
self._disconnect()
|
|
54
|
+
|
|
55
|
+
def _connect(self) -> None:
|
|
56
|
+
socket_path = self._config.socket_path
|
|
57
|
+
logger.info(f"Connecting to Bedger Edge API at {socket_path}")
|
|
58
|
+
try:
|
|
59
|
+
self._connection = UnixSocketHTTPConnection(socket_path)
|
|
60
|
+
except Exception as e:
|
|
61
|
+
raise ConnectionError(socket_path, e)
|
|
62
|
+
|
|
63
|
+
def _disconnect(self) -> None:
|
|
64
|
+
if self._connection:
|
|
65
|
+
try:
|
|
66
|
+
self._connection.close()
|
|
67
|
+
logger.info("Connection closed")
|
|
68
|
+
except Exception as e:
|
|
69
|
+
logger.warning(f"Error closing connection: {e}")
|
|
70
|
+
finally:
|
|
71
|
+
self._connection = None
|
|
72
|
+
|
|
73
|
+
def send_event(
|
|
74
|
+
self, event_type: str, severity: entities.Severity, payload: dict[str, Any]
|
|
75
|
+
) -> None:
|
|
76
|
+
"""Send a DeviceEvent to /device/events."""
|
|
77
|
+
if not self._connection:
|
|
78
|
+
raise ConnectionError(self._config.socket_path)
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
event = DeviceEvent(event_type=event_type, severity=severity, details=payload)
|
|
82
|
+
serialized = event.model_dump_json(by_alias=True).encode("utf-8")
|
|
83
|
+
except Exception as e:
|
|
84
|
+
raise JSONSerializationError(f"Failed to serialize DeviceEvent {event_type}") from e
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
self._connection.request(
|
|
88
|
+
"POST",
|
|
89
|
+
"/device/events",
|
|
90
|
+
body=serialized,
|
|
91
|
+
headers={"Content-Type": "application/json"},
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
response = self._connection.getresponse()
|
|
95
|
+
response_data = response.read().decode("utf-8")
|
|
96
|
+
|
|
97
|
+
if response.status != 200:
|
|
98
|
+
raise HTTPRequestError(response.status, response_data)
|
|
99
|
+
|
|
100
|
+
logger.info(f"Event sent successfully: {response_data}")
|
|
101
|
+
except HTTPRequestError:
|
|
102
|
+
raise
|
|
103
|
+
except Exception as e:
|
|
104
|
+
raise SendError("Failed to send DeviceEvent", e)
|
bedger/edge/entities/__init__.py
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Dict, Any, Annotated
|
|
6
|
+
from pydantic import BaseModel, Field, field_validator, field_serializer
|
|
7
|
+
from .severity import Severity
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DeviceEvent(BaseModel):
|
|
11
|
+
"""
|
|
12
|
+
Represents a stored or transmitted device event.
|
|
13
|
+
This model is compatible with the local /device/events API.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
event_type: Annotated[
|
|
17
|
+
str,
|
|
18
|
+
Field(
|
|
19
|
+
description="Event type in PascalCase format",
|
|
20
|
+
pattern=r"^[A-Z][a-zA-Z0-9]*$",
|
|
21
|
+
),
|
|
22
|
+
]
|
|
23
|
+
severity: Severity
|
|
24
|
+
details: Annotated[
|
|
25
|
+
Dict[str, Any],
|
|
26
|
+
Field(description="Event-specific details, must be JSON serializable"),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
@field_validator("details")
|
|
30
|
+
@classmethod
|
|
31
|
+
def validate_details(cls, value: Dict[str, Any]) -> Dict[str, Any]:
|
|
32
|
+
try:
|
|
33
|
+
json.dumps(value)
|
|
34
|
+
except TypeError:
|
|
35
|
+
raise ValueError("details must be a JSON serializable dictionary")
|
|
36
|
+
return value
|
|
37
|
+
|
|
38
|
+
@field_serializer("severity")
|
|
39
|
+
def serialize_severity(self, severity: Severity) -> str:
|
|
40
|
+
return severity.value
|
|
41
|
+
|
|
42
|
+
@field_serializer("timestamp")
|
|
43
|
+
def serialize_timestamp(self, timestamp: datetime) -> str:
|
|
44
|
+
return timestamp.isoformat()
|
bedger/edge/entities/severity.py
CHANGED
bedger/edge/errors.py
CHANGED
|
@@ -1,18 +1,104 @@
|
|
|
1
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import socket
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BedgerError(Exception):
|
|
6
|
+
"""Base class for all Bedger-related exceptions."""
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# --- Configuration and Initialization ---
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ConfigurationError(BedgerError):
|
|
14
|
+
"""Raised when configuration values are missing, invalid, or inconsistent."""
|
|
15
|
+
def __init__(self, message: str, path: str | None = None):
|
|
16
|
+
self.path = path
|
|
17
|
+
super().__init__(f"{message}{f' (path: {path})' if path else ''}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EnvironmentError(BedgerError):
|
|
21
|
+
"""Raised when the environment or system setup prevents operation (permissions, missing dirs, etc.)."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# --- Networking / Socket Communication ---
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ConnectionError(BedgerError):
|
|
29
|
+
"""Raised when connection to a UNIX or network socket fails."""
|
|
30
|
+
def __init__(self, socket_path: str, original_error: Exception | None = None):
|
|
31
|
+
self.socket_path = socket_path
|
|
32
|
+
self.original_error = original_error
|
|
33
|
+
super().__init__(f"Failed to connect to socket at {socket_path}: {original_error}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SendError(BedgerError):
|
|
37
|
+
"""Raised when sending data to Bedger Edge fails."""
|
|
38
|
+
def __init__(self, message: str, original_error: Exception | None = None):
|
|
39
|
+
self.original_error = original_error
|
|
40
|
+
super().__init__(f"{message}{f' ({original_error})' if original_error else ''}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ReceiveError(BedgerError):
|
|
44
|
+
"""Raised when receiving acknowledgment or response fails."""
|
|
45
|
+
def __init__(self, message: str, original_error: Exception | None = None):
|
|
46
|
+
self.original_error = original_error
|
|
47
|
+
super().__init__(f"{message}{f' ({original_error})' if original_error else ''}")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# --- HTTP API Errors ---
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class HTTPRequestError(BedgerError):
|
|
54
|
+
"""Raised for failed HTTP requests to the local Bedger Edge API."""
|
|
55
|
+
def __init__(self, status_code: int, response: str):
|
|
56
|
+
self.status_code = status_code
|
|
57
|
+
self.response = response
|
|
58
|
+
super().__init__(f"Bedger API returned HTTP {status_code}: {response}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class JSONSerializationError(BedgerError):
|
|
62
|
+
"""Raised when JSON encoding or decoding fails."""
|
|
2
63
|
pass
|
|
3
64
|
|
|
4
65
|
|
|
5
|
-
|
|
66
|
+
# --- Certificates / Security ---
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class CaCertificateError(BedgerError):
|
|
70
|
+
"""Raised when fetching or validating a CA certificate fails."""
|
|
6
71
|
pass
|
|
7
72
|
|
|
8
73
|
|
|
9
|
-
class
|
|
74
|
+
class AuthenticationError(BedgerError):
|
|
75
|
+
"""Raised when authentication or provisioning fails."""
|
|
10
76
|
pass
|
|
11
77
|
|
|
12
78
|
|
|
13
|
-
|
|
79
|
+
# --- Device Twin / State Sync ---
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class DeviceTwinError(BedgerError):
|
|
83
|
+
"""Raised when device twin synchronization or persistence fails."""
|
|
14
84
|
pass
|
|
15
85
|
|
|
16
86
|
|
|
17
|
-
class
|
|
87
|
+
class DeviceEventError(BedgerError):
|
|
88
|
+
"""Raised when processing or storing device events fails."""
|
|
18
89
|
pass
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# --- Utilities ---
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def map_socket_error(err: Exception, socket_path: str) -> BedgerError:
|
|
96
|
+
"""Map low-level socket errors to Bedger-friendly errors."""
|
|
97
|
+
if isinstance(err, FileNotFoundError):
|
|
98
|
+
return ConnectionError(socket_path, original_error=err)
|
|
99
|
+
elif isinstance(err, PermissionError):
|
|
100
|
+
return EnvironmentError(f"Permission denied on socket {socket_path}")
|
|
101
|
+
elif isinstance(err, socket.timeout):
|
|
102
|
+
return ConnectionError(socket_path, original_error=err)
|
|
103
|
+
else:
|
|
104
|
+
return BedgerError(str(err))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: bedger
|
|
3
|
+
Version: 0.0.7
|
|
4
|
+
Summary:
|
|
5
|
+
Author: Henk van den Brink
|
|
6
|
+
Requires-Python: >=3.8, !=2.7.*, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*, !=3.7.*
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
bedger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
bedger/edge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
bedger/edge/client.py,sha256=R8jeGipxdfjPxn2SWRsNvH2UVx2-v7u2_xw-W62T7vc,3363
|
|
4
|
+
bedger/edge/config.py,sha256=0fUKThP0aJFk3WBF7JUtuKKhXlV07SX5VnqVOLNou-A,152
|
|
5
|
+
bedger/edge/entities/__init__.py,sha256=449LXPZNzoQS7_uxAc5GoT3tx2X-TmtJ-mvy080BNbM,104
|
|
6
|
+
bedger/edge/entities/device_event.py,sha256=E4x7Yt_T2FNW1rNV1FJaPPxDxKWzH5hWDkpkeunK9f0,1273
|
|
7
|
+
bedger/edge/entities/severity.py,sha256=tUN7eDSEN5cc5eAqhvKzVHD1pSEmrdwvNEGsmh4Pnfw,157
|
|
8
|
+
bedger/edge/errors.py,sha256=QOE1aI93w9dLb6WG9c2glAnFaLMy9gN1z4PBimB8bXc,3193
|
|
9
|
+
bedger-0.0.7.dist-info/LICENSE,sha256=lVrf6pfElYZ_o6ETq-XR91_7GHTzKGyeNWAKghvcNUE,1075
|
|
10
|
+
bedger-0.0.7.dist-info/METADATA,sha256=-uIPxzTTC63VMaSCF1fcuSMeswwsjLcLey0ZMGNrbPc,434
|
|
11
|
+
bedger-0.0.7.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
12
|
+
bedger-0.0.7.dist-info/RECORD,,
|
bedger/edge/connection.py
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
import socket
|
|
5
|
-
from typing import Optional
|
|
6
|
-
|
|
7
|
-
from bedger.edge import errors
|
|
8
|
-
from bedger.edge.config import Config
|
|
9
|
-
from bedger.edge.entities import Message, Severity
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger("bedger.edge.connection")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class ConnectionManager:
|
|
15
|
-
"""Manages a connection to a UNIX socket for sending and receiving messages.
|
|
16
|
-
|
|
17
|
-
This class provides context manager support for establishing and tearing
|
|
18
|
-
down a connection to a UNIX socket.
|
|
19
|
-
|
|
20
|
-
Attributes:
|
|
21
|
-
_config (Config): The configuration containing the socket path.
|
|
22
|
-
_socket (Optional[socket.socket]): The current socket connection.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
def __init__(self, config: Config = Config()):
|
|
26
|
-
"""Initializes the ConnectionManager.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
config (Config): Configuration for the connection. Defaults to a new `Config` instance.
|
|
30
|
-
"""
|
|
31
|
-
self._config = config
|
|
32
|
-
self._socket: Optional[socket.socket] = None
|
|
33
|
-
|
|
34
|
-
def __enter__(self) -> ConnectionManager:
|
|
35
|
-
"""Establishes the socket connection when entering the context.
|
|
36
|
-
|
|
37
|
-
Returns:
|
|
38
|
-
ConnectionManager: The instance of the ConnectionManager.
|
|
39
|
-
"""
|
|
40
|
-
self._connect()
|
|
41
|
-
return self
|
|
42
|
-
|
|
43
|
-
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
|
44
|
-
"""Closes the socket connection when exiting the context."""
|
|
45
|
-
self._disconnect()
|
|
46
|
-
|
|
47
|
-
def _connect(self) -> None:
|
|
48
|
-
"""Establish a connection to the UNIX socket.
|
|
49
|
-
|
|
50
|
-
Raises:
|
|
51
|
-
errors.SocketPermissionDeniedError: If the application does not have permission to connect to the socket.
|
|
52
|
-
errors.SocketFileNotFoundError: If the socket file is not found at the specified path.
|
|
53
|
-
errors.SocketConnectionError: If any other error occurs during the connection attempt.
|
|
54
|
-
"""
|
|
55
|
-
logger.info(f"Attempting to connect to socket at {self._config.socket_path}")
|
|
56
|
-
try:
|
|
57
|
-
self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
58
|
-
self._socket.connect(self._config.socket_path)
|
|
59
|
-
logger.info("Successfully connected to the socket")
|
|
60
|
-
except PermissionError:
|
|
61
|
-
logger.error("Permission denied: Unable to connect to the socket. Ensure you have the correct permissions.")
|
|
62
|
-
raise errors.SocketPermissionDeniedError("Permission denied to connect to socket. Are you running as root?")
|
|
63
|
-
except FileNotFoundError:
|
|
64
|
-
logger.error("Socket file not found. Verify the server is running and the socket path is correct.")
|
|
65
|
-
raise errors.SocketFileNotFoundError("Socket file not found. Is the server running?")
|
|
66
|
-
except Exception as e:
|
|
67
|
-
logger.exception(f"Unexpected error while connecting to the socket: {e}")
|
|
68
|
-
raise errors.SocketConnectionError(f"An unexpected error occurred while connecting to the socket: {e}")
|
|
69
|
-
|
|
70
|
-
def _disconnect(self) -> None:
|
|
71
|
-
"""Close the socket connection gracefully.
|
|
72
|
-
|
|
73
|
-
Ensures the socket is closed and cleaned up properly, even in case of errors.
|
|
74
|
-
"""
|
|
75
|
-
if self._socket:
|
|
76
|
-
try:
|
|
77
|
-
logger.info("Closing the socket connection")
|
|
78
|
-
self._socket.close()
|
|
79
|
-
except Exception as e:
|
|
80
|
-
logger.warning(f"Error occurred while closing the socket: {e}")
|
|
81
|
-
finally:
|
|
82
|
-
self._socket = None
|
|
83
|
-
|
|
84
|
-
def send_event(self, event_type: str, severity: str | Severity, payload: dict) -> None:
|
|
85
|
-
"""Send an event message through the socket.
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
event_type (str): The type of event being sent.
|
|
89
|
-
severity (str | Severity): The severity level of the event.
|
|
90
|
-
payload (dict): The event's payload details.
|
|
91
|
-
|
|
92
|
-
Raises:
|
|
93
|
-
errors.SocketNotConnectedError: If no active socket connection exists.
|
|
94
|
-
errors.SocketBrokenPipeError: If the socket connection is lost during message transmission.
|
|
95
|
-
errors.SocketCommunicationError: If any error occurs during socket communication.
|
|
96
|
-
"""
|
|
97
|
-
if not self._socket:
|
|
98
|
-
logger.error("Attempted to send a message without an active socket connection.")
|
|
99
|
-
raise errors.SocketNotConnectedError("No active socket connection. Ensure the connection is established.")
|
|
100
|
-
|
|
101
|
-
try:
|
|
102
|
-
message = Message(
|
|
103
|
-
event_type=event_type,
|
|
104
|
-
severity=severity,
|
|
105
|
-
details=payload,
|
|
106
|
-
)
|
|
107
|
-
message_json = message.model_dump_json()
|
|
108
|
-
logger.debug(f"Prepared message: {message_json}")
|
|
109
|
-
|
|
110
|
-
logger.debug("Sending message")
|
|
111
|
-
self._socket.sendall(message_json.encode())
|
|
112
|
-
|
|
113
|
-
ack = self._socket.recv(1024)
|
|
114
|
-
logger.info(f"Received acknowledgment from server: {ack.decode()}")
|
|
115
|
-
except BrokenPipeError:
|
|
116
|
-
logger.error("Broken pipe error: The socket connection was lost during message transmission.")
|
|
117
|
-
raise errors.SocketBrokenPipeError("Socket connection lost. Unable to send message.")
|
|
118
|
-
except socket.error as e:
|
|
119
|
-
logger.error(f"Socket error occurred: {e}")
|
|
120
|
-
raise errors.SocketCommunicationError(f"Socket error during communication: {e}")
|
|
121
|
-
except Exception as e:
|
|
122
|
-
logger.exception(f"Unexpected error while sending the message: {e}")
|
|
123
|
-
raise errors.SocketCommunicationError(f"Unexpected error occurred: {e}")
|
bedger/edge/entities/message.py
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from typing import Dict
|
|
3
|
-
|
|
4
|
-
from pydantic import BaseModel, Field, field_serializer, field_validator
|
|
5
|
-
from typing_extensions import Annotated
|
|
6
|
-
|
|
7
|
-
from .severity import Severity
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Message(BaseModel):
|
|
11
|
-
event_type: Annotated[
|
|
12
|
-
str,
|
|
13
|
-
Field(
|
|
14
|
-
description="Event type in PascalCase format",
|
|
15
|
-
pattern=r"^[A-Z][a-zA-Z0-9]*$",
|
|
16
|
-
),
|
|
17
|
-
]
|
|
18
|
-
severity: Severity
|
|
19
|
-
details: Annotated[Dict, Field(description="Details of the message as a JSON serializable dictionary")]
|
|
20
|
-
|
|
21
|
-
@field_validator("details")
|
|
22
|
-
@classmethod
|
|
23
|
-
def validate_details(cls, value: Dict) -> Dict:
|
|
24
|
-
try:
|
|
25
|
-
json.dumps(value)
|
|
26
|
-
except TypeError:
|
|
27
|
-
raise ValueError("details must be a JSON serializable dictionary")
|
|
28
|
-
return value
|
|
29
|
-
|
|
30
|
-
@field_serializer("severity")
|
|
31
|
-
def serialize_severity(self, severity: Severity) -> str:
|
|
32
|
-
return severity.value
|
bedger-0.0.5.dist-info/METADATA
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: bedger
|
|
3
|
-
Version: 0.0.5
|
|
4
|
-
Summary: Edge monitoring software for secure and efficient device management.
|
|
5
|
-
Author: Henk van den Brink
|
|
6
|
-
Author-email: henk.vandenbrink@bedger.io
|
|
7
|
-
Requires-Python: >=3.8.1,<4.0.0
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
-
Requires-Dist: pydantic (>=2.9.2,<3.0.0)
|
|
15
|
-
Requires-Dist: typing-extensions (>=4.12.2,<5.0.0)
|
|
16
|
-
Project-URL: homepage, https://github.com/bedger-io/BEDGER-edgeservices-securitymonitoring-sdk
|
|
17
|
-
Project-URL: issues, https://github.com/bedger-io/BEDGER-edgeservices-securitymonitoring-sdk/issues
|
|
18
|
-
Description-Content-Type: text/markdown
|
|
19
|
-
|
|
20
|
-
# ConnectionManager Class Documentation
|
|
21
|
-
|
|
22
|
-
The `ConnectionManager` class manages connections to a UNIX socket for sending and receiving messages.
|
|
23
|
-
It provides context management capabilities to ensure connections are properly opened and closed.
|
|
24
|
-
|
|
25
|
-
## Features
|
|
26
|
-
- Context manager support for connection lifecycle management.
|
|
27
|
-
- Error handling for socket-related issues.
|
|
28
|
-
- Sends event messages with acknowledgment handling.
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
31
|
-
Ensure you have the `bedger` package and its dependencies installed.
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
pip install bedger
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Usage
|
|
38
|
-
The following example demonstrates how to use the `ConnectionManager` to send events:
|
|
39
|
-
|
|
40
|
-
```python
|
|
41
|
-
import time
|
|
42
|
-
import bedger.edge.config as config
|
|
43
|
-
import bedger.edge.connection as connection
|
|
44
|
-
import bedger.edge.entities as entities
|
|
45
|
-
|
|
46
|
-
if __name__ == "__main__":
|
|
47
|
-
events = [
|
|
48
|
-
{"event_type": "EventA", "severity": entities.Severity.HIGH, "payload": {"key": "value1"}},
|
|
49
|
-
{"event_type": "EventB", "severity": entities.Severity.LOW, "payload": {"key": "value2"}},
|
|
50
|
-
{"event_type": "EventC", "severity": entities.Severity.CRITICAL, "payload": {"key": "value3"}},
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
with connection.ConnectionManager(config.Config()) as conn:
|
|
54
|
-
for event in events:
|
|
55
|
-
time.sleep(1)
|
|
56
|
-
conn.send_event(event["event_type"], event["severity"], event["payload"])
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## API Reference
|
|
60
|
-
|
|
61
|
-
### `ConnectionManager`
|
|
62
|
-
Manages a connection to a UNIX socket for sending and receiving messages.
|
|
63
|
-
|
|
64
|
-
#### Constructor
|
|
65
|
-
- **`__init__(config: Config = Config())`**
|
|
66
|
-
- Initializes the `ConnectionManager` with a specified configuration.
|
|
67
|
-
- **Parameters:**
|
|
68
|
-
- `config (Config)`: The configuration containing the socket path. Defaults to a new `Config` instance.
|
|
69
|
-
|
|
70
|
-
#### Context Management
|
|
71
|
-
- **`__enter__() -> ConnectionManager`**
|
|
72
|
-
- Establishes the socket connection when entering the context.
|
|
73
|
-
- **Returns:** The instance of the `ConnectionManager`.
|
|
74
|
-
|
|
75
|
-
- **`__exit__(exc_type, exc_value, traceback) -> None`**
|
|
76
|
-
- Closes the socket connection when exiting the context.
|
|
77
|
-
|
|
78
|
-
#### Methods
|
|
79
|
-
- **`send_event(event_type: str, severity: str | Severity, payload: dict) -> None`**
|
|
80
|
-
- Sends an event message through the socket.
|
|
81
|
-
- **Parameters:**
|
|
82
|
-
- `event_type (str)`: The type of event being sent.
|
|
83
|
-
- `severity (str | Severity)`: The severity level of the event.
|
|
84
|
-
- `payload (dict)`: The event's payload details.
|
|
85
|
-
- **Raises:**
|
|
86
|
-
- `SocketNotConnectedError`: If no active socket connection exists.
|
|
87
|
-
- `SocketBrokenPipeError`: If the socket connection is lost during transmission.
|
|
88
|
-
- `SocketCommunicationError`: If an error occurs during socket communication.
|
|
89
|
-
|
|
90
|
-
## Error Handling
|
|
91
|
-
The `ConnectionManager` raises custom errors from the `bedger.edge.errors` module for:
|
|
92
|
-
- Permission issues (`SocketPermissionDeniedError`).
|
|
93
|
-
- Missing socket files (`SocketFileNotFoundError`).
|
|
94
|
-
- Connection problems (`SocketConnectionError`).
|
|
95
|
-
- Communication errors (`SocketCommunicationError`, `SocketBrokenPipeError`).
|
|
96
|
-
|
|
97
|
-
## Logging
|
|
98
|
-
The class uses the `logging` module to log the following:
|
|
99
|
-
- Connection attempts and successes.
|
|
100
|
-
- Errors during connection, disconnection, and message sending.
|
|
101
|
-
- Debug information for message preparation and acknowledgments.
|
|
102
|
-
|
|
103
|
-
## License
|
|
104
|
-
This project is licensed under the MIT License. See the LICENSE file for details.
|
|
105
|
-
|
bedger-0.0.5.dist-info/RECORD
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
bedger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
bedger/edge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
bedger/edge/config.py,sha256=0fUKThP0aJFk3WBF7JUtuKKhXlV07SX5VnqVOLNou-A,152
|
|
4
|
-
bedger/edge/connection.py,sha256=25h7PzRhSw8m0w679p23M6X_o-wuIOl7M1P837bpy9I,5400
|
|
5
|
-
bedger/edge/entities/__init__.py,sha256=_oKO_XdDerqOwVX8izhDPtGv4HqVDwQaT-otOdY8lYg,91
|
|
6
|
-
bedger/edge/entities/message.py,sha256=wLbEZik_FBboyEAvX5Uvlto1t4BsjaeLXUFGOIjIHRU,913
|
|
7
|
-
bedger/edge/entities/severity.py,sha256=lzJhqjFfeJ26EWJYDIe-Fotml00dQK6_ihpc_0NzLRg,175
|
|
8
|
-
bedger/edge/errors.py,sha256=6jdmhlKoWlD-kZ8-xRiAlObRHEo9PwrKqhWQ5su5TLk,266
|
|
9
|
-
bedger-0.0.5.dist-info/LICENSE,sha256=lVrf6pfElYZ_o6ETq-XR91_7GHTzKGyeNWAKghvcNUE,1075
|
|
10
|
-
bedger-0.0.5.dist-info/METADATA,sha256=-yEloT1oseSC-2g89JZtO07GDqW5mH1RkbribcyN6hk,4144
|
|
11
|
-
bedger-0.0.5.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
12
|
-
bedger-0.0.5.dist-info/RECORD,,
|
|
File without changes
|