extract BotModule class

This commit is contained in:
Frank Becker 2020-02-02 22:08:15 +01:00
parent 78901ea505
commit 16ade59c0c
20 changed files with 226 additions and 99 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
# editors # editors
.vscode .vscode
.idea
# ignore Pipfile.lock # ignore Pipfile.lock
Pipfile.lock Pipfile.lock

9
bot.py
View File

@ -9,10 +9,11 @@ import re
import sys import sys
import traceback import traceback
import urllib.parse import urllib.parse
from importlib import reload
import requests import requests
from nio import AsyncClient, InviteEvent, JoinError, RoomMessageText from nio import AsyncClient, InviteEvent, JoinError, RoomMessageText
from importlib import reload
# Couple of custom exceptions # Couple of custom exceptions
@ -125,7 +126,8 @@ class Bot:
except CommandRequiresOwner: except CommandRequiresOwner:
await self.send_text(room, f'Sorry, only bot owner can run that command.') await self.send_text(room, f'Sorry, only bot owner can run that command.')
except Exception: 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) traceback.print_exc(file=sys.stderr)
async def invite_cb(self, room, event): async def invite_cb(self, room, event):
@ -144,6 +146,7 @@ class Bot:
def load_module(self, modulename): def load_module(self, modulename):
try: try:
print("load module: " + modulename)
module = importlib.import_module('modules.' + modulename) module = importlib.import_module('modules.' + modulename)
module = reload(module) module = reload(module)
cls = getattr(module, 'MatrixModule') cls = getattr(module, 'MatrixModule')
@ -168,7 +171,7 @@ class Bot:
moduleobject = self.load_module(modulename) moduleobject = self.load_module(modulename)
if moduleobject: if moduleobject:
self.modules[modulename] = moduleobject self.modules[modulename] = moduleobject
def clear_modules(self): def clear_modules(self):
self.modules = dict() self.modules = dict()

View File

@ -1,30 +1,33 @@
import urllib.request from datetime import datetime
from datetime import datetime, timedelta from modules.common.module import BotModule
class MatrixModule(BotModule):
class MatrixModule:
def matrix_start(self, bot): def matrix_start(self, bot):
self.starttime = datetime.now() self.starttime = datetime.now()
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
if len(args) == 2: if len(args) == 2:
if args[1]=='quit': if args[1] == 'quit':
bot.must_be_admin(room, event) bot.must_be_admin(room, event)
await bot.send_text(room, f'Quitting, as requested') await bot.send_text(room, f'Quitting, as requested')
print(f'{event.sender} commanded bot to quit, so quitting..') print(f'{event.sender} commanded bot to quit, so quitting..')
bot.bot_task.cancel() bot.bot_task.cancel()
elif args[1]=='version': elif args[1] == 'version':
await bot.send_text(room, f'Hemppa version {bot.version} - https://github.com/vranki/hemppa') await bot.send_text(room, f'Hemppa version {bot.version} - https://github.com/vranki/hemppa')
elif args[1]=='reload': elif args[1] == 'reload':
bot.must_be_admin(room, event) bot.must_be_admin(room, event)
await bot.send_text(room, f'Reloading modules..') await bot.send_text(room, f'Reloading modules..')
bot.stop() bot.stop()
bot.reload_modules() bot.reload_modules()
bot.start() bot.start()
elif args[1]=='status': elif args[1] == 'status':
uptime = datetime.now() - self.starttime uptime = datetime.now() - self.starttime
await bot.send_text(room, f'Uptime {uptime} - system time is {datetime.now()} - loaded {len(bot.modules)} modules.') await bot.send_text(room,
elif args[1]=='stats': f'Uptime {uptime} - system time is {datetime.now()} - loaded {len(bot.modules)} modules.')
elif args[1] == 'stats':
roomcount = len(bot.client.rooms) roomcount = len(bot.client.rooms)
usercount = 0 usercount = 0
homeservers = dict() homeservers = dict()
@ -44,8 +47,9 @@ class MatrixModule:
if len(homeservers) > 10: if len(homeservers) > 10:
homeservers = homeservers[0:10] homeservers = homeservers[0:10]
await bot.send_text(room, f'I\'m seeing {usercount} users in {roomcount} rooms. Top ten homeservers: {homeservers}') await bot.send_text(room,
elif args[1]=='leave': f'I\'m seeing {usercount} users in {roomcount} rooms. Top ten homeservers: {homeservers}')
elif args[1] == 'leave':
bot.must_be_admin(room, event) bot.must_be_admin(room, event)
print(f'{event.sender} asked bot to leave room {room.room_id}') print(f'{event.sender} asked bot to leave room {room.room_id}')
await bot.send_text(room, f'By your command.') await bot.send_text(room, f'By your command.')
@ -55,4 +59,4 @@ class MatrixModule:
await bot.send_text(room, 'Unknown command, sorry.') await bot.send_text(room, 'Unknown command, sorry.')
def help(self): def help(self):
return('Bot management commands') return 'Bot management commands'

