first charge

This commit is contained in:
2025-04-21 23:55:23 +01:00
parent 4b1d2bd6d5
commit 0d662a03a1
6 changed files with 109 additions and 0 deletions

5
.env.example Normal file
View File

@@ -0,0 +1,5 @@
# LOG_LEVEL options: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET
HOMESERVER_URL = "https://matrix.org"
USER_ID = "@botbot_user:matrix.org"
PASSWORD = "botbot_password"
LOG_LEVEL=INFO

1
.gitignore vendored
View File

@@ -168,3 +168,4 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/ #.idea/
.vscode/settings.json

14
Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy source code
COPY . .
# Default command
CMD ["python", "main.py"]

12
docker-compose.yml Normal file
View File

@@ -0,0 +1,12 @@
services:
botbot:
build: .
env_file:
- .env
volumes:
- ./:/app # Mount source for hot-reload
- matrix_data:/app/data # Persist Matrix client store and tokens
restart: unless-stopped
volumes:
matrix_data:

75
main.py Normal file
View File

@@ -0,0 +1,75 @@
import os
import asyncio
import logging
from dotenv import load_dotenv
from nio import AsyncClient, AsyncClientConfig, MatrixRoom, RoomMessageText
from nio.responses import LoginResponse
# --- Load environment variables ---
load_dotenv()
HOMESERVER_URL = os.getenv("HOMESERVER_URL")
USER_ID = os.getenv("USER_ID")
PASSWORD = os.getenv("PASSWORD")
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper()
# --- Logging Setup ---
# Convert string level to numeric
numeric_level = getattr(logging, LOG_LEVEL, logging.INFO)
logging.basicConfig(
level=numeric_level,
format="%(asctime)s %(levelname)s %(name)s: %(message)s"
)
logger = logging.getLogger(__name__)
async def message_callback(room: MatrixRoom, event: RoomMessageText):
"""
Called when a new text message is received.
"""
logger.debug("Message callback triggered")
if event.sender == USER_ID:
return
logger.info("Message from %s in %s: %s", event.sender, room.display_name, event.body)
if event.body.strip().lower() == "!ping":
await client.room_send(
room_id=room.room_id,
message_type="m.room.message",
content={"msgtype": "m.text", "body": "Pong!"}
)
logger.info("Replied with Pong! to %s", event.sender)
async def main():
global client
logger.debug(HOMESERVER_URL)
logger.debug(USER_ID)
# Configure client with persistent store
config = AsyncClientConfig(store_sync_tokens=True)
client = AsyncClient(
HOMESERVER_URL,
USER_ID,
store_path="/app/data",
config=config
)
# Login
resp = await client.login(password=PASSWORD)
logger.debug("Login response raw: %r", resp.__dict__)
if not isinstance(resp, LoginResponse) or not resp.access_token:
error_msg = getattr(resp, 'message', repr(resp))
logger.error("Login failed: %s", error_msg)
await client.close()
return
logger.info("Logged in successfully as %s", USER_ID)
# Register callback and start syncing
client.add_event_callback(message_callback, RoomMessageText)
logger.info("Starting sync loop with timeout=30000ms")
await client.sync_forever(timeout=30000)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logger.info("Received interrupt, shutting down client")
asyncio.run(client.close())

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
matrix-nio[aio,http]>=0.25.0
python-dotenv>=1.0.0