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_log
, sys_options
, cmd_manager
, inviteable
, argparser
22 import cmd_admin
, cmd_private
, cmd_user
, internets_channels
, internets_users
, sys_auth
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_private
= cmd_private
.PrivateCommandManager()
98 self
.commands_user
= cmd_user
.UserCommandManager()
99 except Exception, err
:
100 self
.log
.exception('Error initializing core subsystems for internets module (%s)' % err
)
103 self
.elog
.debug('Started core subsystems.')
106 self
.channels
= internets_channels
.InternetsChannelManager(self
)
107 self
.users
= internets_users
.InternetsUserManager(self
)
108 self
.auth
= sys_auth
.InternetsAuthManager(self
)
109 self
.antiflood
= sys_antiflood
.AntiFloodManager(self
)
110 except Exception, err
:
111 self
.log
.exception('Error initializing subsystems for internets module (%s)' % err
)
114 self
.elog
.debug('Started subsystems.')
118 self
.bing
= bing
.Bing(self
.config
.get('internets').get('bing_appid'))
119 except Exception, err
:
120 self
.log
.exception('Error initializing internets bing API (%s)' % err
)
121 self
.nsp
= calc
.NumericStringParser()
122 self
.google
= google
.Google(self
.config
.get('internets').get('key_google'), self
.config
.get('internets').get('yt_parse_delay'))
123 self
.imdb
= imdb
.Imdb()
124 self
.ipinfo
= ipinfo
.IpInfo(self
.config
.get('internets').get('key_ipinfodb'))
125 self
.lastfm
= lastfm
.LastFm(self
.config
.get('internets').get('key_lastfm'))
126 self
.quotes
= quotes
.Quotes(self
.config
.get('internets').get('key_fml'))
127 self
.urbandictionary
= urbandictionary
.UrbanDictionary()
128 self
.urls
= urls
.Urls(self
.config
.get('internets').get('user_bitly'), self
.config
.get('internets').get('key_bitly'))
129 self
.weather
= weather
.Weather(self
.config
.get('internets').get('key_openweathermap'))
130 self
.wolfram
= wolfram
.Wolfram(self
.config
.get('internets').get('key_wolframalpha'))
131 self
.wordnik
= words
.Words(self
.config
.get('internets').get('key_wordnik'))
132 self
.steam
= steam
.Steam(self
.config
.get('internets').get('key_steam'))
133 self
.twitch
= twitch
.Twitch()
134 except Exception, err
:
135 self
.log
.exception('Error initializing internets module (%s)' % err
)
138 for channel
in self
.channels
.list_valid():
139 self
.join(channel
.name
)
141 self
.log
.debug('Joined channels.')
145 except Exception, err
:
146 self
.log
.exception('Error starting threads for internets module (%s)' % err
)
149 self
.initialized
= True
151 self
.elog
.debug('Started threads.')
155 if hasattr(self
, 'antiflood'):
156 self
.antiflood
.stop()
158 if hasattr(self
, 'auth'):
161 if hasattr(self
, 'users'):
166 self
.users
.db_close()
168 if hasattr(self
, 'channels'):
170 self
.channels
.force()
173 self
.channels
.db_close()
175 if hasattr(self
, 'options'):
180 self
.options
.db_close()
182 def errormsg(self
, target
, message
):
183 self
.msg(target
, '@b@c4Error:@o %s' % message
)
185 def usagemsg(self
, target
, description
, examples
):
186 message
= '@errsep @bUsage@b %s @errsep' % description
189 message
+= ' @bExamples@b %s @errsep' % ', '.join(examples
)
191 self
.msg(target
, message
)
193 def msg(self
, target
, message
):
195 Acidictive
.privmsg(self
.nick
, target
, format_ascii_irc(message
))
197 def multimsg(self
, target
, count
, intro
, separator
, pieces
, outro
= ''):
200 while cur
< len(pieces
):
201 self
.msg(target
, intro
+ separator
.join(pieces
[cur
:cur
+ count
]) + outro
)
204 def notice(self
, target
, message
):
206 Acidictive
.notice(self
.nick
, target
, format_ascii_irc(message
))
208 def execute(self
, manager
, command
, argument
, channel
, sender
, userinfo
):
209 full_command
= '%s%s' % (command
, ' %s' % argument
if len(argument
) else '')
210 cmd
= manager
.get_command(command
)
213 self
.msg(channel
, manager
.invalid
)
214 self
.elog
.debug('Parsed command @b%s@b: invalid command.' % full_command
)
217 if self
.users
.is_banned(sender
) or self
.antiflood
.check_user(sender
, command
, argument
):
218 user
= self
.users
[sender
]
219 message
= 'You were banned by @b%s@b.' % user
.ban_source
221 if user
.ban_reason
!= None:
222 message
+= ' Reason: @b%s@b.' % user
.ban_reason
224 if user
.ban_expiry
!= None:
225 message
+= ' Expires: @b%s@b.' % datetime
.fromtimestamp(user
.ban_expiry
)
227 self
.notice(sender
, message
)
228 self
.elog
.debug('Parsed command @b%s@b: user is banned.' % full_command
)
231 self
.elog
.command('%s%s > %s' % (sender
, ':%s' % channel
if channel
!= sender
else '', full_command
))
233 parser
= argparser
.ArgumentParser(add_help_option
= False, option_class
= argparser
.ArgumentParserOption
)
237 parser
.add_option('-?', '--help', action
= 'store_true')
239 for cmd_arg
in cmd_args
:
240 parser
.add_option(cmd_arg
[1], '--' + cmd_arg
[0], **cmd_arg
[3])
243 argument
= argument
.lstrip()
244 if len(argument
) > 1:
245 if argument
[0] == '-' and argument
[1] != '-' and not cmd_args
:
246 argument
= '-- ' + argument
247 (popts
, pargs
) = parser
.parse_args(args
= argument
.split(' '))
248 except argparser
.ArgumentParserError
, err
:
249 self
.msg(channel
, str(err
)) #TODO: Avoid str, use unicode.
251 self
.elog
.debug('Parsed command @b%s@b: invalid options.' % full_command
)
254 if popts
.help == True:
255 manager
.commands
['help'][0](self
, manager
, {}, command
, channel
, sender
)
257 self
.elog
.debug('Parsed command @b%s@b: help intercepted.' % full_command
)
261 larg
= ' '.join(pargs
).strip()
264 for cmd_arg
in cmd_args
:
265 parg
= getattr(popts
, cmd_arg
[0])
268 if len(cmd_arg
) <= 4 or not (cmd_arg
[4] & cmd_manager
.ARG_OFFLINE
):
271 if len(cmd_arg
) > 4 and (cmd_arg
[4] & cmd_manager
.ARG_YES
) and larg
== '':
272 self
.msg(channel
, 'Error: %s option requires an argument.' % cmd_arg
[1])
274 self
.elog
.debug('Parsed command @b%s@b: option constraint was broken.' % full_command
)
277 opt_dict
[cmd_arg
[0]] = parg
278 elif len(cmd_arg
) > 4 and (cmd_arg
[4] & cmd_manager
.ARG_OFFLINE
and cmd_arg
[4] & cmd_manager
.ARG_OFFLINE_REQ
):
281 if not self
.online
and ((len(pargs
) > 0 and not (cmd_type
& cmd_manager
.ARG_OFFLINE
)) or not is_offline
):
282 self
.notice(sender
, 'The eRepublik API is offline. Please retry later.')
284 self
.elog
.debug('Parsed command @b%s@b: offline.' % full_command
)
287 if (cmd_type
& cmd_manager
.ARG_YES
) and (larg
== None or larg
== ''):
288 self
.notice(sender
, '@bUsage@b: %s @b%s@b' % (command
, cmd
[4] if len(cmd
) > 4 else 'argument'))
291 cmd
[0](self
, manager
, opt_dict
, larg
, channel
, sender
, userinfo
)
293 tb
= traceback
.extract_tb(sys
.exc_info()[2])
297 length
= len(entry
[2])
302 self
.elog
.exception('%s%s > @b%s@b: %s' % (sender
, ':%s' % channel
if channel
!= sender
else '', full_command
, e
))
303 self
.log
.exception("internets error!")
306 self
.elog
.traceback('@b%-*s@b : %d %s' % (longest
, entry
[2], entry
[1], entry
[3]))
308 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.')
311 self
.elog
.debug('Parsed command @b%s@b: execution terminated.' % full_command
)
313 def onPrivmsg(self
, source
, target
, message
):
314 if not super(internets
, self
).onPrivmsg(source
, target
, message
):
318 # both 'youtube.com' and 'youtu.be' get caught
319 if not 'youtu' in message
or not self
.channels
[target
].youtube_info
== '1':
322 sourceNick
= User
.findUser(source
)['nick']
323 if not self
.users
.is_banned(sourceNick
) and not self
.antiflood
.check_user(sourceNick
, 'ytinfo', '') and target
[0] == '#':
324 threading
.deferToThread(cmd_user
.onPrivmsg_regex_youtube
, self
, source
, target
, message
)
326 def onChanModes(self
, prefix
, channel
, modes
):
327 if not self
.initialized
:
330 if not modes
== '-z':
333 if channel
in self
.channels
:
334 self
.channels
.remove(channel
)
335 self
.elog
.request('Channel @b%s@b was dropped. Deleting it.' % channel
)
337 def getCommands(self
):
338 return self
.commands_admin
340 def get_location(self
, opts
, arg
, channel
, sender
):
352 location
= self
.users
.get(nick
, 'location')
356 self
.msg(channel
, 'No location found linked to nick %s.' % arg
)
358 self
.msg(channel
, 'No location found linked to your nick. To link one, type: @b%sregister_location <location>@b' % self
.commands_user
.get_prefix())
362 def get_steamid(self
, opts
, arg
, channel
, sender
):
363 """Gets the steamid from the database."""
372 steamid
= self
.users
.get(nick
, 'steamid')
376 self
.msg(channel
, 'No steamid found linked to nick %s.' % arg
)
379 self
.msg(channel
, 'No steamid found linked to your nick. To link one, type: @b%sregister_steam <steamid>@b' % self
.commands_user
.get_prefix())
382 return SteamUser(nick
, steamid
)