86
modules/common/module.py Normal file
View File

@ -0,0 +1,86 @@
from abc import ABC, abstractmethod
from nio import RoomMessageText, Event
class BotModule(ABC):
"""Abtract bot module
A module derives from this class to process and interact on room messages. The subcluss must be named `MatrixModule`.
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.
Example:
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event):
args = event.body.split()
args.pop(0)
# Echo what they said back
await bot.send_text(room, ' '.join(args))
def help(self):
return 'Echoes back what user has said'
"""
def matrix_start(self, bot):
"""Called once on startup
:param bot: a reference to the bot
:type bot: Bot
"""
pass
@abstractmethod
async def matrix_message(self, bot, room, event):
"""Called when a message is sent to room starting with !module_name
:param bot: a reference to the bot
:type bot: Bot
:param room: a matrix room message
:type room: RoomMessageText
:param event: a handle to the event that triggered the callback
:type event: Event
"""
pass
def matrix_stop(self, bot):
"""Called once before exit
:param bot: a reference to the bot
:type bot: Bot
"""
pass
async def matrix_poll(self, bot, pollcount):
"""Called every 10 seconds
:param bot: a reference to the bot
:type bot: Bot
:param pollcount: the actual poll count
:type pollcount: int
"""
pass
@abstractmethod
def help(self):
"""Return one-liner help text"""
pass
def get_settings(self):
"""Must return a dict object that can be converted to JSON and sent to server
:return: a dict object that can be converted to JSON
:rtype: dict
"""
pass
def set_settings(self, data):
"""Load these settings. It should be the same JSON you returned in previous get_settings
:param data: a dict object containing the settings read from the account
:type data: dict
"""
pass

View File

