From f5b2d8c89daafaf2b54c21d00bea3aaddac7b5cb Mon Sep 17 00:00:00 2001 From: Teddy Date: Mon, 2 Sep 2013 12:19:25 +0800 Subject: ... --- server/piztor/easy_import.py | 34 ++++-- server/piztor/import.py | 2 +- server/piztor/model.py | 26 +++-- server/piztor/prober.py | 8 +- server/piztor/ptp.rst | 40 +++++++- server/piztor/ptp_send.py | 48 +++++++-- server/piztor/server.py | 240 ++++++++++++++++++++++++++++++++++++------- 7 files changed, 331 insertions(+), 67 deletions(-) diff --git a/server/piztor/easy_import.py b/server/piztor/easy_import.py index 261d44d..b614315 100644 --- a/server/piztor/easy_import.py +++ b/server/piztor/easy_import.py @@ -16,6 +16,12 @@ class UserData: self.perm = perm self.sub = sub +class MarkerData: + def __init__(self, lat, lng, score): + self.lat = lat + self.lng = lng + self.score = score + def create_database(): engine = create_engine('mysql://' + path, echo = True) Base.metadata.drop_all(engine) @@ -26,7 +32,7 @@ def find_or_create_group(comp_no, sec_no, session): q = session.query(GroupInfo).filter(GroupInfo.id == gid) entry = q.first() if not entry: - entry = GroupInfo(gid = gid) + entry = GroupInfo(id = gid, score = 0) return entry @@ -52,11 +58,22 @@ def import_user_data(data): session.add(um) session.commit() +def import_marker_data(data): + engine = create_engine('mysql://' + path, echo = True) + Session = sessionmaker(bind = engine) + session = Session() + + for marker in data: + mk = MarkerInfo(lat = marker.lat, lng = marker.lng, + status = MARKER_FRESH, score = marker.score) + session.add(mk) + session.commit() + if __name__ == '__main__': from sys import argv, exit - if len(argv) != 2: - print "Usage: " + argv[0] + " FILE" + if len(argv) != 3: + print "Usage: " + argv[0] + " FILE1 FILE2" exit(0) data = list() @@ -64,10 +81,9 @@ if __name__ == '__main__': while True: line = f.readline().split() if len(line) == 0: break - idx = 0 comp_no = line[3] sec_no = line[4] - sub = [ (comp_no, sec_no), (comp_no, 0xff) ] + sub = [ (comp_no, 0xff), (comp_no, sec_no) ] data.append(UserData(username = line[0], nickname = line[1], password = line[0], @@ -76,7 +92,13 @@ if __name__ == '__main__': sex = line[2], perm = line[5], sub = sub)) - + data2 = list() + with open(argv[2], 'r') as f: + while True: + line = f.readline().split() + if len(line) == 0: break + data2.append(MarkerData(lat = line[0], lng = line[1], score = line[2])) create_database() import_user_data(data) + import_marker_data(data2) diff --git a/server/piztor/import.py b/server/piztor/import.py index 7646afc..e552c91 100644 --- a/server/piztor/import.py +++ b/server/piztor/import.py @@ -26,7 +26,7 @@ def find_or_create_group(comp_no, sec_no, session): q = session.query(GroupInfo).filter(GroupInfo.id == gid) entry = q.first() if not entry: - entry = GroupInfo(gid = gid) + entry = GroupInfo(gid = gid, score = 0) return entry diff --git a/server/piztor/model.py b/server/piztor/model.py index cade3ea..bbeeb31 100644 --- a/server/piztor/model.py +++ b/server/piztor/model.py @@ -1,6 +1,6 @@ from sqlalchemy import Table, Column -from sqlalchemy import Integer, String, Float, ForeignKey, Boolean -from sqlalchemy.dialects.mysql import BLOB, TINYINT +from sqlalchemy import Integer, String, ForeignKey, Boolean +from sqlalchemy.dialects.mysql import BLOB, TINYINT, DOUBLE from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, backref from exc import * @@ -12,6 +12,9 @@ _TOKEN_LEN = 16 MAX_USERNAME_SIZE = 20 MAX_PASSWORD_SIZE = 20 NOT_A_LAT = NOT_A_LNG = 300 +MARKER_FRESH = 0x00 +MARKER_DISPLAYED = 0x01 +MARKER_CHECKED = 0x02 _table_typical_settings = { 'mysql_engine' : 'InnoDB', @@ -24,7 +27,7 @@ class _TableName: # avoid typoes UserAuth = 'user_auth' GroupInfo = 'group_info' GroupSub = 'group_sub' - + MarkerInfo = 'marker_info' class GroupInfo(Base): __tablename__ = _TableName.GroupInfo @@ -32,9 +35,7 @@ class GroupInfo(Base): id = Column(Integer, primary_key = True) subscribers = None - - def __init__(self, gid): - self.id = gid + score = Column(Integer, nullable = False) group_sub = Table(_TableName.GroupSub, Base.metadata, Column('uid', Integer, ForeignKey(_TableName.UserModel + '.id')), @@ -82,8 +83,8 @@ class LocationInfo(Base): uid = Column(Integer, ForeignKey(_TableName.UserModel + '.id'), primary_key = True) - lat = Column(Float(precesion = 64), nullable = False) - lng = Column(Float(precesion = 64), nullable = False) + lat = Column(DOUBLE, nullable = False) + lng = Column(DOUBLE, nullable = False) user = relationship("UserModel", uselist = False, backref = backref("location", uselist = False, cascade = "all, delete-orphan")) @@ -136,4 +137,13 @@ class UserAuth(Base): def get_token(self): return self.token +class MarkerInfo(Base): + __tablename__ = _TableName.MarkerInfo + __table_args__ = _table_typical_settings + + id = Column(Integer, primary_key = True) + lat = Column(DOUBLE, nullable = False) + lng = Column(DOUBLE, nullable = False) + status = Column(TINYINT) + score = Column(Integer) diff --git a/server/piztor/prober.py b/server/piztor/prober.py index bb2bcd3..f1f1109 100644 --- a/server/piztor/prober.py +++ b/server/piztor/prober.py @@ -4,8 +4,8 @@ from time import sleep from sys import argv from ptp_send import * -username = "haha" -password = "haha" +username = "yg" +password = "yg" #username = "12345678901234567890" #password = "world123456789012345" @@ -18,7 +18,9 @@ if len(argv) == 3: token = user_auth(username, password) -change_password(token, username, "ddd", "haha") +game_start(token, username) +#check_in(token, username, 0x23) +#change_password(token, username, "ddd", "haha") #print "Client: " + username + "logged in" #open_push_tunnel(token, username) #for i in xrange(100): diff --git a/server/piztor/ptp.rst b/server/piztor/ptp.rst index 24a9612..7e4acc4 100644 --- a/server/piztor/ptp.rst +++ b/server/piztor/ptp.rst @@ -1,5 +1,5 @@ -Piztor Transmission Protocol v2.0d ----------------------------------- +Piztor Transmission Protocol v2.0d for game +------------------------------------------- - Pull @@ -281,6 +281,29 @@ Piztor Transmission Protocol v2.0d - ``0x01`` for invalid token - ``0x03`` for wrong password + - Check-in ``0x09`` + + - Request + + :: + + +-------------+----1b-----+ + | AUTH_HEAD | MARKER_ID | + +-------------+---uchar---+ + + - Response + + :: + + +--------+ + | STATUS | + +--------+ + + - ``0x00`` for success + - ``0x01`` for invalid token + - ``0x05`` for check-in failure + + - Push Notification - General Request @@ -319,7 +342,14 @@ Piztor Transmission Protocol v2.0d :: - ----+--1b---+----8b----+----8b-----+----4b----+ - ... | LEVEL | LATITUDE | LONGITUDE | DEADLINE | - ----+-uchar-+----------+-----------+----int---+ + ----+--1b---+----8b----+----8b-----+----4b----+----1b-----+---4b--+ + ... | LEVEL | LATITUDE | LONGITUDE | DEADLINE | MARKER_ID | SCORE | + ----+-uchar-+----------+-----------+----int---+---uchar---+--int--+ + + - Marker Removal Push + + :: + ----+----1b-----+ + ... | MARKER_ID | + ----+-----------+ diff --git a/server/piztor/ptp_send.py b/server/piztor/ptp_send.py index 6c3b476..bcc996b 100644 --- a/server/piztor/ptp_send.py +++ b/server/piztor/ptp_send.py @@ -24,8 +24,8 @@ class _SectionSize: LOCATION_ENTRY = USER_ID + LATITUDE + LONGITUDE PADDING = 1 -host = "202.120.7.4" -#host = "localhost" +#host = "202.120.7.4" +host = "localhost" port = 2223 def pack_data(optcode, data): @@ -80,11 +80,11 @@ def gen_send_text_mesg(token, username, mesg): data += chr(0) return pack_data(0x06, data) -def gen_set_marker(token, username, lat, lng, deadline): +def gen_set_marker(token, username, lat, lng, deadline, mid, score): data = pack("!32s", token) data += username data += chr(0) - data += pack("!ddL", lat, lng, deadline) + data += pack("!ddLBL", lat, lng, deadline, mid, score) return pack_data(0x07, data) def gen_change_password(token, username, old_pass, new_pass): @@ -97,6 +97,19 @@ def gen_change_password(token, username, old_pass, new_pass): data += chr(0) return pack_data(0x08, data) +def gen_check_in(token, username, mid): + data = pack("!32s", token) + data += username + data += chr(0) + data += pack("!B", mid) + return pack_data(0x09, data) + +def gen_game_start(token, username): + data = pack("!32s", token) + data += username + data += chr(0) + return pack_data(0x0a, data) + def send(data): received = bytes() from time import time @@ -128,6 +141,7 @@ def user_auth(username, password): if pl != len(resp): logger.error("User authentication: incorrect packet length") print "status: " + str(status) + print get_hex(resp[38:]) # print "token: " + get_hex(token) except error: logger.error("User authentication: can not parse the response") @@ -188,8 +202,9 @@ def send_text_mesg(token, username, mesg): except error: logger.error("Send text mesg: can not parse the response") -def set_marker(token, username, lat, lng, deadline): - resp = send(gen_set_marker(token, username, lat, lng, deadline)) +def set_marker(token, username, lat, lng, deadline, mid, score): + resp = send(gen_set_marker(token, username, lat, lng, deadline, + mid, score)) try: pl, optcode, status = unpack("!LBB", resp) if pl != len(resp): @@ -208,6 +223,27 @@ def change_password(token, username, old_pass, new_pass): except error: logger.error("Change password: can not pase the response") +def check_in(token, username, mid): + resp = send(gen_check_in(token, username, mid)) + try: + pl, optcode, status = unpack("!LBB", resp) + if pl != len(resp): + logger.error("Check-in: incorrect packet length") + print "status: " + str(status) + except error: + logger.error("Check-in: can not pase the response") + +def game_start(token, username): + resp = send(gen_game_start(token, username)) + try: + pl, optcode, status = unpack("!LBB", resp) + if pl != len(resp): + logger.error("Game-start: incorrect packet length") + print "status: " + str(status) + except error: + logger.error("Game-start: can not parse the response") + + def open_push_tunnel(token, username): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) diff --git a/server/piztor/server.py b/server/piztor/server.py index 980ae03..7996e0a 100644 --- a/server/piztor/server.py +++ b/server/piztor/server.py @@ -44,6 +44,7 @@ class _SectionSize: LONGITUDE = 8 PADDING = 1 DEADLINE = 4 + MARKER_ID = 1 _MAX_AUTH_HEAD_SIZE = _SectionSize.USER_TOKEN + \ MAX_USERNAME_SIZE + \ @@ -54,6 +55,7 @@ _HEADER_SIZE = _SectionSize.LENGTH + \ _MAX_TEXT_MESG_SIZE = 1024 _MAX_SUB_LIST_SIZE = 10 _MAX_PENDING_PUSH = 10 +_INIT_MARKER_NUM = 2 class _OptCode: user_auth = 0x00 @@ -65,6 +67,8 @@ class _OptCode: send_text_mesg = 0x06 set_marker = 0x07 change_password = 0x08 + check_in = 0x09 + game_start = 0x0A class _StatusCode: sucess = 0x00 @@ -72,6 +76,7 @@ class _StatusCode: insuf_lvl = 0x02 wrong_pass = 0x03 grp_not_found = 0x04 + checkin_fail = 0x05 class PushData(object): from hashlib import sha256 @@ -91,8 +96,16 @@ class PushLocationData(PushData): self.pack(0x01, struct.pack("!Ldd", uid, lat, lng)) class PushMarkerData(PushData): - def __init__(self, perm, lat, lng, deadline): - self.pack(0x02, struct.pack("!Bddl", perm, lat, lng, deadline)) + def __init__(self, perm, lat, lng, deadline, mid, score): + self.pack(0x02, struct.pack("!BddlBL", perm, lat, lng, deadline, + mid, score)) +class PushMarkerRemovalData(PushData): + def __init__(self, mid): + self.pack(0x03, struct.pack("!B", mid)) + +class PushScoreData(PushData): + def __init__(self, score1, score2): + self.pack(0x04, struct.pack("!LL", score1, score2)) class PushTunnel(object): def __init__(self, uid): @@ -126,8 +139,8 @@ class PushTunnel(object): def push(self): if self.blocked: return - #print "Pushing via " + str(self.uid) - #print "Pending size: " + str(len(self.pending)) + print "Pushing via " + str(self.uid) + print "Pending size: " + str(len(self.pending)) #logger.info("Pushing...") if (self.conn is None) or len(self.pending) == 0: return @@ -335,6 +348,17 @@ class UserAuthHandler(RequestHandler): # USER_ENTRY reply += RequestHandler.pack_user_entry(user) reply += RequestHandler.pack_sub_list(user) + score1 = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == 5889).one().score + score2 = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == 5890).one().score + + for mrk in self.session.query(MarkerInfo).all(): + if mrk.status != MARKER_DISPLAYED: + continue + reply += struct.pack("!BddlBL", 2, mrk.lat, mrk.lng, 0x7fffffff, + mrk.id, mrk.score) + reply += struct.pack("!LL", score1, score2) return self.pack(reply) @@ -357,9 +381,9 @@ class UpdateLocationHandler(RequestHandler): except struct.error: raise BadReqError("Update location: Malformed request body") -# logger.info("Trying to update location with " -# "(token = {0}, username = {1}, lat = {2}, lng = {3})"\ -# .format(get_hex(token), username, lat, lng)) + logger.info("Trying to update location with " + "(token = {0}, username = {1}, lat = {2}, lng = {3})"\ + .format(get_hex(token), username, lat, lng)) uauth = RequestHandler.get_uauth(token, username, self.session) # Authentication failure @@ -384,15 +408,6 @@ class UpdateLocationHandler(RequestHandler): pdata = PushLocationData(u.id, lat, lng) for user in comp.subscribers: uid = user.id - if uid == uauth.uid: continue - if pt.has_key(uid): - tunnel = pt[uid] - tunnel.add(pdata) - tunnel.push() - - for user in sec.subscribers: - uid = user.id - if uid == uauth.uid: continue if pt.has_key(uid): tunnel = pt[uid] tunnel.add(pdata) @@ -638,6 +653,32 @@ class SetMarkerHandler(RequestHandler): _SectionSize.LATITUDE + \ _SectionSize.LONGITUDE + \ _SectionSize.DEADLINE + @classmethod + def push_new_marker(cls, u, session): + left = session.query(MarkerInfo) \ + .filter(MarkerInfo.status == MARKER_FRESH).all() + if len(left) == 0: + logger.warn("All markers have been used!") + return + marker = left[0] + marker.status = MARKER_DISPLAYED + session.commit() + pdata = PushMarkerData(perm = 2, lat = marker.lat, \ + lng = marker.lng, \ + deadline = 0x7fffffff, \ + mid = marker.id, \ + score = marker.score) + ulist = session.query(UserModel) \ + .filter(UserModel.comp_id == u.comp_id).all() + + pt = RequestHandler.push_tunnels + for user in ulist: + uid = user.id + if pt.has_key(uid): + tunnel = pt[uid] + tunnel.add(pdata) + tunnel.push() + def handle(self, tr_data, conn): self.check_size(tr_data) @@ -645,15 +686,15 @@ class SetMarkerHandler(RequestHandler): try: token, = struct.unpack("!32s", tr_data[:32]) username, tail = RequestHandler.trunc_padding(tr_data[32:]) - lat, lng, deadline = struct.unpack("!ddl", tail) + lat, lng, deadline, mid, score = struct.unpack("!ddlBL", tail) if username is None: raise struct.error except struct.error: raise BadReqError("Set marker: Malformed request body") -# logger.info("Trying to set marker with " -# "(token = {0}, username = {1})"\ -# .format(get_hex(token), username)) + logger.info("Trying to set marker with " + "(token = {0}, username = {1})"\ + .format(get_hex(token), username)) uauth = RequestHandler.get_uauth(token, username, self.session) # Authentication failure @@ -661,24 +702,8 @@ class SetMarkerHandler(RequestHandler): logger.warning("Authentication failure") return self.pack(struct.pack("!B", _StatusCode.auth_fail)) - pt = RequestHandler.push_tunnels - u = uauth.user - if u.perm == _PermCode.section: - ulist = self.session.query(UserModel) \ - .filter(UserModel.sec_id == u.sec_id).all() - elif u.perm == _PermCode.company: - ulist = self.session.query(UserModel) \ - .filter(UserModel.comp_id == u.comp_id).all() - else: - return self.pack(struct.pack("!B", _StatusCode.insuf_lvl)) + SetMarkerHandler.push_new_marker(uauth.user, self.session) - for user in ulist: - uid = user.id - if uid == uauth.uid: continue - if pt.has_key(uid): - tunnel = pt[uid] - tunnel.add(PushMarkerData(u.perm, lat, lng, deadline)) - tunnel.push() logger.info("Set marker successfully!") return self.pack(struct.pack("!B", _StatusCode.sucess)) @@ -727,6 +752,143 @@ class ChangePasswordHandler(RequestHandler): return self.pack(struct.pack("!B", _StatusCode.sucess)) +class CheckInHandler(RequestHandler): + + _optcode = _OptCode.check_in + _max_tr_data_size = _MAX_AUTH_HEAD_SIZE + \ + _SectionSize.MARKER_ID + + def handle(self, tr_data, conn): + self.check_size(tr_data) + logger.info("Reading check-in data...") + try: + token, = struct.unpack("!32s", tr_data[:32]) + username, tail = RequestHandler.trunc_padding(tr_data[32:]) + if username is None: + raise struct.error + mid, = struct.unpack("!B", tail) + except struct.error: + raise BadReqError("Check-in: Malformed request body") + + logger.info("Trying to check-in with " + "(token = {0}, username = {1}, mid = {2})"\ + .format(get_hex(token), username, str(mid))) + + uauth = RequestHandler.get_uauth(token, username, self.session) + # Authentication failure + if uauth is None: + logger.warning("Authentication failure") + return self.pack(struct.pack("!B", _StatusCode.auth_fail)) + + try: + marker = self.session.query(MarkerInfo) \ + .filter(MarkerInfo.id == mid).one() + except NoResultFound: + raise BadReqError("Check-in: no such marker") + + if marker.status != MARKER_DISPLAYED: + return self.pack(struct.pack("!B", _StatusCode.checkin_fail)) + marker.status = MARKER_CHECKED + + pt = RequestHandler.push_tunnels + u = uauth.user + + comp = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == u.comp_id).one() + sec = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == u.sec_id).one() + + sec.score += marker.score + logger.info("Player {0} got score: {1}".format(username, str(marker.score))) + + score1 = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == 5889).one().score + score2 = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == 5890).one().score + + pdata = PushMarkerRemovalData(mid) + for user in comp.subscribers: + uid = user.id + if pt.has_key(uid): + tunnel = pt[uid] + tunnel.add(pdata) + tunnel.add(PushScoreData(score1, score2)) + tunnel.push() + + SetMarkerHandler.push_new_marker(u, self.session) + + logger.info("User checked in successfully!") + self.session.commit() + return self.pack(struct.pack("!B", _StatusCode.sucess)) + +class GameStartHandler(RequestHandler): + + _optcode = _OptCode.game_start + _max_tr_data_size = _MAX_AUTH_HEAD_SIZE + + def handle(self, tr_data, conn): + self.check_size(tr_data) + logger.info("Reading game-start data...") + try: + token, = struct.unpack("!32s", tr_data[:32]) + username, tail = RequestHandler.trunc_padding(tr_data[32:]) + if username is None: + raise struct.error + except struct.error: + raise BadReqError("Game-start: Malformed request body") + + logger.info("Trying to game-start with " + "(token = {0}, username = {1})"\ + .format(get_hex(token), username)) + + uauth = RequestHandler.get_uauth(token, username, self.session) + # Authentication failure + if uauth is None: + logger.warning("Authentication failure") + return self.pack(struct.pack("!B", _StatusCode.auth_fail)) + + + pt = RequestHandler.push_tunnels + u = uauth.user + + if u.perm != 2: + logger.warning("Insufficient privilege") + return self.pack(struct.pack("!B", _StatusCode.insuf_lvl)) + + team1 = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == 5889).one() + team2 = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == 5890).one() + + team1.score = 0 + team2.score = 0 + + for mrk in self.session.query(MarkerInfo).all(): + mrk.status = MARKER_FRESH + + users1 = self.session.query(UserModel) \ + .filter(UserModel.sec_id == team1.id) + + users2 = self.session.query(UserModel) \ + .filter(UserModel.sec_id == team2.id) + + for i in xrange(_INIT_MARKER_NUM): + SetMarkerHandler.push_new_marker(u, self.session) + + comp = self.session.query(GroupInfo) \ + .filter(GroupInfo.id == u.comp_id).one() + + for user in comp.subscribers: + uid = user.id + if pt.has_key(uid): + tunnel = pt[uid] + tunnel.add(PushScoreData(team1.score, team2.score)) + tunnel.push() + + logger.info("GAME START!") + self.session.commit() + return self.pack(struct.pack("!B", _StatusCode.sucess)) + class PTP(Protocol, TimeoutMixin): @@ -738,7 +900,9 @@ class PTP(Protocol, TimeoutMixin): OpenPushTunnelHandler, SendTextMessageHandler, SetMarkerHandler, - ChangePasswordHandler] + ChangePasswordHandler, + CheckInHandler, + GameStartHandler] handler_num = len(handlers) -- cgit v1.2.3