Merge pull request #42 from ancho/feature/logging-and-signals

use logging and register signal handlers
This commit is contained in:
Frank Becker 2020-02-16 19:13:24 +01:00 committed by GitHub
commit 3ce0d80ecb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 209 additions and 123 deletions

View File

@ -10,6 +10,9 @@ RUN pip install pipenv && \
rm -r /root/.local/*
COPY bot.py *.json *.pickle /bot/
COPY config config
COPY modules modules
VOLUME /bot/config
CMD [ "python", "-u", "./bot.py" ]

View File

@ -15,6 +15,7 @@ requests = "*"
igramscraper = "*"
twitterscraper = "*"
httpx = "*"
pyyaml = "==5.3"
[dev-packages]
pylint = "*"

View File

@ -215,6 +215,7 @@ MATRIX_ACCESS_TOKEN=MDAxOGxvYlotofcharacters53CgYAYFgo
MATRIX_SERVER=https://matrix.org
JOIN_ON_INVITE=True
BOT_OWNERS=@user1:matrix.org,@user2:matrix.org
DEBUG=False
```
Note: without quotes!
@ -227,21 +228,48 @@ docker-compose up
## Env variables
User, access token and server should be self-explanatory. Set JOIN_ON_INVITE to anything if you want the bot to
join invites automatically (do not set it if you don't want it to join).
`MATRIX_USER`, `MATRIX_ACCESS_TOKEN` and `MATRIX_SERVER` should be self-explanatory.
Set `JOIN_ON_INVITE` to anything if you want the bot to join invites automatically (do not set it if you don't want it to join).
You can set MATRIX_PASSWORD if you want to get access token. Normally you can use Riot to get it.
You can set `MATRIX_PASSWORD` if you want to get an access token automatically with a login.
Normally you can use Riot to get it.
BOT_OWNERS is a comma-separated list of matrix id's for the owners of the bot. Some commands require
sender to be bot owner. Typically set your own id into it. Don't include bot itself in BOT_OWNERS if cron
or any other module that can cause bot to send custom commands is used as it could potentially be used to run
owner commands as the bot itself.
`BOT_OWNERS` is a comma-separated list of matrix id's for the owners of the bot.
Some commands require sender to be bot owner.
Typically set your own id into it.
__*ATTENTION:*__ Don't include bot itself in `BOT_OWNERS` if cron or any other module that can cause bot to send custom commands is used, as it could potentially be used to run owner commands as the bot itself.
To enable debugging for the root logger set `DEBUG=True`.
## Logging
Uses [python logging facility](https://docs.python.org/3/library/logging.html) to print information to the console. Customize it to your needs editing `config/logging.yml`.
See [logging.config documentation](https://docs.python.org/3/library/logging.config.html) for further information.
## Module API
Just write a python file with desired command name and place it in modules. See current modules for
examples. No need to register it anywhere else.
*Simple skeleton for a bot module:*
```python
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event):
args = event.body.split()
args.pop(0)
# Echo what they said back
self.logger.debug(f"room: {room.name} sender: {event.sender} wants an echo")
await bot.send_text(room, ' '.join(args))
def help(self):
return 'Echoes back what user has said'
```
Functions:
* matrix_start - Called once on startup
@ -254,6 +282,10 @@ Functions:
You only need to implement the ones you need. See existing bots for examples.
Logging:
Use `self.logger` in your module to print information to the console.
Module settings are stored in Matrix account data.
If you write a new module, please make a PR if it's something useful for others.

156
bot.py
View File

@ -1,14 +1,18 @@
#!/usr/bin/env python3
import asyncio
import functools
import glob
import importlib
import json
import yaml
import os
import re
import signal
import sys
import traceback
import urllib.parse
import logging
import logging.config
from importlib import reload
import requests
@ -28,14 +32,38 @@ class CommandRequiresOwner(Exception):
class Bot:
appid = 'org.vranki.hemppa'
version = '1.2'
client = None
join_on_invite = False
modules = dict()
pollcount = 0
poll_task = None
owners = []
def __init__(self):
self.appid = 'org.vranki.hemppa'
self.version = '1.2'
self.client = None
self.join_on_invite = False
self.modules = dict()
self.pollcount = 0
self.poll_task = None
self.owners = []
self.debug = os.getenv("DEBUG", "false").lower() == "true"
self.logger = None
self.initialize_logger()
def initialize_logger(self):
if os.path.exists('config/logging.yml'):
with open('config/logging.yml') as f:
config = yaml.load(f, Loader=yaml.Loader)
logging.config.dictConfig(config)
else:
log_format = '%(levelname)s - %(name)s - %(message)s'
logging.basicConfig(format=log_format)
self.logger = logging.getLogger("hemppa")
if self.debug:
logging.root.setLevel(logging.DEBUG)
self.logger.info("enabled debugging")
self.logger.debug("Logger initialized")
async def send_text(self, room, body):
msg = {
@ -54,10 +82,10 @@ class Bot:
await self.client.room_send(room.room_id, 'm.room.message', msg)
def remove_callback(self, callback):
for cb_object in bot.client.event_callbacks:
for cb_object in self.client.event_callbacks:
if cb_object.func == callback:
print("remove callback")
bot.client.event_callbacks.remove(cb_object)
self.logger.info("remove callback")
self.client.event_callbacks.remove(cb_object)
def get_room_by_id(self, room_id):
return self.client.rooms[room_id]
@ -124,17 +152,16 @@ class Bot:
if moduleobject is not None:
if moduleobject.enabled:
try:
await moduleobject.matrix_message(bot, room, event)
await moduleobject.matrix_message(self, room, event)
except CommandRequiresAdmin:
await self.send_text(room, f'Sorry, you need admin power level in this room to run that command.')
except CommandRequiresOwner:
await self.send_text(room, f'Sorry, only bot owner can run that command.')
except Exception:
await self.send_text(room,
f'Module {command} experienced difficulty: {sys.exc_info()[0]} - see log for details')
await self.send_text(room, f'Module {command} experienced difficulty: {sys.exc_info()[0]} - see log for details')
traceback.print_exc(file=sys.stderr)
else:
print(f"Unknown command: {command}")
self.logger.error(f"Unknown command: {command}")
# TODO Make this configurable
# await self.send_text(room,
# f"Sorry. I don't know what to do. Execute !help to get a list of available commands.")
@ -152,31 +179,28 @@ class Bot:
for attempt in range(3):
result = await self.client.join(room.room_id)
if type(result) == JoinError:
print(f"Error joining room {room.room_id} (attempt %d): %s",
attempt, result.message,
)
self.logger.error(f"Error joining room %s (attempt %d): %s", room.room_id, attempt, result.message)
else:
print(f"joining room '{room.display_name}'({room.room_id}) invited by '{event.sender}'")
self.logger.info(f"joining room '{room.display_name}'({room.room_id}) invited by '{event.sender}'")
break
else:
print(
f'Received invite event, but not joining as sender is not owner or bot not configured to join on invite. {event}')
self.logger.warning(f'Received invite event, but not joining as sender is not owner or bot not configured to join on invite. {event}')
def load_module(self, modulename):
try:
print("load module: " + modulename)
self.logger.info(f'load module: {modulename}')
module = importlib.import_module('modules.' + modulename)
module = reload(module)
cls = getattr(module, 'MatrixModule')
return cls(modulename)
except ModuleNotFoundError:
print('Module ', modulename, ' failed to load!')
self.logger.error(f'Module {modulename} failed to load!')
traceback.print_exc(file=sys.stderr)
return None
def reload_modules(self):
for modulename in bot.modules:
print('Reloading', modulename, '..')
self.logger.info(f'Reloading {modulename} ..')
self.modules[modulename] = self.load_module(modulename)
self.load_settings(self.get_account_data())
@ -199,7 +223,7 @@ class Bot:
for modulename, moduleobject in self.modules.items():
if moduleobject.enabled:
try:
await moduleobject.matrix_poll(bot, self.pollcount)
await moduleobject.matrix_poll(self, self.pollcount)
except Exception:
traceback.print_exc(file=sys.stderr)
await asyncio.sleep(10)
@ -213,7 +237,7 @@ class Bot:
self.__handle_error_response(response)
if response.status_code != 200:
print('Setting account data failed:', response, response.json())
self.logger.error('Setting account data failed. response: %s json: %s', response, response.json())
def get_account_data(self):
userid = urllib.parse.quote(self.matrix_user)
@ -225,14 +249,13 @@ class Bot:
if response.status_code == 200:
return response.json()
print(
f'Getting account data failed: {response} {response.json()} - this is normal if you have not saved any settings yet.')
self.logger.error(f'Getting account data failed: {response} {response.json()} - this is normal if you have not saved any settings yet.')
return None
def __handle_error_response(self, response):
if response.status_code == 401:
print("ERROR: access token is invalid or missing")
print("NOTE: check MATRIX_ACCESS_TOKEN or set MATRIX_PASSWORD")
self.logger.error("access token is invalid or missing")
self.logger.info("NOTE: check MATRIX_ACCESS_TOKEN or set MATRIX_PASSWORD")
sys.exit(2)
def init(self):
@ -250,7 +273,7 @@ class Bot:
if self.client.access_token is None:
if self.matrix_pass is None:
print("Either MATRIX_ACCESS_TOKEN or MATRIX_PASSWORD need to be set")
self.logger.error("Either MATRIX_ACCESS_TOKEN or MATRIX_PASSWORD need to be set")
sys.exit(1)
self.join_on_invite = join_on_invite is not None
@ -258,25 +281,25 @@ class Bot:
self.get_modules()
else:
print("The environment variables MATRIX_SERVER, MATRIX_USER and BOT_OWNERS are mandatory")
self.logger.error("The environment variables MATRIX_SERVER, MATRIX_USER and BOT_OWNERS are mandatory")
sys.exit(1)
def start(self):
self.load_settings(self.get_account_data())
enabled_modules = [module for module_name, module in self.modules.items() if module.enabled]
print(f'Starting {len(enabled_modules)} modules..')
self.logger.info(f'Starting {len(enabled_modules)} modules..')
for modulename, moduleobject in self.modules.items():
if moduleobject.enabled:
try:
moduleobject.matrix_start(bot)
moduleobject.matrix_start(self)
except Exception:
traceback.print_exc(file=sys.stderr)
def stop(self):
print(f'Stopping {len(self.modules)} modules..')
self.logger.info(f'Stopping {len(self.modules)} modules..')
for modulename, moduleobject in self.modules.items():
try:
moduleobject.matrix_stop(bot)
moduleobject.matrix_stop(self)
except Exception:
traceback.print_exc(file=sys.stderr)
@ -285,18 +308,18 @@ class Bot:
login_response = await self.client.login(self.matrix_pass)
if isinstance(login_response, LoginError):
print(f"Failed to login: {login_response.message}")
self.logger.error(f"Failed to login: {login_response.message}")
return
last_16 = self.client.access_token[-16:]
print(f"Logged in with password, access token: ...{last_16}")
self.logger.info(f"Logged in with password, access token: ...{last_16}")
await self.client.sync()
for roomid, room in self.client.rooms.items():
print(f"Bot is on '{room.display_name}'({roomid}) with {len(room.users)} users")
self.logger.info(f"Bot is on '{room.display_name}'({roomid}) with {len(room.users)} users")
if len(room.users) == 1:
print(f'Room {roomid} has no other users - leaving it.')
print(await self.client.room_leave(roomid))
self.logger.info(f'Room {roomid} has no other users - leaving it.')
self.logger.info(await self.client.room_leave(roomid))
self.start()
@ -308,12 +331,12 @@ class Bot:
self.client.add_event_callback(self.invite_cb, (InviteEvent,))
if self.join_on_invite:
print('Note: Bot will join rooms if invited')
print('Bot running as', self.client.user, ', owners', self.owners)
self.logger.info('Note: Bot will join rooms if invited')
self.logger.info('Bot running as %s, owners %s', self.client.user, self.owners)
self.bot_task = asyncio.create_task(self.client.sync_forever(timeout=30000))
await self.bot_task
else:
print('Client was not able to log in, check env variables!')
self.logger.error('Client was not able to log in, check env variables!')
async def shutdown(self):
@ -321,28 +344,43 @@ class Bot:
logout = await self.client.logout()
if isinstance(logout, LogoutResponse):
print("Logout successful")
self.logger.info("Logout successful")
try:
await self.client.close()
print("Connection closed")
self.logger.info("Connection closed")
except Exception as e:
print("error while closing client", e)
self.logger.error("error while closing client: %s", e)
else:
logout: LogoutError
print(f"Logout unsuccessful. msg: {logout.message}")
self.logger.error(f"Logout unsuccessful. msg: {logout.message}")
else:
await self.client.client_session.close()
def handle_exit(self, signame, loop):
self.logger.info(f"Received signal {signame}")
if self.poll_task:
self.poll_task.cancel()
self.bot_task.cancel()
self.stop()
async def main():
bot = Bot()
bot.init()
loop = asyncio.get_running_loop()
for signame in {'SIGINT', 'SIGTERM'}:
loop.add_signal_handler(
getattr(signal, signame),
functools.partial(bot.handle_exit, signame, loop))
await bot.run()
await bot.shutdown()
bot = Bot()
bot.init()
try:
asyncio.get_event_loop().run_until_complete(bot.run())
except KeyboardInterrupt:
if bot.poll_task:
bot.poll_task.cancel()
bot.bot_task.cancel()
bot.stop()
asyncio.get_event_loop().run_until_complete(bot.shutdown())
asyncio.run(main())
except Exception as e:
print(e)

15
config/logging.yml Normal file
View File

@ -0,0 +1,15 @@
version: 1
formatters:
hemppa:
format: '%(asctime)s - %(levelname)s - %(name)s - %(message)s'
handlers:
console:
class: logging.StreamHandler
formatter: hemppa
stream: ext://sys.stdout
loggers:
hemppa:
level: NOTSET
root:
level: INFO
handlers: [console]

View File

@ -13,6 +13,10 @@ services:
- MATRIX_SERVER
- JOIN_ON_INVITE
- BOT_OWNERS
- DEBUG
volumes:
- ${PWD}/config/:/bot/config
- ${PWD}/credentials.json:/bot/credentials.json
- ${PWD}/token.pickle:/bot/token.pickle
stop_signal: SIGINT

View File

@ -48,7 +48,7 @@ class MatrixModule(BotModule):
async def leave(self, bot, room, event):
bot.must_be_admin(room, event)
print(f'{event.sender} asked bot to leave room {room.room_id}')
self.logger.info(f'{event.sender} asked bot to leave room {room.room_id}')
await bot.send_text(room, f'By your command.')
await bot.client.room_leave(room.room_id)
@ -89,13 +89,12 @@ class MatrixModule(BotModule):
async def quit(self, bot, room, event):
bot.must_be_admin(room, event)
await bot.send_text(room, f'Quitting, as requested')
print(f'{event.sender} commanded bot to quit, so quitting..')
self.logger.info(f'{event.sender} commanded bot to quit, so quitting..')
bot.bot_task.cancel()
async def enable_module(self, bot, room, event, module_name):
bot.must_be_admin(room, event)
print(f"asked to enable {module_name}")
self.logger.info(f"asked to enable {module_name}")
if bot.modules.get(module_name):
module = bot.modules.get(module_name)
module.enable()
@ -107,8 +106,7 @@ class MatrixModule(BotModule):
async def disable_module(self, bot, room, event, module_name):
bot.must_be_admin(room, event)
print(f"asked to disable {module_name}")
self.logger.info(f"asked to disable {module_name}")
if bot.modules.get(module_name):
module = bot.modules.get(module_name)
if module.can_be_disabled:

View File

@ -1,3 +1,4 @@
import logging
from abc import ABC, abstractmethod
from nio import RoomMessageText, MatrixRoom
@ -30,6 +31,7 @@ class BotModule(ABC):
self.enabled = True
self.can_be_disabled = True
self.name = name
self.logger = logging.getLogger("module " + self.name)
def matrix_start(self, bot):
"""Called once on startup
@ -37,7 +39,7 @@ class BotModule(ABC):
:param bot: a reference to the bot
:type bot: Bot
"""
print('Starting', self.name, '..')
self.logger.info('Starting..')
@abstractmethod
async def matrix_message(self, bot, room, event):
@ -58,7 +60,7 @@ class BotModule(ABC):
:param bot: a reference to the bot
:type bot: Bot
"""
print('Stopping', self.name, '..')
self.logger.info('Stopping..')
async def matrix_poll(self, bot, pollcount):
"""Called every 10 seconds

View File

@ -33,7 +33,7 @@ class PollingService(BotModule):
for account in accounts:
await self.poll_account(bot, account, roomid, send_messages)
else:
print(f'Bot is no longer in room {roomid} - deleting it from {self.service_name} room list')
self.logger.warning(f'Bot is no longer in room {roomid} - deleting it from {self.service_name} room list')
delete_rooms.append(roomid)
for roomid in delete_rooms:
self.account_rooms.pop(roomid, None)
@ -62,7 +62,7 @@ class PollingService(BotModule):
f"Next poll in this room at {self.next_poll_time.get(room.room_id)} - in {self.next_poll_time.get(room.room_id) - datetime.now()}")
elif args[1] == 'poll':
bot.must_be_owner(event)
print(f'{self.service_name} force polling requested by {event.sender}')
self.logger.info(f'{self.service_name} force polling requested by {event.sender}')
# Faking next poll times to force poll
for roomid in self.account_rooms:
self.next_poll_time[roomid] = datetime.now() - timedelta(hours=1)
@ -77,7 +77,7 @@ class PollingService(BotModule):
bot.must_be_admin(room, event)
account = args[2]
print(f'Adding {self.service_name} account {account} to room id {room.room_id}')
self.logger.info(f'Adding {self.service_name} account {account} to room id {room.room_id}')
if self.account_rooms.get(room.room_id):
if account not in self.account_rooms[room.room_id]:
@ -94,12 +94,12 @@ class PollingService(BotModule):
bot.must_be_admin(room, event)
account = args[2]
print(f'Removing {self.service_name} account {account} from room id {room.room_id}')
self.logger.info(f'Removing {self.service_name} account {account} from room id {room.room_id}')
if self.account_rooms.get(room.room_id):
self.account_rooms[room.room_id].remove(account)
print(f'{self.service_name} accounts now for this room {self.account_rooms.get(room.room_id)}')
self.logger.info(f'{self.service_name} accounts now for this room {self.account_rooms.get(room.room_id)}')
bot.save_settings()
await bot.send_text(room, f'Removed {self.service_name} account from this room')

View File

@ -1,5 +1,6 @@
import shlex
from datetime import datetime
from .common.module import BotModule

View File

@ -7,7 +7,8 @@ class MatrixModule(BotModule):
args.pop(0)
# Echo what they said back
self.logger.debug(f"room: {room.name} sender: {event.sender} wants an echo")
await bot.send_text(room, ' '.join(args))
def help(self):
return ('Echoes back what user has said')
return 'Echoes back what user has said'

View File

@ -9,7 +9,6 @@ from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
#
# Google calendar notifications
#
@ -40,10 +39,10 @@ class MatrixModule(BotModule):
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
print('Loaded existing pickle file')
self.logger.info('Loaded existing pickle file')
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
print('No credentials or credentials not valid!')
self.logger.warn('No credentials or credentials not valid!')
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
@ -53,19 +52,17 @@ class MatrixModule(BotModule):
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
print('Pickle saved')
self.logger.info('Pickle saved')
self.service = build('calendar', 'v3', credentials=creds)
try:
calendar_list = self.service.calendarList().list().execute()[
'items']
print(
f'Google calendar set up successfully with access to {len(calendar_list)} calendars:\n')
calendar_list = self.service.calendarList().list().execute()['items']
self.logger.info(f'Google calendar set up successfully with access to {len(calendar_list)} calendars:\n')
for calendar in calendar_list:
print(calendar['summary'] + ' - ' + calendar['id'])
self.logger.info(f"{calendar['summary']} - + {calendar['id']}")
except Exception:
print('Getting calendar list failed!')
self.logger.error('Getting calendar list failed!')
async def matrix_message(self, bot, room, event):
if not self.service:
@ -78,7 +75,7 @@ class MatrixModule(BotModule):
if len(args) == 2:
if args[1] == 'today':
for calid in calendars:
print('Listing events in cal', calid)
self.logger.info(f'Listing events in cal {calid}')
events = events + self.list_today(calid)
if args[1] == 'list':
await bot.send_text(room, 'Calendars in this room: ' + str(self.calendar_rooms.get(room.room_id)))
@ -89,7 +86,7 @@ class MatrixModule(BotModule):
bot.must_be_admin(room, event)
calid = args[2]
print(f'Adding calendar {calid} to room id {room.room_id}')
self.logger.info(f'Adding calendar {calid} to room id {room.room_id}')
if self.calendar_rooms.get(room.room_id):
if calid not in self.calendar_rooms[room.room_id]:
@ -100,8 +97,7 @@ class MatrixModule(BotModule):
else:
self.calendar_rooms[room.room_id] = [calid]
print(
f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
self.logger.info(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
bot.save_settings()
@ -112,13 +108,12 @@ class MatrixModule(BotModule):
bot.must_be_admin(room, event)
calid = args[2]
print(f'Removing calendar {calid} from room id {room.room_id}')
self.logger.info(f'Removing calendar {calid} from room id {room.room_id}')
if self.calendar_rooms.get(room.room_id):
self.calendar_rooms[room.room_id].remove(calid)
print(
f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
self.logger.info(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
bot.save_settings()
@ -127,14 +122,14 @@ class MatrixModule(BotModule):
else:
for calid in calendars:
print('Listing events in cal', calid)
self.logger.info(f'Listing events in cal {calid}')
events = events + self.list_upcoming(calid)
if len(events) > 0:
print(f'Found {len(events)} events')
self.logger.info(f'Found {len(events)} events')
await self.send_events(bot, events, room)
else:
print(f'No events found')
self.logger.info(f'No events found')
await bot.send_text(room, 'No events found, try again later :)')
async def send_events(self, bot, events, room):
@ -154,19 +149,18 @@ class MatrixModule(BotModule):
def list_today(self, calid):
startTime = datetime.utcnow()
startTime = startTime.replace(
hour=0, minute=0, second=0, microsecond=0)
startTime = startTime.replace(hour=0, minute=0, second=0, microsecond=0)
endTime = startTime + timedelta(hours=24)
now = startTime.isoformat() + 'Z'
end = endTime.isoformat() + 'Z'
print('Looking for events between', now, end)
self.logger.info(f'Looking for events between {now} {end}')
events_result = self.service.events().list(calendarId=calid, timeMin=now,
timeMax=end, maxResults=10, singleEvents=True,
orderBy='startTime').execute()
return events_result.get('items', [])
def help(self):
return ('Google calendar. Lists 10 next events by default. today = list today\'s events.')
return 'Google calendar. Lists 10 next events by default. today = list today\'s events.'
def get_settings(self):
data = super().get_settings()

View File

@ -19,7 +19,7 @@ class MatrixModule(PollingService):
async def poll_implementation(self, bot, account, roomid, send_messages):
try:
medias = self.instagram.get_medias(account, 5)
print(f'Polling instagram account {account} for room {roomid} - got {len(medias)} posts.')
self.logger.info(f'Polling instagram account {account} for room {roomid} - got {len(medias)} posts.')
for media in medias:
if send_messages:
if media.identifier not in self.known_ids:
@ -29,12 +29,11 @@ class MatrixModule(PollingService):
self.known_ids.add(media.identifier)
except InstagramNotFoundException:
print('ig error: there is ', account,
' account that does not exist - deleting from room')
self.logger.error(f"{account} does not exist - deleting from room")
self.account_rooms[roomid].remove(account)
bot.save_settings()
except Exception:
print('Polling instagram account failed:')
self.logger.error('Polling instagram account failed:')
traceback.print_exc(file=sys.stderr)
polldelay = timedelta(minutes=30 + randrange(30))

View File

@ -1,5 +1,6 @@
from geopy.geocoders import Nominatim
from nio import RoomMessageUnknown, AsyncClient
from nio import RoomMessageUnknown
from modules.common.module import BotModule
@ -50,9 +51,9 @@ class MatrixModule(BotModule):
else:
query = event.body[4:]
geolocator = Nominatim(user_agent=bot.appid)
print('loc: looking up', query, '..')
self.logger.info('loc: looking up %s ..', query)
location = geolocator.geocode(query)
print('loc rx', location)
self.logger.info('loc rx %s', location)
if location:
locationmsg = {
"body": str(location.address),

View File

@ -3,7 +3,6 @@ from datetime import datetime
from pyteamup import Calendar
#
# TeamUp calendar notifications
#
@ -48,7 +47,7 @@ class MatrixModule(BotModule):
bot.must_be_admin(room, event)
calid = args[2]
print(f'Adding calendar {calid} to room id {room.room_id}')
self.logger.info(f'Adding calendar {calid} to room id {room.room_id}')
if self.calendar_rooms.get(room.room_id):
if calid not in self.calendar_rooms[room.room_id]:
@ -59,8 +58,7 @@ class MatrixModule(BotModule):
else:
self.calendar_rooms[room.room_id] = [calid]
print(
f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
self.logger.info(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
bot.save_settings()
self.setup_calendars()
@ -69,13 +67,12 @@ class MatrixModule(BotModule):
bot.must_be_admin(room, event)
calid = args[2]
print(f'Removing calendar {calid} from room id {room.room_id}')
self.logger.info(f'Removing calendar {calid} from room id {room.room_id}')
if self.calendar_rooms.get(room.room_id):
self.calendar_rooms[room.room_id].remove(calid)
print(
f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
self.logger.info(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
bot.save_settings()
self.setup_calendars()

View File

@ -16,7 +16,7 @@ class MatrixModule(PollingService):
async def poll_implementation(self, bot, account, roomid, send_messages):
try:
tweets = query_tweets_from_user(account, limit=1)
print(f'Polling twitter account {account} - got {len(tweets)} tweets')
self.logger.info(f'Polling twitter account {account} - got {len(tweets)} tweets')
for tweet in tweets:
if tweet.tweet_id not in self.known_ids:
if send_messages:
@ -25,5 +25,5 @@ class MatrixModule(PollingService):
f'Twitter {account}: {tweet.text} - https://twitter.com{tweet.tweet_url}')
self.known_ids.add(tweet.tweet_id)
except Exception:
print('Polling twitter account failed:')
self.logger.error('Polling twitter account failed:')
traceback.print_exc(file=sys.stderr)

View File

@ -100,11 +100,11 @@ class MatrixModule(BotModule):
try:
r = httpx.get(url)
except Exception as e:
print(f"Failed fetching url {url}. Error: {e}")
self.logger.error(f"Failed fetching url {url}. Error: {e}")
return (title, description)
if r.status_code != 200:
print(f"Failed fetching url {url}. Status code: {r.status_code}")
self.logger.info(f"Failed fetching url {url}. Status code: {r.status_code}")
return (title, description)
# try parse and get the title
@ -115,7 +115,7 @@ class MatrixModule(BotModule):
if descr_tag:
description = descr_tag.get("content", None)
except Exception as e:
print(f"Failed parsing response from url {url}. Error: {e}")
self.logger.error(f"Failed parsing response from url {url}. Error: {e}")
return (title, description)
return (title, description)