@ -1,15 +1,14 @@
import traceback
import sys
from datetime import datetime, timedelta from datetime import datetime, timedelta
from random import randrange from random import randrange
class PollingService: class PollingService:
def __init__(self): def __init__(self):
self.known_ids = set() self.known_ids = set()
self.account_rooms = dict() # Roomid -> [account, account..] self.account_rooms = dict() # Roomid -> [account, account..]
self.next_poll_time = dict() # Roomid -> datetime, None = not polled yet self.next_poll_time = dict() # Roomid -> datetime, None = not polled yet
self.service_name = "Service" self.service_name = "Service"
self.poll_interval_min = 30 # TODO: Configurable self.poll_interval_min = 30 # TODO: Configurable
self.poll_interval_random = 30 self.poll_interval_random = 30
async def matrix_poll(self, bot, pollcount): async def matrix_poll(self, bot, pollcount):
@ -47,16 +46,17 @@ class PollingService:
await self.poll_implementation(bot, account, roomid, send_messages) await self.poll_implementation(bot, account, roomid, send_messages)
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
if len(args) == 2: if len(args) == 2:
if args[1] == 'list': if args[1] == 'list':
await bot.send_text(room, f'{self.service_name} accounts in this room: {self.account_rooms.get(room.room_id) or []}') await bot.send_text(room,
f'{self.service_name} accounts in this room: {self.account_rooms.get(room.room_id) or []}')
elif args[1] == 'debug': elif args[1] == 'debug':
await bot.send_text(room, f"{self.service_name} accounts: {self.account_rooms.get(room.room_id) or []} - known ids: {self.known_ids}\n" \ await bot.send_text(room,
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()}") f"{self.service_name} accounts: {self.account_rooms.get(room.room_id) or []} - known ids: {self.known_ids}\n" \
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': elif args[1] == 'poll':
bot.must_be_owner(event) bot.must_be_owner(event)
print(f'{self.service_name} force polling requested by {event.sender}') print(f'{self.service_name} force polling requested by {event.sender}')
@ -111,4 +111,4 @@ class PollingService:
self.account_rooms = data['account_rooms'] self.account_rooms = data['account_rooms']
def help(self): def help(self):
return(f'{self.service_name} polling') return f'{self.service_name} polling'

View File

@ -1,8 +1,9 @@
import shlex import shlex
from datetime import datetime from datetime import datetime
from .common.module import BotModule
class MatrixModule: class MatrixModule(BotModule):
daily_commands = dict() # room_id -> command json daily_commands = dict() # room_id -> command json
last_hour = datetime.now().hour last_hour = datetime.now().hour
@ -30,7 +31,7 @@ class MatrixModule:
await bot.send_text(room, 'Cleared commands on this room.') await bot.send_text(room, 'Cleared commands on this room.')
def help(self): def help(self):
return('Runs scheduled commands') return ('Runs scheduled commands')
def get_settings(self): def get_settings(self):
return {'daily_commands': self.daily_commands} return {'daily_commands': self.daily_commands}
@ -54,4 +55,4 @@ class MatrixModule:
delete_rooms.append(room_id) delete_rooms.append(room_id)
for roomid in delete_rooms: for roomid in delete_rooms:
self.daily_commands.pop(roomid, None) self.daily_commands.pop(roomid, None)

View File

@ -1,4 +1,7 @@
class MatrixModule: from modules.common.module import BotModule
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
args.pop(0) args.pop(0)
@ -7,4 +10,4 @@ class MatrixModule:
await bot.send_text(room, ' '.join(args)) await bot.send_text(room, ' '.join(args))
def help(self): def help(self):
return('Echoes back what user has said') return ('Echoes back what user has said')

View File

@ -1,4 +1,7 @@
class MatrixModule: from modules.common.module import BotModule
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
msg = f'This is Hemppa {bot.version}, a generic Matrix bot. Known commands:\n\n' msg = f'This is Hemppa {bot.version}, a generic Matrix bot. Known commands:\n\n'
@ -13,4 +16,4 @@ class MatrixModule:
await bot.send_text(room, msg) await bot.send_text(room, msg)
def help(self): def help(self):
return('Prints help on commands') return 'Prints help on commands'

View File

@ -1,8 +1,9 @@
from geopy.geocoders import Nominatim from geopy.geocoders import Nominatim
from nio import RoomMessageUnknown from nio import RoomMessageUnknown
from modules.common.module import BotModule
class MatrixModule: class MatrixModule(BotModule):
bot = None bot = None
def matrix_start(self, bot): def matrix_start(self, bot):
@ -29,7 +30,7 @@ class MatrixModule:
float(latlon[1]) float(latlon[1])
osm_link = 'https://www.openstreetmap.org/?mlat=' + \ osm_link = 'https://www.openstreetmap.org/?mlat=' + \
latlon[0] + "&mlon=" + latlon[1] latlon[0] + "&mlon=" + latlon[1]
plain = sender + ' 🚩 ' + osm_link plain = sender + ' 🚩 ' + osm_link
html = f'{sender} 🚩 <a href={osm_link}>{location_text}</a>' html = f'{sender} 🚩 <a href={osm_link}>{location_text}</a>'
@ -58,4 +59,4 @@ class MatrixModule:
await bot.send_text(room, "Can't find " + query + " on map!") await bot.send_text(room, "Can't find " + query + " on map!")
def help(self): def help(self):
return('Search for locations and display Matrix location events as OSM links') return 'Search for locations and display Matrix location events as OSM links'

View File

@ -9,6 +9,7 @@ from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build from googleapiclient.discovery import build
# #
# Google calendar notifications # Google calendar notifications
# #
@ -16,9 +17,10 @@ from googleapiclient.discovery import build
# It's created on first run (run from console!) and # It's created on first run (run from console!) and
# can be copied to another computer. # can be copied to another computer.
# #
from modules.common.module import BotModule
class MatrixModule: class MatrixModule(BotModule):
def matrix_start(self, bot): def matrix_start(self, bot):
self.bot = bot self.bot = bot
self.SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'] self.SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
@ -135,7 +137,8 @@ class MatrixModule:
async def send_events(self, bot, events, room): async def send_events(self, bot, events, room):
for event in events: for event in events:
start = event['start'].get('dateTime', event['start'].get('date')) start = event['start'].get('dateTime', event['start'].get('date'))
await bot.send_html(room, f'{self.parse_date(start)} <a href="{event["htmlLink"]}">{event["summary"]}</a>', f'{self.parse_date(start)} {event["summary"]}') await bot.send_html(room, f'{self.parse_date(start)} <a href="{event["htmlLink"]}">{event["summary"]}</a>',
f'{self.parse_date(start)} {event["summary"]}')
def list_upcoming(self, calid): def list_upcoming(self, calid):
startTime = datetime.utcnow() startTime = datetime.utcnow()
@ -160,7 +163,7 @@ class MatrixModule:
return events_result.get('items', []) return events_result.get('items', [])
def help(self): 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): def get_settings(self):
return {'calendar_rooms': self.calendar_rooms} return {'calendar_rooms': self.calendar_rooms}

