now even stable with asyc events like chat or mail, etc
[shakeTheFidget.git] / session.py
blob05d9645b61d7ee1dacf3ae6a4cfe5b663e5e2a1d
1 import socket
2 from time import sleep
3 from threading import Thread, Event, Lock
5 # SQL stuff
6 from sqlalchemy import create_engine
7 from sqlalchemy.orm import sessionmaker
8 from player import metadata as metadataPlayer
10 # classes
11 from player import Player
12 from quest import QuestList
15 class Session():
16 def __init__(self, user, passwd, host = '213.165.80.92', port = 8005, version = 'v1.31'):
17 self.user = user
18 self.passwd = passwd
19 self.host = host
20 self.port = port
21 self.version = version
23 # s&f variables
24 self.character = Player(self, user)
26 self.quests = QuestList(self)
27 self.questTime = 0
29 # interfaces
30 self.socket = None
31 self.db = None
32 self.dbEngine = None
33 self.dbSession = None
35 # locks
36 self.lSocket = Lock()
38 # threads
39 self.tNoop = Noop(self)
40 self.tQueryList = QueryList(self, self.db)
42 # function to do cleanup on exit
43 def close(self):
44 self.disconnect()
45 self.dbClose()
47 # database init and close
48 def dbInit(self, filename = None):
49 if(not filename): filename = 'sqlite:///%s.db' % (self.user)
50 self.dbEngine = create_engine(filename)
52 #create tables (if !exist)
53 metadataPlayer.create_all(self.dbEngine)
55 #create session
56 self.dbSessionMaker = sessionmaker(bind=self.dbEngine)
57 self.db = self.dbSessionMaker()
59 def dbClose(self):
60 self.db.close()
62 # server primitives: connect, send, request, disconnect
63 def connect(self, host = None, port = None):
64 if(host): self.host = host
65 if(port): self.port = port
66 self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
67 self.socket.connect((self.host, self.port))
68 self.tNoop.start()
70 def disconnect(self):
71 self.tNoop.stop()
72 self.tQueryList.stop()
73 self.socket.close()
74 self.socket = None
76 def send(self, data):
77 with self.lSocket:
78 self.socket.send(data.encode('utf8')+chr(0))
80 def request(self, request, bufferlen = 1024):
81 with self.lSocket:
82 # discard everything not yet of interest (chat, mail, etc..)
83 self.socket.settimeout(0.0)
84 try:
85 while(True): self.socket.recv(bufflen)
86 except:
87 self.socket.settimeout(None)
89 self.socket.send(request.encode('utf8')+chr(0))
90 data = ''
91 while(data[-1:] != chr(0)):
92 data += self.socket.recv(bufferlen)
93 return data[:-1].decode('utf8')
95 # s&f functions
96 def sfLogin(self):
97 self.request('002%s;%s;%s' % (self.user, self.passwd, self.version))
99 def sfQueryTavern(self):
100 r010 = self.request('010')
101 code = r010[0:3]
102 data = r010[3:].split('/')
104 # questTime remaining
105 self.questTime = int(data[456])
107 # quests
108 self.quests.parse(r010)
110 def sfWardCity(self, hours = 1):
111 if(hours < 1 or hours > 10):
112 raise ValueError
113 try:
114 self.request('502%i' % (int(hours)))
115 sleep(hours *3600)
116 except KeyboardInterrupt:
117 self.request('505')
118 finally:
119 self.sfQueryTavern()
122 # getattribute of dynamic values
123 def __getattr__(self, name):
124 if(name == 'cooldownArena'):
125 r010 = self.request('010')
126 data = r010.split('/')
127 return int(data[460])-int(data[510])
129 # representation
130 def __repr__(self):
131 return '<Session \'%s\'>' % (self.name)
136 class MyThread(Thread):
137 def __init__(self, name = None):
138 Thread.__init__(self, name=name)
139 self.eStop = Event()
141 def stop(self):
142 if(self.isAlive()):
143 self.eStop.set()
144 self.join()
145 Thread.__init__(self, name=self.name)
147 def __del__(self):
148 self.stop()
150 class Noop(MyThread):
151 def __init__(self, session):
152 self.session = session
153 MyThread.__init__(self, name='Noop')
155 def run(self):
156 while(not self.eStop.isSet()):
157 self.session.send('999')
158 self.eStop.wait(50.0)
159 self.eStop.clear()
161 class QueryList(MyThread):
162 def __init__(self, session, db):
163 self.session = session
164 self.db = db
165 MyThread.__init__(self)
167 def run(self):
168 playerCount = self.session.request('007;%i' % (100000)).split('/')[-6]
169 i = 1
170 while(not self.eStop.isSet()):
171 data = self.session.request('007;%i' % (i))
172 result = data[0:3]
173 data = data[3:].split('/')
174 for j in range(15):
175 try:
176 #new = False
177 p = self.db.query(Player).filter(Player.name == data[(j *5) +1]).one()
178 except NoResultFound, e:
179 #new = True
180 p = Player(self.session)
181 p.name = data[(j *5) +1]
182 self.db.add(p)
183 p.honor = int(data[(j *5) +4])
184 p.guild = data[(j *5) +2]
185 p.level = abs(int(data[(j *5) +3]))
186 #print ('%s%s(%i) of %s - %i' % (['~', '+'][new], p.name, p.level, p.guild, p.honor)).encode('unicode_escape', 'replace')
187 self.db.commit()
188 i += 15
189 self.eStop.wait(5.0)
190 self.eStop.clear()