1 #!/usr/bin/python pseudoserver.py
3 # module for pypseudoserver
4 # written by ElChE <elche@rizon.net>, martin <martin@rizon.net>
11 from istring
import istring
12 from datetime
import datetime
13 from decimal
import Decimal
, InvalidOperation
19 import mythreading
as threading
20 from pseudoclient
import sys_antiflood
, sys_auth
, sys_channels
, sys_log
, sys_options
, cmd_manager
, inviteable
, argparser
22 import cmd_admin
, cmd_user
, internets_users
23 from api
import bing
, calc
, google
, imdb
, ipinfo
, lastfm
, quotes
, urbandictionary
, urls
, weather
, wolfram
, words
, steam
, twitch
24 from internets_utils
import *
25 from api
.steam
import SteamUser
27 import pyva_net_rizon_acid_core_Acidictive
as Acidictive
28 import pyva_net_rizon_acid_core_AcidCore
as AcidCore
29 import pyva_net_rizon_acid_core_User
as User
33 inviteable
.InviteablePseudoclient
37 def bind_function(self
, function
):
38 func
= types
.MethodType(function
, self
, internets
)
39 setattr(internets
, function
.__name
__, func
)
42 def bind_admin_commands(self
):
43 list = cmd_admin
.get_commands()
44 self
.commands_admin
= []
47 self
.commands_admin
.append(
51 'callback': self
.bind_function(list[command
][0]),
52 'usage': list[command
][1]
58 AcidPlugin
.__init
__(self
)
60 self
.name
= "internets"
61 self
.log
= logging
.getLogger(__name__
)
64 self
.nick
= istring(self
.config
.get('internets').get('nick'))
65 except Exception, err
:
66 self
.log
.exception("Error reading 'internets:nick' configuration option: %s" % err
)
70 self
.chan
= istring(self
.config
.get('internets').get('channel'))
71 except Exception, err
:
72 self
.log
.exception("Error reading 'internets:channel' configuration option: %s" % err
)
76 self
.output_limit
= int(self
.config
.get('internets').get('outputlimit'))
77 except Exception, err
:
78 self
.log
.exception("Error reading 'internets:outputlimit' configuration option: %s" % err
)
81 self
.bind_admin_commands()
83 def start_threads(self
):
88 self
.antiflood
.start()
92 AcidPlugin
.start(self
)
93 inviteable
.InviteablePseudoclient
.start(self
)
95 self
.options
= sys_options
.OptionManager(self
)
96 self
.elog
= sys_log
.LogManager(self
)
97 self
.commands_user
= cmd_user
.UserCommandManager()
98 except Exception, err
:
99 self
.log
.exception('Error initializing core subsystems for internets module (%s)' % err
)
102 self
.elog
.debug('Started core subsystems.')
105 self
.channels
= sys_channels
.ChannelManager(self
)
106 self
.users
= internets_users
.InternetsUserManager(self
)
107 self
.auth
= sys_auth
.AuthManager(self
)
108 self
.antiflood
= sys_antiflood
.AntiFloodManager(self
)
109 except Exception, err
:
110 self
.log
.exception('Error initializing subsystems for internets module (%s)' % err
)
113 self
.elog
.debug('Started subsystems.')
117 self
.bing
= bing
.Bing(self
.config
.get('internets').get('bing_appid'))
118 except Exception, err
:
119 self
.log
.exception('Error initializing internets bing API (%s)' % err
)
120 self
.nsp
= calc
.NumericStringParser()
121 self
.google
= google
.Google(self
.config
.get('internets').get('key_google'), self
.config
.get('internets').get('yt_parse_delay'))
122 self
.imdb
= imdb
.Imdb()
123 self
.ipinfo
= ipinfo
.IpInfo(self
.config
.get('internets').get('key_ipinfodb'))
124 self
.lastfm
= lastfm
.LastFm(self
.config
.get('internets').get('key_lastfm'))
125 self
.quotes
= quotes
.Quotes(self
.config
.get('internets').get('key_fml'))
126 self
.urbandictionary
= urbandictionary
.UrbanDictionary()
127 self
.urls
= urls
.Urls(self
.config
.get('internets').get('user_bitly'), self
.config
.get('internets').get('key_bitly'))
128 self
.weather
= weather
.Weather(self
.config
.get('internets').get('key_openweathermap'))
129 self
.wolfram
= wolfram
.Wolfram(self
.config
.get('internets').get('key_wolframalpha'))
130 self
.wordnik
= words
.Words(self
.config
.get('internets').get('key_wordnik'))
131 self
.steam
= steam
.Steam(self
.config
.get('internets').get('key_steam'))
132 self
.twitch
= twitch
.Twitch()
133 except Exception, err
:
134 self
.log
.exception('Error initializing internets module (%s)' % err
)
137 for channel
in self
.channels
.list_valid():
138 self
.join(channel
.name
)
140 self
.log
.debug('Joined channels.')
144 except Exception, err
:
145 self
.log
.exception('Error starting threads for internets module (%s)' % err
)
148 self
.initialized
= True
150 self
.elog
.debug('Started threads.')
154 if hasattr(self
, 'antiflood'):
155 self
.antiflood
.stop()
157 if hasattr(self
, 'auth'):
160 if hasattr(self
, 'users'):
165 self
.users
.db_close()
167 if hasattr(self
, 'channels'):
169 self
.channels
.force()
172 self
.channels
.db_close()
174 if hasattr(self
, 'options'):
179 self
.options
.db_close()
181 def errormsg(self
, target
, message
):
182 self
.msg(target
, '@b@c4Error:@o %s' % message
)
184 def usagemsg(self
, target
, description
, examples
):
185 message
= '@errsep @bUsage@b %s @errsep' % description
188 message
+= ' @bExamples@b %s @errsep' % ', '.join(examples
)
190 self
.msg(target
, message
)
192 def msg(self
, target
, message
):
194 Acidictive
.privmsg(self
.nick
, target
, format_ascii_irc(message
))
196 def multimsg(self
, target
, count
, intro
, separator
, pieces
, outro
= ''):
199 while cur
< len(pieces
):
200 self
.msg(target
, intro
+ separator
.join(pieces
[cur
:cur
+ count
]) + outro
)
203 def notice(self
, target
, message
):
205 Acidictive
.notice(self
.nick
, target
, format_ascii_irc(message
))
207 def execute(self
, manager
, command
, argument
, channel
, sender
, userinfo
):
208 full_command
= '%s%s' % (command
, ' %s' % argument
if len(argument
) else '')
209 cmd
= manager
.get_command(command
)
212 self
.msg(channel
, manager
.invalid
)
213 self
.elog
.debug('Parsed command @b%s@b: invalid command.' % full_command
)
216 if self
.users
.is_banned(sender
) or self
.antiflood
.check_user(sender
, command
, argument
):
217 user
= self
.users
[sender
]
218 message
= 'You were banned by @b%s@b.' % user
.ban_source
220 if user
.ban_reason
!= None:
221 message
+= ' Reason: @b%s@b.' % user
.ban_reason
223 if user
.ban_expiry
!= None:
224 message
+= ' Expires: @b%s@b.' % datetime
.fromtimestamp(user
.ban_expiry
)
226 self
.notice(sender
, message
)
227 self
.elog
.debug('Parsed command @b%s@b: user is banned.' % full_command
)
230 self
.elog
.command('%s%s > %s' % (sender
, ':%s' % channel
if channel
!= sender
else '', full_command
))
232 parser
= argparser
.ArgumentParser(add_help_option
= False, option_class
= argparser
.ArgumentParserOption
)
236 parser
.add_option('-?', '--help', action
= 'store_true')
238 for cmd_arg
in cmd_args
:
239 parser
.add_option(cmd_arg
[1], '--' + cmd_arg
[0], **cmd_arg
[3])
242 argument
= argument
.lstrip()
243 if len(argument
) > 1:
244 if argument
[0] == '-' and argument
[1] != '-' and not cmd_args
:
245 argument
= '-- ' + argument
246 (popts
, pargs
) = parser
.parse_args(args
= argument
.split(' '))
247 except argparser
.ArgumentParserError
, err
:
248 self
.msg(channel
, str(err
)) #TODO: Avoid str, use unicode.
250 self
.elog
.debug('Parsed command @b%s@b: invalid options.' % full_command
)
253 if popts
.help == True:
254 manager
.commands
['help'][0](self
, manager
, {}, command
, channel
, sender
)
256 self
.elog
.debug('Parsed command @b%s@b: help intercepted.' % full_command
)
260 larg
= ' '.join(pargs
).strip()
263 for cmd_arg
in cmd_args
:
264 parg
= getattr(popts
, cmd_arg
[0])
267 if len(cmd_arg
) <= 4 or not (cmd_arg
[4] & cmd_manager
.ARG_OFFLINE
):
270 if len(cmd_arg
) > 4 and (cmd_arg
[4] & cmd_manager
.ARG_YES
) and larg
== '':
271 self
.msg(channel
, 'Error: %s option requires an argument.' % cmd_arg
[1])
273 self
.elog
.debug('Parsed command @b%s@b: option constraint was broken.' % full_command
)
276 opt_dict
[cmd_arg
[0]] = parg
277 elif len(cmd_arg
) > 4 and (cmd_arg
[4] & cmd_manager
.ARG_OFFLINE
and cmd_arg
[4] & cmd_manager
.ARG_OFFLINE_REQ
):
280 if not self
.online
and ((len(pargs
) > 0 and not (cmd_type
& cmd_manager
.ARG_OFFLINE
)) or not is_offline
):
281 self
.notice(sender
, 'The eRepublik API is offline. Please retry later.')
283 self
.elog
.debug('Parsed command @b%s@b: offline.' % full_command
)
286 if (cmd_type
& cmd_manager
.ARG_YES
) and (larg
== None or larg
== ''):
287 self
.notice(sender
, '@bUsage@b: %s @b%s@b' % (command
, cmd
[4] if len(cmd
) > 4 else 'argument'))
290 cmd
[0](self
, manager
, opt_dict
, larg
, channel
, sender
, userinfo
)
292 tb
= traceback
.extract_tb(sys
.exc_info()[2])
296 length
= len(entry
[2])
301 self
.elog
.exception('%s%s > @b%s@b: %s' % (sender
, ':%s' % channel
if channel
!= sender
else '', full_command
, e
))
302 self
.log
.exception("internets error!")
305 self
.elog
.traceback('@b%-*s@b : %d %s' % (longest
, entry
[2], entry
[1], entry
[3]))
307 self
.msg(channel
, 'An exception occurred and has been reported to the developers. If this error persists please do not use the faulty command until it has been fixed.')
310 self
.elog
.debug('Parsed command @b%s@b: execution terminated.' % full_command
)
312 def onPrivmsg(self
, source
, target
, message
):
313 if not super(internets
, self
).onPrivmsg(source
, target
, message
):
317 if not self
.users
.is_banned(User
.findUser(source
)['nick']) and target
[0] == '#':
318 if 'youtu' in message
:
319 # both 'youtube.com' and 'youtu.be' get caught
320 threading
.deferToThread(cmd_user
.onPrivmsg_regex_youtube
, self
, source
, target
, message
)
322 def onChanModes(self
, prefix
, channel
, modes
):
323 if not self
.initialized
:
326 if not modes
== '-z':
329 if channel
in self
.channels
:
330 self
.channels
.remove(channel
)
331 self
.elog
.request('Channel @b%s@b was dropped. Deleting it.' % channel
)
333 def getCommands(self
):
334 return self
.commands_admin
336 def get_location(self
, opts
, arg
, channel
, sender
):
348 location
= self
.users
.get(nick
, 'location')
352 self
.msg(channel
, 'No location found linked to nick %s.' % arg
)
354 self
.msg(channel
, 'No location found linked to your nick. To link one, type: @b%sregister_location <location>@b' % self
.commands_user
.get_prefix())
358 def get_steamid(self
, opts
, arg
, channel
, sender
):
359 """Gets the steamid from the database."""
368 steamid
= self
.users
.get(nick
, 'steamid')
372 self
.msg(channel
, 'No steamid found linked to nick %s.' % arg
)
375 self
.msg(channel
, 'No steamid found linked to your nick. To link one, type: @b%sregister_steam <steamid>@b' % self
.commands_user
.get_prefix())
378 return SteamUser(nick
, steamid
)