View File

@ -1,13 +1,15 @@
import traceback
import sys import sys
import traceback
from datetime import datetime, timedelta from datetime import datetime, timedelta
from random import randrange from random import randrange
from modules.common.pollingservice import PollingService
from igramscraper.exception.instagram_not_found_exception import \ from igramscraper.exception.instagram_not_found_exception import \
InstagramNotFoundException InstagramNotFoundException
from igramscraper.instagram import Instagram from igramscraper.instagram import Instagram
from modules.common.pollingservice import PollingService
class MatrixModule(PollingService): class MatrixModule(PollingService):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -21,12 +23,14 @@ class MatrixModule(PollingService):
for media in medias: for media in medias:
if send_messages: if send_messages:
if media.identifier not in self.known_ids: if media.identifier not in self.known_ids:
await bot.send_html(bot.get_room_by_id(roomid), f'<a href="{media.link}">Instagram {account}:</a> {media.caption}', f'{account}: {media.caption} {media.link}') await bot.send_html(bot.get_room_by_id(roomid),
f'<a href="{media.link}">Instagram {account}:</a> {media.caption}',
f'{account}: {media.caption} {media.link}')
self.known_ids.add(media.identifier) self.known_ids.add(media.identifier)
except InstagramNotFoundException: except InstagramNotFoundException:
print('ig error: there is ', account, print('ig error: there is ', account,
' account that does not exist - deleting from room') ' account that does not exist - deleting from room')
self.account_rooms[roomid].remove(account) self.account_rooms[roomid].remove(account)
bot.save_settings() bot.save_settings()
except Exception: except Exception:

View File

@ -1,13 +1,15 @@
import urllib.request import urllib.request
from modules.common.module import BotModule
class MatrixModule:
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
if len(args) == 2: if len(args) == 2:
icao = args[1] icao = args[1]
metar_url = "https://tgftp.nws.noaa.gov/data/observations/metar/stations/" + \ metar_url = "https://tgftp.nws.noaa.gov/data/observations/metar/stations/" + \
icao.upper() + ".TXT" icao.upper() + ".TXT"
response = urllib.request.urlopen(metar_url) response = urllib.request.urlopen(metar_url)
lines = response.readlines() lines = response.readlines()
await bot.send_text(room, lines[1].decode("utf-8").strip()) await bot.send_text(room, lines[1].decode("utf-8").strip())
@ -15,4 +17,4 @@ class MatrixModule:
await bot.send_text(room, 'Usage: !metar <icao code>') await bot.send_text(room, 'Usage: !metar <icao code>')
def help(self): def help(self):
return('Metar data access (usage: !metar <icao code>)') return ('Metar data access (usage: !metar <icao code>)')

View File

@ -1,8 +1,10 @@
import urllib.request
import re import re
import urllib.request
from modules.common.module import BotModule
class MatrixModule: class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
if len(args) == 2 and len(args[1]) == 4: if len(args) == 2 and len(args[1]) == 4:
@ -13,12 +15,12 @@ class MatrixModule:
await bot.send_text(room, 'Usage: !notam <icao code>') await bot.send_text(room, 'Usage: !notam <icao code>')
def help(self): def help(self):
return('NOTAM data access (usage: !notam <icao code>) - Currently Finnish airports only') return ('NOTAM data access (usage: !notam <icao code>) - Currently Finnish airports only')
# TODO: This handles only finnish airports. Implement support for other countries. # TODO: This handles only finnish airports. Implement support for other countries.
def get_notam(self, icao): def get_notam(self, icao):
if not icao.startswith('EF'): if not icao.startswith('EF'):
return('Only Finnish airports supported currently, sorry.') return ('Only Finnish airports supported currently, sorry.')
icao_first_letter = icao[2] icao_first_letter = icao[2]
if icao_first_letter < 'M': if icao_first_letter < 'M':

View File

