|
@@ -10,6 +10,7 @@ from datetime import datetime, timedelta
|
|
|
import getpass
|
|
|
import ircbot
|
|
|
import irclib
|
|
|
+import oauth2 as oauth
|
|
|
import os
|
|
|
import psycopg2
|
|
|
import psycopg2.extensions
|
|
@@ -19,6 +20,7 @@ import sys
|
|
|
import time
|
|
|
import threading
|
|
|
import urllib, urllib2
|
|
|
+import urlparse
|
|
|
import warnings
|
|
|
|
|
|
try:
|
|
@@ -58,6 +60,8 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
self.__admins = self.__config.get(nick, 'admins').split()
|
|
|
self.__channels = set(self.__config.get(nick, 'channels').split())
|
|
|
self.__dsn = self.__config.get(nick, 'dsn')
|
|
|
+ self.__latitude_key = self.__config.get(nick, 'latitude_key')
|
|
|
+ self.__latitude_consumer = oauth.Consumer(key = self.__latitude_key, secret = self.__config.get(nick, 'latitude_secret'))
|
|
|
except NoOptionError, error:
|
|
|
sys.exit(error)
|
|
|
|
|
@@ -68,16 +72,14 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
|
|
|
ircbot.SingleServerIRCBot.__init__(self, servers, nick, 'Location Bot')
|
|
|
|
|
|
- self.__latitude_timer_lock = threading.Lock()
|
|
|
- self.__latitude_timer = None
|
|
|
- self.__locations_lock = threading.Lock()
|
|
|
-
|
|
|
if bot is None:
|
|
|
+ self.__geocode_cache = {}
|
|
|
self.__locations = []
|
|
|
self.__logins = {}
|
|
|
self.__nick = None
|
|
|
self.__reloading = False
|
|
|
else:
|
|
|
+ self.__geocode_cache = bot.__geocode_cache
|
|
|
irclibobj = self.ircobj.connections[0].irclibobj
|
|
|
self.ircobj.connections[0] = bot.ircobj.connections[0]
|
|
|
self.ircobj.connections[0].irclibobj = irclibobj
|
|
@@ -88,9 +90,16 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
self.__nick = bot.__nick
|
|
|
self.__reloading = True
|
|
|
|
|
|
+ self.__geocode_cache_lock = threading.Lock()
|
|
|
+ self.__geocode_cache_clean_timer_lock = threading.Lock()
|
|
|
+ self.__geocode_cache_clean_timer = None
|
|
|
+ self.__latitude_granularities = frozenset(['city', 'best'])
|
|
|
+ self.__latitude_timer_lock = threading.Lock()
|
|
|
+ self.__latitude_timer = None
|
|
|
+ self.__locations_lock = threading.Lock()
|
|
|
self.__quiting = False
|
|
|
self.__variables = frozenset(['nick', 'secret', 'masks', 'channels', 'timezone', 'location', 'coordinates', 'latitude'])
|
|
|
- self.__geocode = self.__variables.intersection(['location', 'coordinates'])
|
|
|
+ self.__geocode_variables = self.__variables.intersection(['location', 'coordinates'])
|
|
|
self.__lists = self.__variables.intersection(['masks', 'channels'])
|
|
|
self.__unsetable = self.__variables.difference(['nick', 'secret'])
|
|
|
|
|
@@ -106,9 +115,6 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
|
|
|
return _or(lambda channel: channel.has_user(nick), channels)
|
|
|
|
|
|
- def __coordinates(self, coordinates):
|
|
|
- return ' http://maps.google.com/maps?q=%f,%f' % coordinates if coordinates else ''
|
|
|
-
|
|
|
def __db(self):
|
|
|
db = psycopg2.connect(self.__dsn)
|
|
|
|
|
@@ -120,6 +126,84 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
|
|
|
return db, db.cursor()
|
|
|
|
|
|
+ def __geocode(self, sensor, coordinates = None, location = None):
|
|
|
+ parameters = {'sensor': 'true' if sensor else 'false'}
|
|
|
+
|
|
|
+ with self.__geocode_cache_lock:
|
|
|
+ if coordinates is not None:
|
|
|
+ try:
|
|
|
+ return self.__geocode_cache[coordinates][0]
|
|
|
+ except KeyError:
|
|
|
+ parameters['latlng'] = '%f,%f' % coordinates
|
|
|
+ else:
|
|
|
+ try:
|
|
|
+ return self.__geocode_cache[coordinates][0]
|
|
|
+ except KeyError:
|
|
|
+ parameters['address'] = location
|
|
|
+
|
|
|
+ geocode = json.load(urllib2.urlopen('http://maps.google.com/maps/api/geocode/json?' + urllib.urlencode(parameters)))
|
|
|
+ status = geocode['status']
|
|
|
+
|
|
|
+ if status != 'OK':
|
|
|
+ if coordinates is not None and status == 'ZERO_RESULTS':
|
|
|
+ return self.__geocode(sensor, location = parameters['latlng'])
|
|
|
+ else:
|
|
|
+ raise Exception(status)
|
|
|
+
|
|
|
+ results = geocode['results']
|
|
|
+
|
|
|
+ def _result():
|
|
|
+ _location = result['geometry']['location']
|
|
|
+ geocode = (_location['lat'], _location['lng']), result['formatted_address']
|
|
|
+
|
|
|
+ with self.__geocode_cache_lock:
|
|
|
+ self.__geocode_cache[coordinates if coordinates is not None else location] = (geocode, datetime.utcnow())
|
|
|
+
|
|
|
+ return geocode
|
|
|
+
|
|
|
+ if coordinates is not None:
|
|
|
+ types = frozenset([
|
|
|
+ 'country',
|
|
|
+ 'administrative_area_level_1',
|
|
|
+ 'administrative_area_level_2',
|
|
|
+ 'administrative_area_level_3',
|
|
|
+ 'colloquial_area',
|
|
|
+ 'locality',
|
|
|
+ 'sublocality',
|
|
|
+ 'neighborhood',
|
|
|
+ ])
|
|
|
+
|
|
|
+ for result in results:
|
|
|
+ if not types.isdisjoint(result['types']):
|
|
|
+ return _result()
|
|
|
+
|
|
|
+ result = results[0]
|
|
|
+
|
|
|
+ return _result()
|
|
|
+
|
|
|
+ def __geocode_cache_clean(self):
|
|
|
+ now = datetime.utcnow()
|
|
|
+
|
|
|
+ try:
|
|
|
+ while now < self.__geocode_cache_clean_next:
|
|
|
+ time.sleep((self.__geocode_cache_clean_next - now).seconds)
|
|
|
+
|
|
|
+ now = datetime.utcnow()
|
|
|
+ except AttributeError:
|
|
|
+ self.__geocode_cache_length = timedelta(hours = 1)
|
|
|
+
|
|
|
+ self.__geocode_cache_clean_next = now.replace(minute = 2, second = 30, microsecond = 0) + self.__geocode_cache_length
|
|
|
+
|
|
|
+ with self.__geocode_cache_lock:
|
|
|
+ for location, (geocode, created) in self.__geocode_cache.items():
|
|
|
+ if now - created >= self.__geocode_cache_length:
|
|
|
+ del self.__geocode_cache[location]
|
|
|
+
|
|
|
+ with self.__geocode_cache_clean_timer_lock:
|
|
|
+ self.__geocode_cache_clean_timer = threading.Timer((self.__geocode_cache_clean_next - datetime.utcnow()).seconds, self.__latitude)
|
|
|
+
|
|
|
+ self.__geocode_cache_clean_timer.start()
|
|
|
+
|
|
|
def __help(self, connection, nick, admin, login, arguments):
|
|
|
command = irclib.irc_lower(arguments.split(None, 1)[0].lstrip('!')) if arguments else None
|
|
|
commands = {
|
|
@@ -173,12 +257,17 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
self.__write()
|
|
|
connection.privmsg(nick, 'successfully joined channel ("%s")' % channel)
|
|
|
|
|
|
- def __latitude(self, latitude = None):
|
|
|
- if latitude is not None:
|
|
|
- feature = json.load(urllib2.urlopen('http://www.google.com/latitude/apps/badge/api?' + urllib.urlencode({'user': latitude, 'type': 'json'})))['features'][0]
|
|
|
- properties = feature['properties']
|
|
|
+ def __latitude(self, granularity = None, token = None, secret = None):
|
|
|
+ if granularity is not None:
|
|
|
+ response, content = oauth.Client(self.__latitude_consumer, oauth.Token(token, secret)).request('https://www.googleapis.com/latitude/v1/currentLocation?' + urllib.urlencode({'granularity': granularity}), 'GET')
|
|
|
+
|
|
|
+ if int(response['status']) != 200:
|
|
|
+ raise Exception(content.strip())
|
|
|
+
|
|
|
+ data = json.loads(content)['data']
|
|
|
+ coordinates = (data['latitude'], data['longitude'])
|
|
|
|
|
|
- return properties['reverseGeocode'], tuple(reversed(feature['geometry']['coordinates'])), datetime.fromtimestamp(properties['timeStamp'], pytz.utc)
|
|
|
+ return datetime.fromtimestamp(int(data['timestampMs']) / 1e3, pytz.utc), coordinates, data.get('accuracy'), data.get('speed'), data.get('heading'), data.get('altitude'), data.get('altitudeAccuracy'), self.__geocode(False, coordinates = coordinates)[1]
|
|
|
|
|
|
now = datetime.utcnow()
|
|
|
|
|
@@ -195,25 +284,18 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
try:
|
|
|
db, cursor = self.__db()
|
|
|
|
|
|
- cursor.execute('select nick, channels, location, latitude from locationbot.nick where latitude is not null order by latitude')
|
|
|
+ cursor.execute('select nick, channels, location, latitude.granularity, token, latitude.secret from locationbot.nick join locationbot.latitude using (id)')
|
|
|
|
|
|
- locations = {}
|
|
|
-
|
|
|
- for nick, channels, old_location, latitude in cursor.fetchall():
|
|
|
- new_location = locations.get(latitude)
|
|
|
-
|
|
|
- if latitude not in locations:
|
|
|
- try:
|
|
|
- new_location, coordinates, updated = self.__latitude(latitude)
|
|
|
- locations[latitude] = new_location
|
|
|
- except Exception, error:
|
|
|
- print error
|
|
|
- continue
|
|
|
-
|
|
|
- cursor.execute('update locationbot.nick set location = %s, coordinates = point %s, updated = %s where latitude = %s', (new_location, coordinates, updated, latitude))
|
|
|
- db.commit()
|
|
|
+ for nick, channels, old_location, granularity, token, secret in cursor.fetchall():
|
|
|
+ try:
|
|
|
+ updated, coordinates, accuracy, speed, heading, altitude, altitude_accuracy, new_location = self.__latitude(granularity, token, secret)
|
|
|
+ except Exception, error:
|
|
|
+ print error
|
|
|
+ continue
|
|
|
|
|
|
- self.__location(nick, channels, old_location, new_location, coordinates)
|
|
|
+ cursor.execute('update locationbot.nick set granularity = %s, location = %s, coordinates = point %s, updated = %s where nick = %s', (granularity, new_location, coordinates, updated, nick))
|
|
|
+ db.commit()
|
|
|
+ self.__location(nick, channels, granularity, old_location, new_location, coordinates)
|
|
|
except psycopg2.Error, error:
|
|
|
print error
|
|
|
|
|
@@ -222,11 +304,11 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
|
|
|
self.__latitude_timer.start()
|
|
|
|
|
|
- def __location(self, nick, channels, old_location, new_location, coordinates = None):
|
|
|
+ def __location(self, nick, channels, granularity, old_location, new_location, coordinates):
|
|
|
if channels and new_location and new_location != old_location:
|
|
|
with self.__locations_lock:
|
|
|
for channel in self.__channels.intersection(channels):
|
|
|
- self.__locations.append((nick, channel, new_location, coordinates))
|
|
|
+ self.__locations.append((nick, channel, granularity, new_location, coordinates))
|
|
|
|
|
|
def __login(self, connection, nickmask, nick, arguments = ''):
|
|
|
login = nick
|
|
@@ -374,11 +456,19 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
if value is None:
|
|
|
variables = sorted(self.__variables) if variable is None else [variable]
|
|
|
|
|
|
- cursor.execute('select ' + ', '.join(map(lambda variable: "'%s'" % ('*' * 8) if variable == 'secret' else variable, variables)) + ' from locationbot.nick where nick = %s', (login,))
|
|
|
+ cursor.execute('select ' + ', '.join(map(lambda variable: "'%s'" % ('*' * 8) if variable == 'secret' else 'latitude.granularity, latitude.authorized' if variable == 'latitude' else variable, variables)) + ' from locationbot.nick join locationbot.latitude using (id) where nick = %s', (login,))
|
|
|
+
|
|
|
+ values = list(cursor.fetchone())
|
|
|
+
|
|
|
+ try:
|
|
|
+ index = variables.index('latitude')
|
|
|
+ values[index:index + 2] = ['%s (%s)' % (values[index], 'authorized' if values[index + 1] else 'unauthorized')]
|
|
|
+ except ValueError:
|
|
|
+ pass
|
|
|
|
|
|
connection.privmsg(nick, '\x02variable value\x0f')
|
|
|
|
|
|
- for variable, value in zip(variables, cursor.fetchone()):
|
|
|
+ for variable, value in zip(variables, values):
|
|
|
connection.privmsg(nick, '%-11s %s' % (variable, ' '.join(value) if isinstance(value, list) else '%f,%f' % value if isinstance(value, tuple) else value))
|
|
|
else:
|
|
|
def invalid(value, variable = variable):
|
|
@@ -398,18 +488,56 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
if not _mask.match(mask):
|
|
|
return invalid(mask, 'mask')
|
|
|
elif variable == 'latitude':
|
|
|
- try:
|
|
|
- value = int(re.sub(r'^(?:http://(?:www\.)?google\.com/latitude/apps/badge/api\?user=)?([0-9]+)(?:&type=.*)?$', r'\1', value))
|
|
|
- except ValueError:
|
|
|
- return invalid(value)
|
|
|
- elif variable in self.__geocode:
|
|
|
+ if value in self.__latitude_granularities:
|
|
|
+ response, content = oauth.Client(self.__latitude_consumer).request('https://www.google.com/accounts/OAuthGetRequestToken', 'POST', urllib.urlencode({
|
|
|
+ 'scope': 'https://www.googleapis.com/auth/latitude',
|
|
|
+ 'oauth_callback': 'oob',
|
|
|
+ }))
|
|
|
+
|
|
|
+ if int(response['status']) != 200:
|
|
|
+ raise Exception(content.strip())
|
|
|
+
|
|
|
+ authorized = False
|
|
|
+ else:
|
|
|
+ cursor.execute('select channels, location, latitude.granularity, token, latitude.secret from locationbot.nick join locationbot.latitude using (id) where nick = %s and authorized = false', (login,))
|
|
|
+
|
|
|
+ if cursor.rowcount == 0:
|
|
|
+ return invalid(value)
|
|
|
+
|
|
|
+ channels, old_location, granularity, token, secret = cursor.fetchone()
|
|
|
+ token = oauth.Token(token, secret)
|
|
|
+
|
|
|
+ token.set_verifier(value)
|
|
|
+
|
|
|
+ response, content = oauth.Client(self.__latitude_consumer, token).request('https://www.google.com/accounts/OAuthGetAccessToken', 'GET')
|
|
|
+ status = int(response['status'])
|
|
|
+
|
|
|
+ if status == 400:
|
|
|
+ return invalid(value)
|
|
|
+ elif status != 200:
|
|
|
+ raise Exception(content.strip())
|
|
|
+
|
|
|
+ authorized = True
|
|
|
+
|
|
|
+ data = dict(urlparse.parse_qsl(content))
|
|
|
+ token = data['oauth_token']
|
|
|
+ secret = data['oauth_token_secret']
|
|
|
+
|
|
|
+ if not authorized:
|
|
|
+ connection.privmsg(nick, 'go to https://www.google.com/latitude/apps/OAuthAuthorizeToken?' + urllib.urlencode({
|
|
|
+ 'domain': self.__latitude_key,
|
|
|
+ 'granularity': value,
|
|
|
+ 'oauth_token': token,
|
|
|
+ }))
|
|
|
+ elif variable in self.__geocode_variables:
|
|
|
cursor.execute('select channels, location from locationbot.nick where nick = %s', (login,))
|
|
|
|
|
|
channels, old_location = cursor.fetchone()
|
|
|
- parameters = {'sensor': 'false'}
|
|
|
|
|
|
if variable == 'location':
|
|
|
- parameters['address'] = value
|
|
|
+ coordinates = None
|
|
|
+ granularity = 'city'
|
|
|
+ location = value
|
|
|
else:
|
|
|
coordinates = value.split(None, 1)
|
|
|
|
|
@@ -421,42 +549,20 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
except ValueError:
|
|
|
return invalid(value)
|
|
|
|
|
|
- parameters['latlng'] = '%f,%f' % coordinates
|
|
|
+ for coordinate in coordinates:
|
|
|
+ if not -180.0 <= coordinate <= 180.0:
|
|
|
+ return invalid(value)
|
|
|
|
|
|
- geocode = json.load(urllib2.urlopen('http://maps.google.com/maps/api/geocode/json?' + urllib.urlencode(parameters)))
|
|
|
- status = geocode['status']
|
|
|
+ granularity = 'best'
|
|
|
+ location = None
|
|
|
|
|
|
- if status != 'OK':
|
|
|
- if status == 'ZERO_RESULTS':
|
|
|
- return invalid(value)
|
|
|
- else:
|
|
|
- raise Exception(status)
|
|
|
-
|
|
|
- results = geocode['results']
|
|
|
- result = results[0]
|
|
|
- new_location = result['formatted_address']
|
|
|
+ geocode = self.__geocode(False, coordinates, location)
|
|
|
+ new_location = geocode[1]
|
|
|
|
|
|
if variable == 'location':
|
|
|
- location = result['geometry']['location']
|
|
|
- coordinates = (location['lat'], location['lng'])
|
|
|
+ coordinates = geocode[0]
|
|
|
value = new_location
|
|
|
else:
|
|
|
- types = frozenset([
|
|
|
- 'country',
|
|
|
- 'administrative_area_level_1',
|
|
|
- 'administrative_area_level_2',
|
|
|
- 'administrative_area_level_3',
|
|
|
- 'colloquial_area',
|
|
|
- 'locality',
|
|
|
- 'sublocality',
|
|
|
- 'neighborhood',
|
|
|
- ])
|
|
|
-
|
|
|
- for result in results:
|
|
|
- if not types.isdisjoint(result['types']):
|
|
|
- new_location = result['formatted_address']
|
|
|
- break
|
|
|
-
|
|
|
value = coordinates
|
|
|
elif variable == 'nick':
|
|
|
_nick = value.split(None, 1)
|
|
@@ -468,7 +574,17 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
return invalid(value)
|
|
|
|
|
|
try:
|
|
|
- cursor.execute('update locationbot.nick set ' + ('location = %s, coordinates = point %s, updated = now()' if variable in self.__geocode else variable + ' = ' + ('md5(%s)' if variable == 'secret' else '%s')) + ' where nick = %s', (new_location, coordinates, login) if variable in self.__geocode else (value, login))
|
|
|
+ if variable in self.__geocode_variables:
|
|
|
+ cursor.execute('update locationbot.nick set granularity = %s, location = %s, coordinates = point %s, updated = now() where nick = %s', (granularity, new_location, coordinates, login))
|
|
|
+ elif variable == 'latitude':
|
|
|
+ if authorized:
|
|
|
+ cursor.execute('update locationbot.latitude set token = %s, secret = %s, authorized = %s from locationbot.nick where latitude.id = nick.id and nick = %s', (token, secret, authorized, login))
|
|
|
+ else:
|
|
|
+ cursor.execute('delete from locationbot.latitude using locationbot.nick where latitude.id = nick.id and nick = %s', (login,))
|
|
|
+ cursor.execute('insert into locationbot.latitude (id, granularity, token, secret, authorized) select id, %s, %s, %s, %s from locationbot.nick where nick = %s', (value, token, secret, authorized, login))
|
|
|
+ else:
|
|
|
+ cursor.execute('update locationbot.nick set ' + variable + ' = ' + ('md5(%s)' if variable == 'secret' else '%s') + ' where nick = %s', (value, login))
|
|
|
+
|
|
|
db.commit()
|
|
|
except psycopg2.IntegrityError:
|
|
|
if variable == 'nick':
|
|
@@ -480,16 +596,13 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
|
|
|
if variable == 'nick':
|
|
|
self.__logins[nick] = (value, nickmask)
|
|
|
- elif variable in self.__geocode or variable == 'latitude':
|
|
|
+ elif variable in self.__geocode_variables or variable == 'latitude' and authorized:
|
|
|
if variable == 'latitude':
|
|
|
- cursor.execute('select channels, location from locationbot.nick where nick = %s', (login,))
|
|
|
-
|
|
|
- channels, old_location = cursor.fetchone()
|
|
|
- new_location, coordinates, updated = self.__latitude(value)
|
|
|
+ updated, coordinates, accuracy, speed, heading, altitude, altitude_accuracy, new_location = self.__latitude(granularity, token, secret)
|
|
|
|
|
|
- cursor.execute('update locationbot.nick set location = %s, coordinates = point %s, updated = %s where nick = %s', (new_location, coordinates, updated, login))
|
|
|
+ cursor.execute('update locationbot.nick set granularity = %s, location = %s, coordinates = point %s, updated = %s where nick = %s', (granularity, new_location, coordinates, updated, login))
|
|
|
|
|
|
- self.__location(login, channels, old_location, new_location, coordinates)
|
|
|
+ self.__location(login, channels, granularity, old_location, new_location, coordinates)
|
|
|
|
|
|
def __status(self, connection, nick, login, arguments):
|
|
|
_nick = arguments.split(None, 1)[0] if arguments else None
|
|
@@ -509,10 +622,10 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
else:
|
|
|
timezone = pytz.utc
|
|
|
|
|
|
- connection.privmsg(nick, '\x02nick location when map\x0f')
|
|
|
+ connection.privmsg(nick, '\x02nick location when map\x0f')
|
|
|
|
|
|
for _nick, location, coordinates, updated in locations:
|
|
|
- connection.privmsg(nick, '%-23s %-35s %-23s %s' % (_nick, location, timezone.normalize(updated.astimezone(timezone)).strftime('%Y-%m-%d %H:%M %Z'), self.__coordinates(coordinates)))
|
|
|
+ connection.privmsg(nick, '%-23s %-35s %-23s %s' % (_nick, location, timezone.normalize(updated.astimezone(timezone)).strftime('%Y-%m-%d %H:%M %Z'), self.__url(_nick, 'best', location, coordinates)))
|
|
|
|
|
|
def __unknown(self, connection, nick, command):
|
|
|
connection.privmsg(nick, 'unknown command ("%s"); try "help"' % command)
|
|
@@ -534,10 +647,16 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
|
|
|
db, cursor = self.__db()
|
|
|
|
|
|
- cursor.execute('update locationbot.nick set ' + ('location = null, coordinates = null, updated = null' if variable in self.__geocode else variable + ' = null') + ' where nick = %s and ' + variable + ' is not null', (login,))
|
|
|
+ cursor.execute('update locationbot.nick set ' + ('location = null, coordinates = null, updated = null' if variable in self.__geocode_variables else variable + ' = null') + ' where nick = %s and ' + variable + ' is not null', (login,))
|
|
|
db.commit()
|
|
|
connection.privmsg(nick, 'variable ("%s") %s unset' % (variable, 'successfuly' if cursor.rowcount == 1 else 'already'))
|
|
|
|
|
|
+ def __url(self, nick, granularity, location, coordinates):
|
|
|
+ if granularity == 'best':
|
|
|
+ location = '%f,%f' % coordinates
|
|
|
+
|
|
|
+ return 'http://maps.google.com/maps?' + urllib.urlencode({'q': '%s (%s)' % (location, nick)})
|
|
|
+
|
|
|
def __who(self, connection, nick):
|
|
|
if self.__logins:
|
|
|
connection.privmsg(nick, '\x02login nick nick mask\x0f')
|
|
@@ -665,10 +784,15 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
connection.join(channel)
|
|
|
|
|
|
def start(self):
|
|
|
- self.__latitude_thread = threading.Thread(None, self.__latitude)
|
|
|
- self.__latitude_thread.daemon = True
|
|
|
+ latitude_thread = threading.Thread(None, self.__latitude)
|
|
|
+ latitude_thread.daemon = True
|
|
|
|
|
|
- self.__latitude_thread.start()
|
|
|
+ latitude_thread.start()
|
|
|
+
|
|
|
+ geocode_cache_clean_thread = threading.Thread(None, self.__geocode_cache_clean)
|
|
|
+ geocode_cache_clean_thread.daemon = True
|
|
|
+
|
|
|
+ geocode_cache_clean_thread.start()
|
|
|
|
|
|
if not self.__reloading:
|
|
|
self._connect()
|
|
@@ -684,8 +808,8 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
while not self.__reloading:
|
|
|
if self.__locations_lock.acquire(False):
|
|
|
if self.__locations and self.__channels.issubset(self.channels.keys()):
|
|
|
- for nick, channel, location, coordinates in self.__locations:
|
|
|
- self.connection.notice(channel, '%s is in %s' % (nick, location + self.__coordinates(coordinates)))
|
|
|
+ for nick, channel, granularity, location, coordinates in self.__locations:
|
|
|
+ self.connection.notice(channel, '%s is in %s %s' % (nick, location, self.__url(nick, granularity, location, coordinates)))
|
|
|
|
|
|
self.__locations = []
|
|
|
|
|
@@ -693,20 +817,30 @@ class LocationBot(ircbot.SingleServerIRCBot):
|
|
|
|
|
|
self.ircobj.process_once(0.2)
|
|
|
|
|
|
- self.__latitude_thread.join()
|
|
|
+ latitude_thread.join()
|
|
|
+ geocode_cache_clean_thread.join()
|
|
|
|
|
|
with self.__latitude_timer_lock:
|
|
|
if self.__latitude_timer is not None:
|
|
|
self.__latitude_timer.cancel()
|
|
|
self.__latitude_timer.join()
|
|
|
|
|
|
+ with self.__geocode_cache_clean_timer_lock:
|
|
|
+ if self.__geocode_cache_clean_timer is not None:
|
|
|
+ self.__geocode_cache_clean_timer.cancel()
|
|
|
+ self.__geocode_cache_clean_timer.join()
|
|
|
+
|
|
|
return not self.__quiting
|
|
|
|
|
|
def success(self):
|
|
|
self.connection.privmsg(self.__nick, 'successfully reloaded')
|
|
|
|
|
|
def _or(function, values):
|
|
|
- return reduce(lambda a, b: a or b, map(function, values) if values else [False])
|
|
|
+ for value in values:
|
|
|
+ if function(value):
|
|
|
+ return True
|
|
|
+
|
|
|
+ return False
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
os.chdir(os.path.abspath(os.path.dirname(__file__)))
|