language: Python (python 2.7.3)
date: 737 days 10 hours ago
link:
visibility: public
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)