@ -1,7 +1,9 @@
import urllib.request import urllib.request
from modules.common.module import BotModule
class MatrixModule:
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
if len(args) == 2: if len(args) == 2:
@ -18,4 +20,4 @@ class MatrixModule:
await bot.send_text(room, 'Usage: !taf <icao code>') await bot.send_text(room, 'Usage: !taf <icao code>')
def help(self): def help(self):
return('Taf data access (usage: !taf <icao code>)') return ('Taf data access (usage: !taf <icao code>)')

View File

@ -3,12 +3,14 @@ from datetime import datetime
from pyteamup import Calendar from pyteamup import Calendar
# #
# TeamUp calendar notifications # TeamUp calendar notifications
# #
from modules.common.module import BotModule
class MatrixModule: class MatrixModule(BotModule):
api_key = None api_key = None
calendar_rooms = dict() # Roomid -> [calid, calid..] calendar_rooms = dict() # Roomid -> [calid, calid..]
calendars = dict() # calid -> Calendar calendars = dict() # calid -> Calendar
@ -87,7 +89,7 @@ class MatrixModule:
await bot.send_text(room, 'Api key set') await bot.send_text(room, 'Api key set')
def help(self): def help(self):
return('Polls teamup calendar.') return ('Polls teamup calendar.')
async def poll_all_calendars(self, bot): async def poll_all_calendars(self, bot):
delete_rooms = [] delete_rooms = []
@ -102,7 +104,7 @@ class MatrixModule:
await bot.send_text(bot.get_room_by_id(roomid), 'Calendar: ' + self.eventToString(event)) await bot.send_text(bot.get_room_by_id(roomid), 'Calendar: ' + self.eventToString(event))
else: else:
delete_rooms.append(roomid) delete_rooms.append(roomid)
for roomid in delete_rooms: for roomid in delete_rooms:
self.calendar_rooms.pop(roomid, None) self.calendar_rooms.pop(roomid, None)
@ -115,7 +117,7 @@ class MatrixModule:
return datetime.strptime(dts, '%Y-%m-%dT%H:%M:%S') return datetime.strptime(dts, '%Y-%m-%dT%H:%M:%S')
except ValueError: except ValueError:
pos = len(dts) - 3 pos = len(dts) - 3
dts = dts[:pos] + dts[pos+1:] dts = dts[:pos] + dts[pos + 1:]
return datetime.strptime(dts, '%Y-%m-%dT%H:%M:%S%z') return datetime.strptime(dts, '%Y-%m-%dT%H:%M:%S%z')
def eventToString(self, event): def eventToString(self, event):
@ -123,7 +125,7 @@ class MatrixModule:
if len(event['title']) == 0: if len(event['title']) == 0:
event['title'] = '(empty name)' event['title'] = '(empty name)'
if(event['delete_dt']): if (event['delete_dt']):
s = event['title'] + ' deleted.' s = event['title'] + ' deleted.'
else: else:
s = event['title'] + " " + (event['notes'] or '') + \ s = event['title'] + " " + (event['notes'] or '') + \
@ -144,7 +146,7 @@ class MatrixModule:
self.calendars[calid].timestamp = int(time.time()) self.calendars[calid].timestamp = int(time.time())
def get_settings(self): def get_settings(self):
return {'apikey': self.api_key or '', 'calendar_rooms': self.calendar_rooms} return {'apikey': self.api_key or '', 'calendar_rooms': self.calendar_rooms}
def set_settings(self, data): def set_settings(self, data):
if data.get('calendar_rooms'): if data.get('calendar_rooms'):

View File

@ -1,9 +1,11 @@
from twitterscraper import query_tweets_from_user from twitterscraper import query_tweets_from_user
from modules.common.pollingservice import PollingService from modules.common.pollingservice import PollingService
# https://github.com/taspinar/twitterscraper/tree/master/twitterscraper # https://github.com/taspinar/twitterscraper/tree/master/twitterscraper
class MatrixModule(PollingService): class MatrixModule(PollingService):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.service_name = 'Twitter' self.service_name = 'Twitter'
@ -15,7 +17,9 @@ class MatrixModule(PollingService):
for tweet in tweets: for tweet in tweets:
if tweet.tweet_id not in self.known_ids: if tweet.tweet_id not in self.known_ids:
if send_messages: if send_messages:
await bot.send_html(bot.get_room_by_id(roomid), f'<a href="https://twitter.com{tweet.tweet_url}">Twitter {account}</a>: {tweet.text}', f'Twitter {account}: {tweet.text} - https://twitter.com{tweet.tweet_url}') await bot.send_html(bot.get_room_by_id(roomid),
f'<a href="https://twitter.com{tweet.tweet_url}">Twitter {account}</a>: {tweet.text}',
f'Twitter {account}: {tweet.text} - https://twitter.com{tweet.tweet_url}')
self.known_ids.add(tweet.tweet_id) self.known_ids.add(tweet.tweet_id)
except Exception: except Exception:
print('Polling twitter account failed:') print('Polling twitter account failed:')

View File

@ -6,8 +6,10 @@ import httpx
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from nio import RoomMessageText from nio import RoomMessageText
from modules.common.module import BotModule
class MatrixModule:
class MatrixModule(BotModule):
""" """
Simple url fetch and spit out title module. Simple url fetch and spit out title module.
@ -152,3 +154,7 @@ class MatrixModule:
def help(self): def help(self):
return "If I see a url in a message I will try to get the title from the page and spit it out" return "If I see a url in a message I will try to get the title from the page and spit it out"
def dump(self, obj):
for attr in dir(obj):
print("obj.%s = %r" % (attr, getattr(obj, attr)))

View File

@ -1,40 +1,37 @@
from timeit import default_timer as timer from timeit import default_timer as timer
import os
import sys
import urllib.request
from urllib.request import urlopen from urllib.request import urlopen
from modules.common.module import BotModule
class MatrixModule:
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
args.pop(0) args.pop(0)
url=args[0] url = args[0]
# check url # check url
if (not (url.startswith('http://') or url.startswith('https://'))): if not (url.startswith('http://') or url.startswith('https://')):
# print ("adding trailing https") # print ("adding trailing https")
url="https://"+url url = "https://" + url
print(url) print(url)
start = timer() start = timer()
try: try:
data = urlopen(url) data = urlopen(url)
length = format(len(data.read())/1024,'.3g') #kB length = format(len(data.read()) / 1024, '.3g') # kB
retcode = data.getcode() retcode = data.getcode()
except Exception as e: except Exception as e:
await bot.send_text(room, "Ping failed: " +str(e)) await bot.send_text(room, "Ping failed: " + str(e))
print ("Error: " + str(e)) print("Error: " + str(e))
return False return False
end = timer() end = timer()
await bot.send_text(room, url + ": OK (" + str(retcode) + ") / " + "Size: "+ str(length) + await bot.send_text(room, url + ": OK (" + str(retcode) + ") / " + "Size: " + str(length) +
" kB / Time: " + str(format(end - start, '.3g')) +" sec") " kB / Time: " + str(format(end - start, '.3g')) + " sec")
def help(self): def help(self):
return('check if IP or URL is accessable') return 'check if IP or URL is accessible'

View File

@ -1,30 +1,32 @@
import subprocess import subprocess
import os
class MatrixModule: from modules.common.module import BotModule
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
args.pop(0) args.pop(0)
encoding="utf-8" encoding = "utf-8"
allowed_args = ['list', 'add', 'del','done', 'undo', 'calc'] allowed_args = ['list', 'add', 'del', 'done', 'undo', 'calc']
# wrap task # wrap task
if not args: if not args:
args=['list'] args = ['list']
if args[0] not in allowed_args: if args[0] not in allowed_args:
await bot.send_text(room, "command not allowed") await bot.send_text(room, "command not allowed")
return() return ()
result = subprocess.check_output( result = subprocess.check_output(
["task", ["task",
"rc.confirmation:no", "rc.confirmation:no",
"rc.verbose:list", "rc.verbose:list",
"rc.bulk:0", "rc.bulk:0",
"rc.recurrence.confirmation:yes"] "rc.recurrence.confirmation:yes"]
+ args, stderr=subprocess.DEVNULL) + args, stderr=subprocess.DEVNULL)
await bot.send_text(room, result.decode(encoding)) await bot.send_text(room, result.decode(encoding))
def help(self): def help(self):
return('taskwarrior') return ('taskwarrior')

View File

@ -1,16 +1,17 @@
import subprocess import subprocess
import os from modules.common.module import BotModule
class MatrixModule:
class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
args.pop(0) args.pop(0)
encoding="utf-8" encoding = "utf-8"
# get weather from ansiweather # get weather from ansiweather
result = subprocess.check_output(["ansiweather","-a false","-l", ' '.join(args)]) result = subprocess.check_output(["ansiweather", "-a false", "-l", ' '.join(args)])
await bot.send_text(room, result.decode(encoding)) await bot.send_text(room, result.decode(encoding))
def help(self): def help(self):
return('How\'s the weather?') return ('How\'s the weather?')