generated from anoadragon453/nio-template
-
Notifications
You must be signed in to change notification settings - Fork 4
/
main.py
126 lines (106 loc) · 4.15 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python3
import logging
from time import sleep
import aiolog
import asyncio
# noinspection PyPackageRequirements
from aiohttp import (
ServerDisconnectedError,
ClientConnectionError
)
# noinspection PyPackageRequirements
from nio import (
AsyncClient,
AsyncClientConfig,
ForwardedRoomKeyEvent,
InviteMemberEvent,
LocalProtocolError,
LoginError,
MegolmEvent,
RoomKeyEvent,
RoomMessageText,
UnknownEvent,
)
from bubo.callbacks import Callbacks
from bubo.config import Config, load_config
from bubo.rooms import maintain_configured_rooms
from bubo.storage import Storage
logger = logging.getLogger(__name__)
async def main(config: Config):
# Configure the database
store = Storage(config.database_filepath)
# Configuration options for the AsyncClient
client_config = AsyncClientConfig(
max_limit_exceeded=0,
max_timeouts=0,
store_sync_tokens=True,
encryption_enabled=True,
)
# Initialize the matrix client
client = AsyncClient(
config.homeserver_url,
config.user_id,
device_id=config.device_id,
store_path=config.store_filepath,
config=client_config,
)
if config.user_token:
client.access_token = config.user_token
client.user_id = config.user_id
# Set up event callbacks
callbacks = Callbacks(client, store, config)
# noinspection PyTypeChecker
client.add_event_callback(callbacks.message, (RoomMessageText,))
# noinspection PyTypeChecker
client.add_event_callback(callbacks.invite, (InviteMemberEvent,))
# noinspection PyTypeChecker
client.add_event_callback(callbacks.decryption_failure, (MegolmEvent,))
# Nio doesn't currently have m.reaction events so we catch UnknownEvent for reactions and filter there
# noinspection PyTypeChecker
client.add_event_callback(callbacks.reaction, (UnknownEvent,))
# noinspection PyTypeChecker
client.add_to_device_callback(callbacks.room_key, (ForwardedRoomKeyEvent, RoomKeyEvent))
# Keep trying to reconnect on failure (with some time in-between)
while True:
try:
if config.user_token:
client.load_store()
else:
# Try to login with the configured username/password
try:
login_response = await client.login(
password=config.user_password,
device_name=config.device_name,
)
# Check if login failed
if type(login_response) == LoginError:
logger.error(f"Failed to login: %s", login_response.message)
return False
except LocalProtocolError as e:
# There's an edge case here where the user hasn't installed the correct C
# dependencies. In that case, a LocalProtocolError is raised on login.
logger.fatal(
"Failed to login. Have you installed the correct dependencies? "
"https://github.com/poljar/matrix-nio#installation "
"Error: %s", e
)
return False
# Login succeeded!
# Sync encryption keys with the server
# Required for participating in encrypted rooms
if client.should_upload_keys:
await client.keys_upload()
# Maintain rooms
await maintain_configured_rooms(client, store, config)
logger.info(f"Logged in as {config.user_id}")
await client.sync_forever(timeout=30000, full_state=True)
except (ClientConnectionError, ServerDisconnectedError):
logger.warning("Unable to connect to homeserver, retrying in 15s...")
# Sleep so we don't bombard the server with login requests
sleep(15)
finally:
# Make sure to close the client connection on disconnect
await client.close()
config_file = load_config()
aiolog.start()
asyncio.get_event_loop().run_until_complete(main(config_file)).run_util_complete(aiolog.stop())