11#!/usr/bin/env python
22
33import sys
4+
45sys .dont_write_bytecode = True
56
67import glob
78import yaml
8- import json
99import os
1010import sys
1111import time
1414
1515from slackclient import SlackClient
1616
17+
1718def dbg (debug_string ):
1819 if debug :
1920 logging .info (debug_string )
2021
22+
2123class RtmBot (object ):
2224 def __init__ (self , token ):
2325 self .last_ping = 0
2426 self .token = token
2527 self .bot_plugins = []
2628 self .slack_client = None
29+
2730 def connect (self ):
2831 """Convenience method that creates Server instance"""
2932 self .slack_client = SlackClient (self .token )
3033 self .slack_client .rtm_connect ()
34+
3135 def start (self ):
3236 self .connect ()
3337 self .load_plugins ()
@@ -38,48 +42,54 @@ def start(self):
3842 self .output ()
3943 self .autoping ()
4044 time .sleep (.1 )
45+
4146 def autoping (self ):
42- #hardcode the interval to 3 seconds
47+ # hardcode the interval to 3 seconds
4348 now = int (time .time ())
4449 if now > self .last_ping + 3 :
4550 self .slack_client .server .ping ()
4651 self .last_ping = now
52+
4753 def input (self , data ):
4854 if "type" in data :
4955 function_name = "process_" + data ["type" ]
5056 dbg ("got {}" .format (function_name ))
5157 for plugin in self .bot_plugins :
5258 plugin .register_jobs ()
5359 plugin .do (function_name , data )
60+
5461 def output (self ):
5562 for plugin in self .bot_plugins :
5663 limiter = False
5764 for output in plugin .do_output ():
5865 channel = self .slack_client .server .channels .find (output [0 ])
59- if channel != None and output [1 ] != None :
60- if limiter == True :
66+ if channel is not None and output [1 ] is not None :
67+ if limiter :
6168 time .sleep (.1 )
62- limiter = False
63- message = output [1 ].encode ('ascii' ,'ignore' )
64- channel .send_message ("{}" .format (message ))
65- limiter = True
69+ limiter = True # TODO: check goal: no sleep for 1st channel, sleep of all after ?
70+ # TODO: find out how to safely encode stuff if needed :(
71+ # message = output[1].encode('utf-8','ignore')
72+ channel .send_message (output [1 ]) # message
73+
74+
6675 def crons (self ):
6776 for plugin in self .bot_plugins :
6877 plugin .do_jobs ()
78+
6979 def load_plugins (self ):
70- for plugin in glob .glob (directory + '/plugins/*' ):
80+ for plugin in glob .glob (directory + '/plugins/*' ):
7181 sys .path .insert (0 , plugin )
72- sys .path .insert (0 , directory + '/plugins/' )
73- for plugin in glob .glob (directory + '/plugins/*.py' ) + glob .glob (directory + '/plugins/*/*.py' ):
82+ sys .path .insert (0 , directory + '/plugins/' )
83+ for plugin in glob .glob (directory + '/plugins/*.py' ) + glob .glob (directory + '/plugins/*/*.py' ):
7484 logging .info (plugin )
7585 name = plugin .split ('/' )[- 1 ][:- 3 ]
76- # try:
86+ # try:
7787 self .bot_plugins .append (Plugin (name ))
78- # except:
79- # print "error loading plugin %s" % name
88+ # except:
89+ # print "error loading plugin %s" % name
8090
8191class Plugin (object ):
82- def __init__ (self , name , plugin_config = {} ):
92+ def __init__ (self , name ):
8393 self .name = name
8494 self .jobs = []
8595 self .module = __import__ (name )
@@ -90,32 +100,36 @@ def __init__(self, name, plugin_config={}):
90100 self .module .config = config [name ]
91101 if 'setup' in dir (self .module ):
92102 self .module .setup ()
103+
93104 def register_jobs (self ):
94105 if 'crontable' in dir (self .module ):
95106 for interval , function in self .module .crontable :
96- self .jobs .append (Job (interval , eval ("self.module." + function )))
107+ self .jobs .append (Job (interval , eval ("self.module." + function )))
97108 logging .info (self .module .crontable )
98109 self .module .crontable = []
99110 else :
100111 self .module .crontable = []
112+
101113 def do (self , function_name , data ):
102114 if function_name in dir (self .module ):
103- #this makes the plugin fail with stack trace in debug mode
115+ # this makes the plugin fail with stack trace in debug mode
104116 if not debug :
105117 try :
106- eval ("self.module." + function_name )(data )
118+ eval ("self.module." + function_name )(data , bot , config )
107119 except :
108120 dbg ("problem in module {} {}" .format (function_name , data ))
109121 else :
110- eval ("self.module." + function_name )(data )
122+ eval ("self.module." + function_name )(data , bot , config )
111123 if "catch_all" in dir (self .module ):
112124 try :
113125 self .module .catch_all (data )
114126 except :
115127 dbg ("problem in catch all" )
128+
116129 def do_jobs (self ):
117130 for job in self .jobs :
118131 job .check ()
132+
119133 def do_output (self ):
120134 output = []
121135 while True :
@@ -129,15 +143,19 @@ def do_output(self):
129143 self .module .outputs = []
130144 return output
131145
146+
132147class Job (object ):
133148 def __init__ (self , interval , function ):
134149 self .function = function
135150 self .interval = interval
136151 self .lastrun = 0
152+
137153 def __str__ (self ):
138154 return "{} {} {}" .format (self .function , self .interval , self .lastrun )
155+
139156 def __repr__ (self ):
140157 return self .__str__ ()
158+
141159 def check (self ):
142160 if self .lastrun + self .interval < time .time ():
143161 if not debug :
@@ -150,6 +168,7 @@ def check(self):
150168 self .lastrun = time .time ()
151169 pass
152170
171+
153172class UnknownChannel (Exception ):
154173 pass
155174
@@ -182,8 +201,8 @@ def parse_args():
182201 directory = os .path .dirname (sys .argv [0 ])
183202 if not directory .startswith ('/' ):
184203 directory = os .path .abspath ("{}/{}" .format (os .getcwd (),
185- directory
186- ))
204+ directory
205+ ))
187206
188207 config = yaml .load (file (args .config or 'rtmbot.conf' , 'r' ))
189208 debug = config ["DEBUG" ]
@@ -195,7 +214,7 @@ def parse_args():
195214 if config .has_key ("DAEMON" ):
196215 if config ["DAEMON" ]:
197216 import daemon
217+
198218 with daemon .DaemonContext ():
199219 main_loop ()
200220 main_loop ()
201-
0 commit comments