Skip to content

Instantly share code, notes, and snippets.

@arty-name
Created December 23, 2012 13:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arty-name/4363417 to your computer and use it in GitHub Desktop.
Save arty-name/4363417 to your computer and use it in GitHub Desktop.
Simple bot to publish jabber statuses as atom feed + upstart configuration file
description "Logger of IM statuses"
author "Artemy Tregubenko <me@arty.name>"
start on runlevel [234]
stop on runlevel [0156]
expect daemon
respawn
chdir /var/www/shared_arty_name/im-status/
exec python /var/www/shared_arty_name/im-status/IMStatus.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import syslog
import signal
import daemon
import grp
import datetime
from pyxmpp.all import JID
from pyxmpp.jabber.client import JabberClient
from pyxmpp.streamtls import TLSSettings
from xml.sax.saxutils import escape
from pubsubhubbub_publish import publish
JID_VALUE = 'user@example.com/bot'
PASSWORD = '133t'
FILE_PATH = '/var/www/shared_arty_name/im-status/index.atom'
PUSH_URL = 'http://pubsubhubbub.appspot.com/'
SELF_URL = 'http://shared.arty.name/im-status/'
TEMPLATE = u"""<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>tag:shared.arty.name/im-status,2012:index.atom</id>
<link rel="hub" href="http://pubsubhubbub.appspot.com/"/>
<title>«Статусы» Артемия Трегубенко</title>
<link rel="self" href="http://shared.arty.name/im-status/"/>
<author>
<name>Артемий Трегубенко</name>
<email>me@arty.name</email>
<uri>http://arty.name</uri>
</author>
<updated>%s</updated>
<entry>
<id>tag:shared.arty.name/im-status,%s</id>
<title>%s</title>
<published>%s</published>
<updated>%s</updated>
</entry>
</feed>
"""
class Client(JabberClient):
current_status = ''
def __init__(self):
JabberClient.__init__(self,
JID(JID_VALUE),
PASSWORD,
server='talk.google.com',
auth_methods=['plain'],
tls_settings=TLSSettings(require=True, verify_peer=False))
def presence(self, stanza):
status = stanza.get_status()
if stanza.get_show() is not None or not status or status == self.current_status:
return True
self.current_status = status
self.update_feed(status)
publish(PUSH_URL, SELF_URL)
syslog.syslog('New status: %s' % (status.encode('utf8')))
return True
def stream_state_changed(self, state, arg):
syslog.syslog('%s %r' % (state, arg))
if state == 'authorized':
self.get_stream().set_presence_handler('available', self.presence)
def get_feed_bytes(self, status):
time = datetime.datetime.now().isoformat()
return (TEMPLATE % (time, time, escape(status), time, time)).encode('utf8')
def update_feed(self, status):
f = open(FILE_PATH, 'w+')
f.write(self.get_feed_bytes(status))
f.close()
def start():
client = Client()
client.connect()
client.loop(1)
def stop():
client.disconnect()
syslog.openlog(facility=syslog.LOG_DAEMON)
context = daemon.DaemonContext(
signal_map={signal.SIGTERM: stop},
gid=grp.getgrnam('www-data').gr_gid,
uid=grp.getgrnam('www-data').gr_gid,
detach_process=True,
)
with context: start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment