1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | """ Recieves JSON messages from googlecode and outputs to IRC channels. """ from twisted.words.protocols import irc from twisted.internet import protocol from twisted.application.internet import TCPServer, TCPClient from twisted.application.service import Application from twisted.web.resource import Resource from twisted.web.server import Site from twisted.python import log import hmac, json class CHookBot(irc.IRCClient): """Commit Hook Bot""" nickname = "shfl2|bot" last_msg = "No logs since starting" def connectionMade(self): irc.IRCClient.connectionMade(self) self.factory.bot = self def connectionLost(self, reason): irc.IRCClient.connectionLost(self, reason) def signedOn(self): """Called when bot has succesfully signed on to server.""" self.join(self.factory.channel) def privmsg(self, user, channel, msg): """This will get called when the bot receives a message.""" user = user.split('!', 1)[0] if msg == "!lastlog": self.msg(channel, user + ": " + self.last_msg) def commit_msg(self, msg): self.last_msg = msg self.msg(self.factory.channel, self.last_msg) class CHookBotFactory(protocol.ClientFactory): """A factory for CHookBots.""" # the class of the protocol to build when new connection is made protocol = CHookBot def __init__(self, channel): self.channel = channel def clientConnectionLost(self, connector, reason): """If we get disconnected, reconnect to server.""" connector.connect() def clientConnectionFailed(self, connector, reason): log.msg(reason) reactor.stop() class PostPage(Resource): def __init__(self, botf, secret_key): self.bot_factory = botf self.secret_key = secret_key def render_GET(self, request): return '' def render_POST(self, request): # Check authentication m = hmac.new(self.secret_key) m.update(request.content.getvalue()) digest = m.hexdigest() try: hdr_digest = request.received_headers["google-code-project-hosting-hook-hmac"] except KeyError: hdr_digest = "0" if digest != hdr_digest: log.msg("failed auth check") # return 200 so the msg is not resent return '' # Parse JSON payload = json.loads(request.content.getvalue()) # Send to IRC for revision in payload["revisions"]: txt = u"r%s by %s [%i+|%i~|%i-] %s" % ( \ revision["revision"], revision["author"], len(revision["added"]), len(revision["modified"]), len(revision["removed"]), revision["message"]) self.bot_factory.bot.commit_msg(txt.encode('utf-8')) return '' ''' All config can be done here (except for bot nick...) TODO more rubust config... ''' # The application for twistd application = Application("gcode irc bot") # Setup IRC bot botf = CHookBotFactory("#dolphin-emu") # Setup HTTP listener root = Resource() root.putChild("dolphin-emu", PostPage(botf, "projectkeyhere")) # Start! TCPServer(8800, Site(root)).setServiceParent(application) TCPClient("irc.underworld.no", 7000, botf).setServiceParent(application) |
IiIiClJlY2lldmVzIEpTT04gbWVzc2FnZXMgZnJvbSBnb29nbGVjb2RlIGFuZCBvdXRwdXRzIHRvIElSQyBjaGFubmVscy4KIiIiCmZyb20gdHdpc3RlZC53b3Jkcy5wcm90b2NvbHMgaW1wb3J0IGlyYwpmcm9tIHR3aXN0ZWQuaW50ZXJuZXQgaW1wb3J0IHByb3RvY29sCmZyb20gdHdpc3RlZC5hcHBsaWNhdGlvbi5pbnRlcm5ldCBpbXBvcnQgVENQU2VydmVyLCBUQ1BDbGllbnQKZnJvbSB0d2lzdGVkLmFwcGxpY2F0aW9uLnNlcnZpY2UgaW1wb3J0IEFwcGxpY2F0aW9uCmZyb20gdHdpc3RlZC53ZWIucmVzb3VyY2UgaW1wb3J0IFJlc291cmNlCmZyb20gdHdpc3RlZC53ZWIuc2VydmVyIGltcG9ydCBTaXRlCmZyb20gdHdpc3RlZC5weXRob24gaW1wb3J0IGxvZwoKaW1wb3J0IGhtYWMsIGpzb24KCgpjbGFzcyBDSG9va0JvdChpcmMuSVJDQ2xpZW50KToKICAgICIiIkNvbW1pdCBIb29rIEJvdCIiIgoJCiAgICBuaWNrbmFtZSA9ICJzaGZsMnxib3QiCiAgICBsYXN0X21zZyA9ICJObyBsb2dzIHNpbmNlIHN0YXJ0aW5nIgogICAgCiAgICBkZWYgY29ubmVjdGlvbk1hZGUoc2VsZik6CiAgICAgICAgaXJjLklSQ0NsaWVudC5jb25uZWN0aW9uTWFkZShzZWxmKQogICAgICAgIHNlbGYuZmFjdG9yeS5ib3QgPSBzZWxmCgogICAgZGVmIGNvbm5lY3Rpb25Mb3N0KHNlbGYsIHJlYXNvbik6CiAgICAgICAgaXJjLklSQ0NsaWVudC5jb25uZWN0aW9uTG9zdChzZWxmLCByZWFzb24pCgogICAgZGVmIHNpZ25lZE9uKHNlbGYpOgogICAgICAgICIiIkNhbGxlZCB3aGVuIGJvdCBoYXMgc3VjY2VzZnVsbHkgc2lnbmVkIG9uIHRvIHNlcnZlci4iIiIKICAgICAgICBzZWxmLmpvaW4oc2VsZi5mYWN0b3J5LmNoYW5uZWwpCiAgICAgICAgCiAgICBkZWYgcHJpdm1zZyhzZWxmLCB1c2VyLCBjaGFubmVsLCBtc2cpOgogICAgICAgICIiIlRoaXMgd2lsbCBnZXQgY2FsbGVkIHdoZW4gdGhlIGJvdCByZWNlaXZlcyBhIG1lc3NhZ2UuIiIiCiAgICAgICAgdXNlciA9IHVzZXIuc3BsaXQoJyEnLCAxKVswXQogICAgICAgIGlmIG1zZyA9PSAiIWxhc3Rsb2ciOgogICAgICAgICAgICBzZWxmLm1zZyhjaGFubmVsLCB1c2VyICsgIjogIiArIHNlbGYubGFzdF9tc2cpCiAgICAgICAgCiAgICBkZWYgY29tbWl0X21zZyhzZWxmLCBtc2cpOgogICAgICAgIHNlbGYubGFzdF9tc2cgPSBtc2cKICAgICAgICBzZWxmLm1zZyhzZWxmLmZhY3RvcnkuY2hhbm5lbCwgc2VsZi5sYXN0X21zZykKCiAgICAgICAgCmNsYXNzIENIb29rQm90RmFjdG9yeShwcm90b2NvbC5DbGllbnRGYWN0b3J5KToKICAgICIiIkEgZmFjdG9yeSBmb3IgQ0hvb2tCb3RzLiIiIgoJCiAgICAjIHRoZSBjbGFzcyBvZiB0aGUgcHJvdG9jb2wgdG8gYnVpbGQgd2hlbiBuZXcgY29ubmVjdGlvbiBpcyBtYWRlCiAgICBwcm90b2NvbCA9IENIb29rQm90CgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGNoYW5uZWwpOgogICAgICAgIHNlbGYuY2hhbm5lbCA9IGNoYW5uZWwKCiAgICBkZWYgY2xpZW50Q29ubmVjdGlvbkxvc3Qoc2VsZiwgY29ubmVjdG9yLCByZWFzb24pOgogICAgICAgICIiIklmIHdlIGdldCBkaXNjb25uZWN0ZWQsIHJlY29ubmVjdCB0byBzZXJ2ZXIuIiIiCiAgICAgICAgY29ubmVjdG9yLmNvbm5lY3QoKQoKICAgIGRlZiBjbGllbnRDb25uZWN0aW9uRmFpbGVkKHNlbGYsIGNvbm5lY3RvciwgcmVhc29uKToKICAgICAgICBsb2cubXNnKHJlYXNvbikKICAgICAgICByZWFjdG9yLnN0b3AoKQoKICAgICAgICAKY2xhc3MgUG9zdFBhZ2UoUmVzb3VyY2UpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGJvdGYsIHNlY3JldF9rZXkpOgogICAgICAgIHNlbGYuYm90X2ZhY3RvcnkgPSBib3RmCiAgICAgICAgc2VsZi5zZWNyZXRfa2V5ID0gc2VjcmV0X2tleQogICAgICAgIAogICAgZGVmIHJlbmRlcl9HRVQoc2VsZiwgcmVxdWVzdCk6CiAgICAgICAgcmV0dXJuICcnCgogICAgZGVmIHJlbmRlcl9QT1NUKHNlbGYsIHJlcXVlc3QpOgogICAgICAgICMgQ2hlY2sgYXV0aGVudGljYXRpb24KICAgICAgICBtID0gaG1hYy5uZXcoc2VsZi5zZWNyZXRfa2V5KQogICAgICAgIG0udXBkYXRlKHJlcXVlc3QuY29udGVudC5nZXR2YWx1ZSgpKQogICAgICAgIGRpZ2VzdCA9IG0uaGV4ZGlnZXN0KCkKICAgICAgICB0cnk6CiAgICAgICAgICAgIGhkcl9kaWdlc3QgPSByZXF1ZXN0LnJlY2VpdmVkX2hlYWRlcnNbImdvb2dsZS1jb2RlLXByb2plY3QtaG9zdGluZy1ob29rLWhtYWMiXQogICAgICAgIGV4Y2VwdCBLZXlFcnJvcjoKICAgICAgICAgICAgaGRyX2RpZ2VzdCA9ICIwIgoKICAgICAgICBpZiBkaWdlc3QgIT0gaGRyX2RpZ2VzdDoKICAgICAgICAgICAgbG9nLm1zZygiZmFpbGVkIGF1dGggY2hlY2siKQogICAgICAgICAgICAjIHJldHVybiAyMDAgc28gdGhlIG1zZyBpcyBub3QgcmVzZW50CiAgICAgICAgICAgIHJldHVybiAnJwogICAgICAgIAogICAgICAgICMgUGFyc2UgSlNPTgogICAgICAgIHBheWxvYWQgPSBqc29uLmxvYWRzKHJlcXVlc3QuY29udGVudC5nZXR2YWx1ZSgpKQogICAgICAgIAogICAgICAgICMgU2VuZCB0byBJUkMKICAgICAgICBmb3IgcmV2aXNpb24gaW4gcGF5bG9hZFsicmV2aXNpb25zIl06CiAgICAgICAgICAgIHR4dCA9IHUiciVzIGJ5ICVzIFslaSt8JWl+fCVpLV0gJXMiICUgKCBcCiAgICAgICAgICAgICAgICByZXZpc2lvblsicmV2aXNpb24iXSwKICAgICAgICAgICAgICAgIHJldmlzaW9uWyJhdXRob3IiXSwKICAgICAgICAgICAgICAgIGxlbihyZXZpc2lvblsiYWRkZWQiXSksIGxlbihyZXZpc2lvblsibW9kaWZpZWQiXSksIGxlbihyZXZpc2lvblsicmVtb3ZlZCJdKSwKICAgICAgICAgICAgICAgIHJldmlzaW9uWyJtZXNzYWdlIl0pCiAgICAgICAgICAgIHNlbGYuYm90X2ZhY3RvcnkuYm90LmNvbW1pdF9tc2codHh0LmVuY29kZSgndXRmLTgnKSkKICAgICAgICByZXR1cm4gJycKCiAgICAgICAgICAgIAonJycKQWxsIGNvbmZpZyBjYW4gYmUgZG9uZSBoZXJlIChleGNlcHQgZm9yIGJvdCBuaWNrLi4uKQpUT0RPIG1vcmUgcnVidXN0IGNvbmZpZy4uLgonJycKIyBUaGUgYXBwbGljYXRpb24gZm9yIHR3aXN0ZCAgICAgICAgICAgIAphcHBsaWNhdGlvbiA9IEFwcGxpY2F0aW9uKCJnY29kZSBpcmMgYm90IikKCiMgU2V0dXAgSVJDIGJvdApib3RmID0gQ0hvb2tCb3RGYWN0b3J5KCIjZG9scGhpbi1lbXUiKQoKIyBTZXR1cCBIVFRQIGxpc3RlbmVyCnJvb3QgPSBSZXNvdXJjZSgpCnJvb3QucHV0Q2hpbGQoImRvbHBoaW4tZW11IiwgUG9zdFBhZ2UoYm90ZiwgInByb2plY3RrZXloZXJlIikpCgojIFN0YXJ0IQpUQ1BTZXJ2ZXIoODgwMCwgU2l0ZShyb290KSkuc2V0U2VydmljZVBhcmVudChhcHBsaWNhdGlvbikKVENQQ2xpZW50KCJpcmMudW5kZXJ3b3JsZC5ubyIsIDcwMDAsIGJvdGYpLnNldFNlcnZpY2VQYXJlbnQoYXBwbGljYXRpb24pCg==


