With small changes, comes great change
Introduced asynchronous plugins that gather their data on different intervals than the mainloop. Here it is used for the modsde plugin. The statushandler has a new class Module, which acts as documentation for the API These changes let the output evenly flow, even if an async plugin hangs due to network problems or similiar issues.
This commit is contained in:
parent
80d7184e14
commit
db94df07a3
98
modsde.py
98
modsde.py
@ -2,75 +2,84 @@
|
||||
|
||||
import sys
|
||||
import json
|
||||
from datetime import datetime,timedelta
|
||||
import time
|
||||
import threading
|
||||
import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse
|
||||
import re
|
||||
import http.cookiejar
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
class LoginError(Exception):
|
||||
pass
|
||||
|
||||
class ModsDeChecker(object):
|
||||
"""
|
||||
This class returns i3status parsable output of the number of
|
||||
unread posts in any bookmark in the mods.de forums.
|
||||
"""
|
||||
|
||||
last_checked = datetime.now()
|
||||
unread_cache = 0
|
||||
login_url = 'http://login.mods.de/'
|
||||
async = True
|
||||
output = None
|
||||
|
||||
login_url = "http://login.mods.de/"
|
||||
bookmark_url = "http://forum.mods.de/bb/xml/bookmarks.php"
|
||||
opener = None
|
||||
cj = None
|
||||
logged_in = False
|
||||
|
||||
settings = {
|
||||
'color': '#7181fe',
|
||||
'pause': 20,
|
||||
'username': "",
|
||||
'password': ""
|
||||
"color": "#7181fe",
|
||||
"pause": 20,
|
||||
"username": "",
|
||||
"password": "",
|
||||
"offset": 0,
|
||||
}
|
||||
|
||||
def __init__(self, settings = None):
|
||||
self.settings.update(settings)
|
||||
self.cj = http.cookiejar.CookieJar()
|
||||
self.last_checked = \
|
||||
datetime.now() - timedelta(seconds=self.settings['pause'])
|
||||
self.opener = urllib.request.build_opener(
|
||||
urllib.request.HTTPCookieProcessor(self.cj))
|
||||
self.opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(self.cj))
|
||||
|
||||
self.thread = threading.Thread(target=self.mainloop)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
|
||||
def mainloop(self):
|
||||
while True:
|
||||
unread = self.get_unread_count()
|
||||
|
||||
if not unread:
|
||||
self.output = None
|
||||
else:
|
||||
self.output = {"full_text" : "%d new posts in bookmarks" % unread,
|
||||
"name" : "modsde",
|
||||
"urgent" : "true",
|
||||
"color" : self.settings["color"]}
|
||||
|
||||
time.sleep(self.settings["pause"])
|
||||
|
||||
def get_unread_count(self):
|
||||
delta = datetime.now() - self.last_checked
|
||||
if not self.logged_in:
|
||||
self.login()
|
||||
|
||||
if delta.total_seconds() > self.settings['pause']:
|
||||
if not self.logged_in:
|
||||
try:
|
||||
self.login()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
f = self.opener.open(self.bookmark_url)
|
||||
root = ET.fromstring(f.read())
|
||||
self.last_checked = datetime.now()
|
||||
self.unread_cache = int(root.attrib['newposts'])
|
||||
except Exception:
|
||||
self.cj.clear()
|
||||
self.opener = urllib.request.build_opener(
|
||||
urllib.request.HTTPCookieProcessor(self.cj))
|
||||
self.logged_in = False
|
||||
|
||||
return self.unread_cache
|
||||
|
||||
try:
|
||||
f = self.opener.open(self.bookmark_url)
|
||||
root = ET.fromstring(f.read())
|
||||
return int(root.attrib["newposts"]) - self.settings["offset"]
|
||||
except Exception:
|
||||
self.cj.clear()
|
||||
self.opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(self.cj))
|
||||
self.logged_in = False
|
||||
|
||||
def login(self):
|
||||
|
||||
data = urllib.parse.urlencode({
|
||||
"login_username": self.settings["username"],
|
||||
"login_password": self.settings["password"],
|
||||
"login_lifetime": "31536000"
|
||||
})
|
||||
|
||||
response = self.opener.open(self.login_url, data)
|
||||
m = re.search("http://forum.mods.de/SSO.php[^']*", response.read())
|
||||
response = self.opener.open(self.login_url, data.encode("ascii"))
|
||||
m = re.search("http://forum.mods.de/SSO.php[^']*", response.read().decode("ISO-8859-15"))
|
||||
self.cj.clear()
|
||||
|
||||
if m and m.group(0):
|
||||
@ -79,20 +88,5 @@ class ModsDeChecker(object):
|
||||
for cookie in self.cj:
|
||||
self.cj.clear
|
||||
self.logged_in = True
|
||||
self.opener.addheaders.append(('Cookie',
|
||||
'{}={}'.format(cookie.name, cookie.value)))
|
||||
self.opener.addheaders.append(('Cookie', '{}={}'.format(cookie.name, cookie.value)))
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def output(self):
|
||||
|
||||
unread = self.get_unread_count()
|
||||
|
||||
if not unread:
|
||||
return None
|
||||
|
||||
return {'full_text' : '%d new posts in bookmarks' % unread,
|
||||
'name' : 'modsde',
|
||||
'urgent' : 'true',
|
||||
'color' : self.settings['color']}
|
||||
|
@ -4,6 +4,16 @@ import sys
|
||||
import json
|
||||
import urllib.request, urllib.error, urllib.parse
|
||||
|
||||
class Module(object):
|
||||
output = None
|
||||
async = False
|
||||
|
||||
def registered(self, status_handler):
|
||||
"""Called when this module is registered with a status handler"""
|
||||
|
||||
def run(self):
|
||||
"""Only called if self.async == False. Called once per tick"""
|
||||
|
||||
class I3statusHandler(object):
|
||||
modules = []
|
||||
|
||||
@ -11,24 +21,24 @@ class I3statusHandler(object):
|
||||
pass
|
||||
|
||||
def register_module(self, module):
|
||||
""" Register a new module. """
|
||||
"""Register a new module."""
|
||||
|
||||
# check if module implemented the
|
||||
# correct functions
|
||||
if not hasattr(module, 'output'):
|
||||
raise Exception("Module %s does not implement \
|
||||
all the needed functions!".format(module))
|
||||
#if not hasattr(module, 'output'):
|
||||
# raise Exception("Module %s does not implement \
|
||||
# all the needed functions!".format(module))
|
||||
|
||||
self.modules.append(module)
|
||||
|
||||
def print_line(self, message):
|
||||
""" Non-buffered printing to stdout. """
|
||||
"""Unbuffered printing to stdout."""
|
||||
|
||||
sys.stdout.write(message + '\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
def read_line(self):
|
||||
""" Interrupted respecting reader for stdin. """
|
||||
"""Interrupted respecting reader for stdin."""
|
||||
|
||||
# try reading a line, removing any extra whitespace
|
||||
try:
|
||||
@ -52,13 +62,16 @@ class I3statusHandler(object):
|
||||
if line.startswith(','):
|
||||
line, prefix = line[1:], ','
|
||||
|
||||
j = json.loads(line)
|
||||
j = [] #json.loads(line)
|
||||
|
||||
for module in self.modules:
|
||||
output = module.output()
|
||||
if not module.async:
|
||||
module.tick()
|
||||
|
||||
output = module.output
|
||||
|
||||
if output:
|
||||
j.insert(0, module.output())
|
||||
j.insert(0, output)
|
||||
|
||||
# and echo back new encoded json
|
||||
self.print_line(prefix+json.dumps(j))
|
||||
|
@ -10,6 +10,7 @@
|
||||
import dbus, gobject
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
import json
|
||||
import threading
|
||||
|
||||
class ThunderbirdMailChecker(object):
|
||||
"""
|
||||
@ -17,7 +18,10 @@ class ThunderbirdMailChecker(object):
|
||||
the dbus-sender extension for thunderbird.
|
||||
"""
|
||||
|
||||
unread = []
|
||||
async = False
|
||||
output = None
|
||||
|
||||
unread = set()
|
||||
|
||||
def __init__(self):
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
@ -32,20 +36,28 @@ class ThunderbirdMailChecker(object):
|
||||
dbus.mainloop.glib.threads_init()
|
||||
self.context = loop.get_context()
|
||||
|
||||
def tick(self):
|
||||
self.context.iteration(False)
|
||||
|
||||
def new_msg(self, id, author, subject):
|
||||
if id not in self.unread:
|
||||
self.unread.append(id)
|
||||
self.unread.add(id)
|
||||
self._output()
|
||||
|
||||
def changed_msg(self, id, event):
|
||||
if event == "read" and id in self.unread:
|
||||
self.unread.remove(id)
|
||||
self._output()
|
||||
|
||||
def output(self):
|
||||
def _output(self):
|
||||
self.context.iteration(False)
|
||||
|
||||
unread = len(self.unread)
|
||||
|
||||
return {'full_text' : '%d new email' % unread,
|
||||
if unread:
|
||||
self.output = {'full_text' : '%d new email' % unread,
|
||||
'name' : 'newmail-tb',
|
||||
'urgent' : True,
|
||||
'color' : '#ff0000' } if unread else None
|
||||
'color' : '#ff0000' }
|
||||
else:
|
||||
self.output = None
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user