matrix-agent 0.1.1__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.
matrix_agent/__init__.py
ADDED
matrix_agent/agent.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Dict, Any, Optional
|
|
5
|
+
from nio import AsyncClient, AsyncClientConfig
|
|
6
|
+
from nio.crypto import TrustState
|
|
7
|
+
|
|
8
|
+
from .core import BaseChain
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class AgentConfig:
|
|
14
|
+
homeserver: str
|
|
15
|
+
user_id: str
|
|
16
|
+
device_id: Optional[str] = None
|
|
17
|
+
access_token: Optional[str] = None
|
|
18
|
+
store_path: str = "/tmp"
|
|
19
|
+
store_sync_tokens: bool = True
|
|
20
|
+
encryption_enabled: bool = True
|
|
21
|
+
|
|
22
|
+
class MatrixAgent:
|
|
23
|
+
def __init__(self, config: AgentConfig, chain: BaseChain):
|
|
24
|
+
self.config = config
|
|
25
|
+
self.chain = chain
|
|
26
|
+
self._client: Optional[AsyncClient] = None
|
|
27
|
+
|
|
28
|
+
async def login(self):
|
|
29
|
+
client_config = AsyncClientConfig(
|
|
30
|
+
store_sync_tokens=self.config.store_sync_tokens,
|
|
31
|
+
encryption_enabled=self.config.encryption_enabled,
|
|
32
|
+
)
|
|
33
|
+
self._client = AsyncClient(
|
|
34
|
+
self.config.homeserver,
|
|
35
|
+
self.config.user_id,
|
|
36
|
+
device_id=self.config.device_id,
|
|
37
|
+
store_path=self.config.store_path,
|
|
38
|
+
config=client_config,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if not self.config.access_token:
|
|
42
|
+
raise ValueError("Access token is required for automated login.")
|
|
43
|
+
|
|
44
|
+
self._client.restore_login(
|
|
45
|
+
user_id=self.config.user_id,
|
|
46
|
+
device_id=self.config.device_id,
|
|
47
|
+
access_token=self.config.access_token,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def _callback_wrapper(self, event):
|
|
51
|
+
asyncio.create_task(self._dispatch(event))
|
|
52
|
+
|
|
53
|
+
async def _dispatch(self, event):
|
|
54
|
+
request_context = {"event": event, "client": self._client}
|
|
55
|
+
await self.chain.execute(request_context)
|
|
56
|
+
|
|
57
|
+
async def start(self):
|
|
58
|
+
await self._client.sync(full_state=True)
|
|
59
|
+
for device in self._client.device_store:
|
|
60
|
+
if device.trust_state != TrustState.verified:
|
|
61
|
+
self._client.verify_device(device)
|
|
62
|
+
|
|
63
|
+
# Register both Room and ToDevice event paths
|
|
64
|
+
self._client.add_event_callback(self._callback_wrapper)
|
|
65
|
+
self._client.add_to_device_callback(self._callback_wrapper)
|
|
66
|
+
|
|
67
|
+
await self._client.sync_forever(timeout=30_000, full_state=True)
|
|
68
|
+
|
|
69
|
+
async def close(self):
|
|
70
|
+
if self._client:
|
|
71
|
+
await self._client.close()
|
matrix_agent/core.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Dict, Any, Optional, Type, List
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
class FactoryMeta(type):
|
|
8
|
+
def __call__(cls, *args, **kwargs):
|
|
9
|
+
name = args[0] if args else kwargs.get("name")
|
|
10
|
+
if cls.__name__ == "BaseFactory" and isinstance(name, str):
|
|
11
|
+
if name in cls._registry:
|
|
12
|
+
concrete_class = cls._registry[name]
|
|
13
|
+
else:
|
|
14
|
+
concrete_class = cls._lazy_load(name)
|
|
15
|
+
return super(FactoryMeta, cls).__call__(concrete_class, *args, **kwargs)
|
|
16
|
+
return super().__call__(*args, **kwargs)
|
|
17
|
+
|
|
18
|
+
class BaseFactory(metaclass=FactoryMeta):
|
|
19
|
+
plugin_dir: Optional[str] = None
|
|
20
|
+
_registry: Dict[str, Type["BaseFactory"]] = {}
|
|
21
|
+
|
|
22
|
+
def __init_subclass__(cls, name: Optional[str] = None, **kwargs):
|
|
23
|
+
super().__init_subclass__(**kwargs)
|
|
24
|
+
if name is None:
|
|
25
|
+
name = cls.__module__.split(".")[-1]
|
|
26
|
+
|
|
27
|
+
# Handle registry isolation for different factory types
|
|
28
|
+
if BaseFactory not in cls.__bases__:
|
|
29
|
+
factory_cls = cls.__bases__[0]
|
|
30
|
+
if not hasattr(factory_cls, "_registry") or factory_cls._registry is BaseFactory._registry:
|
|
31
|
+
setattr(factory_cls, "_registry", {})
|
|
32
|
+
factory_cls._registry[name] = cls
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def _lazy_load(cls, name: str) -> Type["BaseFactory"]:
|
|
36
|
+
if not cls.plugin_dir:
|
|
37
|
+
raise RuntimeError(f"Factory {cls.__name__} has no 'plugin_dir' defined.")
|
|
38
|
+
try:
|
|
39
|
+
importlib.import_module(f"{cls.plugin_dir}.{name}")
|
|
40
|
+
return cls._registry[name]
|
|
41
|
+
except (ImportError, KeyError):
|
|
42
|
+
raise KeyError(f"Could not find registered implementation '{name}' in {cls.plugin_dir}")
|
|
43
|
+
|
|
44
|
+
class BaseHandler:
|
|
45
|
+
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
|
46
|
+
self.config = config or {}
|
|
47
|
+
|
|
48
|
+
def can_handle(self, request: Dict[str, Any]) -> bool:
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
|
|
51
|
+
async def handle(self, request: Dict[str, Any]) -> bool:
|
|
52
|
+
raise NotImplementedError
|
|
53
|
+
|
|
54
|
+
class BaseChain:
|
|
55
|
+
def __init__(self, factory: Type[BaseFactory], handler_names: List[str], global_config: Dict[str, Any]):
|
|
56
|
+
self.handlers = []
|
|
57
|
+
for name in handler_names:
|
|
58
|
+
config = global_config.get(name, {})
|
|
59
|
+
handler_cls = factory(name)
|
|
60
|
+
self.handlers.append(handler_cls(config))
|
|
61
|
+
|
|
62
|
+
async def execute(self, request: Dict[str, Any]):
|
|
63
|
+
for handler in self.handlers:
|
|
64
|
+
if handler.can_handle(request):
|
|
65
|
+
consumed = await handler.handle(request)
|
|
66
|
+
if consumed:
|
|
67
|
+
break
|
matrix_agent/handlers.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from .core import BaseHandler
|
|
3
|
+
|
|
4
|
+
class MatrixHandler(BaseHandler):
|
|
5
|
+
"""
|
|
6
|
+
Abstract Base Class for Matrix Handlers.
|
|
7
|
+
The 'request' object passed to these methods always contains:
|
|
8
|
+
{'event': nio_event, 'client': nio_client}
|
|
9
|
+
"""
|
|
10
|
+
def can_handle(self, request: dict) -> bool:
|
|
11
|
+
# To be overridden by concrete handlers
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
async def handle(self, request: dict) -> bool:
|
|
15
|
+
# To be overridden by concrete handlers
|
|
16
|
+
return False
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: matrix-agent
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Plugin-driven matrix client framework.
|
|
5
|
+
Author-email: Peach <james@christhall.us>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/girrasol/matrix-bot
|
|
8
|
+
Keywords: matrix,agent,bot
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Requires-Python: >=3.12
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: matrix-nio
|
|
16
|
+
Requires-Dist: pyyaml
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
20
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
21
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
22
|
+
|
|
23
|
+
# Matrix Bot
|
|
24
|
+
|
|
25
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
matrix_agent/__init__.py,sha256=9h0iYvIae-zddLFp2PYgEDC5oW743glYQRAeSotFvyY,208
|
|
2
|
+
matrix_agent/agent.py,sha256=EFEz4jTTg8fd2SAEyD3-F28dkJtVpZ9D0clxnfURw1A,2270
|
|
3
|
+
matrix_agent/core.py,sha256=8TmWZVcmMIrpcd_uE5hFV43-fBK1GeQ6VYWFwXWCWuA,2627
|
|
4
|
+
matrix_agent/handlers.py,sha256=W17sQzVjUnlvFZ8ODxoMIMBToK0VhkAiptF46Hbh_vg,501
|
|
5
|
+
matrix_agent-0.1.1.dist-info/METADATA,sha256=P_caHUBquxz0u8Q-qOSwk1lzEUHvxiXiz3hRO2HNvj8,757
|
|
6
|
+
matrix_agent-0.1.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
+
matrix_agent-0.1.1.dist-info/top_level.txt,sha256=AbvkOHrhUIWo2DQLcZnQ-Lmi5tzaDUgC3HVPXuiLcto,13
|
|
8
|
+
matrix_agent-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
matrix_agent
|