"""
Copyright 2015, Joseph Botosh <rumly111@gmail.com>
This file is part of tradey, a trading bot in The Mana World
see www.themanaworld.org
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
Additionally to the GPL, you are *strongly* encouraged to share any modifications
you do on these sources.
"""
import sys
import logging
import urllib2
import string
import sqlite3
import datetime
import threading
import time
from net.packet_out import whisper
import config
class OnlineUsers:
def __init__(self, online_url='http://server.themanaworld.org/online-old.txt', update_interval=20):
self._active = False
self._timer = 0
self._thread = threading.Thread(target=self._threadfunc, args=())
self._url = online_url
self._update_interval = update_interval
self.__lock = threading.Lock()
self.__online_users = []
@property
def online_users(self):
self.__lock.acquire(True)
users = self.__online_users[:]
self.__lock.release()
return users
def dl_online_list(self):
"""
Download online.txt, parse it, and return a list of online user nicks.
If error occurs, return empty list
"""
try:
data = urllib2.urlopen(self._url).read()
except urllib2.URLError, e:
# self.logger.error("urllib error: %s", e.message)
print ("urllib error: %s" % e.message)
return []
start = string.find(data, '------------------------------\n') + 31
end = string.rfind(data, '\n\n')
s = data[start:end]
return map(lambda n: n[:-5].strip() if n.endswith('(GM) ') else n.strip(),
s.split('\n'))
def _threadfunc(self):
while self._active:
if (time.time() - self._timer) > self._update_interval:
users = self.dl_online_list()
self.__lock.acquire(True)
self.__online_users=users
self.__lock.release()
self._timer = time.time()
else:
time.sleep(1.0)
def start(self):
self._active = True
self._thread.start()
def stop(self):
if self._active:
self._active = False
self._thread.join()
class SqliteDbManager:
def __init__(self, dbfile):
self._active = False
self._timer = 0
self._lastseen_thread = threading.Thread(target=self.__lastseen_threadfunc, args=())
self._mailbox_thread = threading.Thread(target=self.__mailbox_threadfunc, args=())
self._dbfile = dbfile
self.mapserv = None
self._online_manager = OnlineUsers(config.online_txt_url, config.online_txt_interval)
self.db, self.cur = self._open_sqlite_db(dbfile)
self.cur.execute('create table if not exists LastSeen(\
NICK text[25] not null unique,\
DATE_ date not null)')
self.cur.execute('create table if not exists MailBox(\
ID integer primary key,\
FROM_ text[25] not null,\
TO_ text[25] not null,\
MESSAGE text[255] not null)')
self.cur.execute('create unique index if not exists \
FROM_TO_IDX on MailBox(FROM_,TO_)')
self.db.commit()
def __del__(self):
try:
self.db.close()
except Exception:
pass
def _open_sqlite_db(self, dbfile):
"""
Open sqlite db, and return tuple (connection, cursor)
"""
try:
db = sqlite3.connect(dbfile)
cur = db.cursor()
except sqlite3.Error, e:
# self.logger.error("sqlite3 error: %s", e.message)
print ("sqlite3 error: %s" % e.message)
sys.exit(1)
return db, cur
def __update_lastseen_info(self, users, db, cur):
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
values = map(lambda u: (u, now), users)
cur.executemany('replace into LastSeen(NICK,DATE_) values(?,?)',
values)
db.commit()
def get_lastseen_info(self, nick):
try:
self.cur.execute('select DATE_ from LastSeen where NICK=?',(nick,))
self.db.commit() # NOTE: do I need it?
row = self.cur.fetchone()
except sqlite3.Error, e:
print ("sqlite3 error: %s" % e.message)
row = ["although I do not remember when."]
if row:
return ('%s was seen %s' % (nick, row[0])).encode('utf-8')
else:
return '%s was never seen' % nick
def __lastseen_threadfunc(self):
print '__lastseen_threadfunc started'
db, cur = self._open_sqlite_db(self._dbfile)
while self._active:
if (time.time() - self._timer) > 60:
users = self._online_manager.online_users
self.__update_lastseen_info(users, db, cur)
self._timer = time.time()
else:
time.sleep(1.0)
db.close()
def send_mail(self, from_, to_, message):
try:
self.cur.execute('replace into MailBox(FROM_,TO_,MESSAGE) values(?,?,?)',
(from_,to_,message))
self.db.commit()
except sqlite3.Error, e:
print ("sqlite3 error: %s" % e.message)
def get_unread_mails(self, nick, db=None, cur=None):
try:
if db is None:
db = self.db
if cur is None:
cur = self.cur
cur.execute('select FROM_,MESSAGE from MailBox where TO_=?',
(nick,))
db.commit()
mails = cur.fetchall()
cur.execute('delete from MailBox where TO_=?',
(nick,))
db.commit()
except sqlite3.Error, e:
print ("sqlite3 error: %s" % e.message)
mails = []
return mails
def __mailbox_threadfunc(self):
print '__mailbox_threadfunc started'
db, cur = self._open_sqlite_db(self._dbfile)
while self._active:
if (time.time() - self._timer) > 60:
users = self._online_manager.online_users
for u in users:
mail = self.get_unread_mails(u, db, cur)
nm = len(mail)
if nm > 0:
self.mapserv.sendall(whisper(u, "You have %d new mails:" % (nm,)))
time.sleep(0.7)
for m in mail:
msg = ("From %s : %s" % (m[0], m[1])).encode('utf-8')
self.mapserv.sendall(whisper(u, msg))
time.sleep(0.7)
self._timer = time.time()
else:
time.sleep(1.0)
db.close()
def forEachOnline(self, callback, *args):
users = self._online_manager.online_users
for u in users:
callback(u, *args)
def start(self):
self._online_manager.start()
self._active = True
self._lastseen_thread.start()
self._mailbox_thread.start()
def stop(self):
if self._active:
self._active = False
self._lastseen_thread.join()
self._mailbox_thread.join()
self._online_manager.stop()
if __name__=='__main__':
print "You should not run this file. Use main.py"