From fca8b55ebc85ac447daeb241063622bf79fa0910 Mon Sep 17 00:00:00 2001 From: Teddy Date: Fri, 30 Aug 2013 10:08:29 +0800 Subject: ptp v2.0 and server on the road --- server/piztor/import.py | 51 +++++++++--- server/piztor/model.py | 85 ++++++++++--------- server/piztor/ptp.rst | 214 ++++++++++++++++++++++++++---------------------- server/piztor/server.py | 46 ++++++----- 4 files changed, 222 insertions(+), 174 deletions(-) (limited to 'server') diff --git a/server/piztor/import.py b/server/piztor/import.py index 4896325..f5228e7 100644 --- a/server/piztor/import.py +++ b/server/piztor/import.py @@ -2,32 +2,49 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from model import * -path = "root:helloworld@localhost/piztor" +path = "root:helloworld@localhost/piztor2" class UserData: - def __init__(self, username, password, comp_id, sec_no, sex): + def __init__(self, username, nickname, password, comp_no, sec_no, sex, sub): self.username = username + self.nickname = nickname self.password = password - self.comp_id = int(comp_id) + self.comp_no = int(comp_no) self.sec_no = int(sec_no) - self.sex = sex + self.sex = int(sex) + self.sub = sub def create_database(): engine = create_engine('mysql://' + path, echo = True) Base.metadata.drop_all(engine) Base.metadata.create_all(engine) +def find_or_create_group(comp_no, sec_no, session): + gid = UserModel.to_gid(comp_no, sec_no) + q = session.query(GroupInfo).filter(GroupInfo.id == gid) + entry = None + entry = q.first() + if not entry: + entry = GroupInfo(gid = gid) + return entry + + def import_user_data(data): engine = create_engine('mysql://' + path, echo = True) Session = sessionmaker(bind = engine) session = Session() + for user in data: um = UserModel(username = user.username, - comp_id = user.comp_id, - sec_no = user.sec_no, - sec_id = user.comp_id * 256 + user.sec_no, - sex = user.sex) - print um.sec_id + nickname = user.nickname, + sex = user.sex, + comp_no = user.comp_no, + sec_no = user.sec_no) + + for cn, sn in user.sub: + print cn, sn + g = find_or_create_group(int(cn), int(sn), session) + um.sub.append(g) um.auth = UserAuth(user.password) um.location = LocationInfo(lat = 0, lng = 0) session.add(um) @@ -45,11 +62,19 @@ if __name__ == '__main__': while True: line = f.readline().split() if len(line) == 0: break + line2 = f.readline().split() + idx = 0 + sub = list() + while idx < len(line2): + sub.append((line2[idx], line2[idx + 1])) + idx += 2 data.append(UserData(username = line[0], - password = line[1], - comp_id = line[2], - sec_no = line[3], - sex = line[4])) + nickname = line[1], + password = line[2], + comp_no = line[3], + sec_no = line[4], + sex = line[5], sub = sub)) + create_database() import_user_data(data) diff --git a/server/piztor/model.py b/server/piztor/model.py index b1a7804..03c0192 100644 --- a/server/piztor/model.py +++ b/server/piztor/model.py @@ -3,6 +3,7 @@ from sqlalchemy import Integer, String, Float, ForeignKey, Boolean from sqlalchemy.dialects.mysql import BLOB, TINYINT from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, backref +from exc import * Base = declarative_base() @@ -20,18 +21,25 @@ class _TableName: # avoid typoes UserModel = 'users' LocationInfo = 'location_info' UserAuth = 'user_auth' - CompanyInfo = 'comp_info' - SectionInfo = 'sec_info' - CompanySub = 'comp_sub' - SectionSub = 'sec_sub' - -#comp_sub_assoc = Table(_TableName.CompanySub, Base.metadata, -# Column('uid', Integer, ForeignKey(_TableName.UserModel + '.id')), -# Column('comp_id', Integer, ForeignKey(_TableName.CompanyInfo + '.id'))) -# -#sec_sub_assoc = Table(_TableName.SectionSub, Base.metadata, -# Column('uid', Integer, ForeignKey(_TableName.UserModel + '.id')), -# Column('sec_id', Integer, ForeignKey(_TableName.SectionInfo + '.id'))) + GroupInfo = 'group_info' + GroupSub = 'group_sub' + + +class GroupInfo(Base): + __tablename__ = _TableName.GroupInfo + __table_args__ = _table_typical_settings + + id = Column(Integer, primary_key = True) + subscribers = None + + def __init__(self, gid): + self.id = gid + +group_sub = Table(_TableName.GroupSub, Base.metadata, + Column('uid', Integer, ForeignKey(_TableName.UserModel + '.id')), + Column('gid', Integer, ForeignKey(_TableName.GroupInfo + '.id')), + mysql_engine = 'InnoDB') + class UserModel(Base): __tablename__ = _TableName.UserModel @@ -39,24 +47,31 @@ class UserModel(Base): id = Column(Integer, primary_key = True) username = Column(String(MAX_USERNAME_SIZE), unique = True, nullable = False) - + nickname = Column(String(MAX_USERNAME_SIZE), + unique = False) sex = Column(Boolean, nullable = False) - sec_no = Column(TINYINT) -# comp_id = Column(TINYINT, ForeignKey(_TableName.CompanyInfo + '.id')) - comp_id = Column(TINYINT) -# sec_id = Column(TINYINT, ForeignKey(_TableName.SectionInfo + '.id')) + comp_id = Column(Integer) sec_id = Column(Integer) -# comp_sub = relationship(_TableName.CompanyInfo, -# secondary = comp_sub_assoc, -# backref = "subscribers") -# sec_sub = relationship(_TableName.SectionInfo, -# secondary = sec_sub_assoc, -# backref = "subscribers") + sub = relationship("GroupInfo", + secondary = group_sub, + backref = "subscribers") location = None auth = None - sec = None + + @classmethod + def to_gid(self, comp_no, sec_no): + return comp_no * 256 + sec_no + + def __init__(self, username, nickname, sex, comp_no, sec_no): + self.username = username + self.nickname = nickname + self.sex = sex + self.comp_id = UserModel.to_gid(comp_no, 0xff) + self.sec_id = UserModel.to_gid(comp_no, sec_no) + self.sub = list() + class LocationInfo(Base): __tablename__ = _TableName.LocationInfo @@ -117,23 +132,5 @@ class UserAuth(Base): def get_token(self): return self.token -# -#class CompanyInfo(Base): -# __tablename__ = _TableName.CompanyInfo -# __table_args__ = _table_typical_settings -# -# id = Column(TINYINT, primary_key = True) -# marker_lat = Column(Float(precesion = 64), nullable = False) -# marker_lng = Column(Float(precesion = 64), nullable = False) -# -# subscribers = None -# -#class SectionInfo(Base): -# __tablename__ = _TableName.SectionInfo -# __table_args__ = _table_typical_settings -# -# id = Column(TINYINT, primary_key = True) -# marker_lat = Column(Float(precesion = 64), nullable = False) -# market_lng = Column(Float(precesion = 64), nullable = False) -# -# subscribers = None + + diff --git a/server/piztor/ptp.rst b/server/piztor/ptp.rst index 19eab65..66c1fe2 100644 --- a/server/piztor/ptp.rst +++ b/server/piztor/ptp.rst @@ -1,4 +1,4 @@ -Piztor Transmission Protocol v1.0b +Piztor Transmission Protocol v2.0 ---------------------------------- - Pull @@ -23,9 +23,16 @@ Piztor Transmission Protocol v1.0b Notice: - - In following sections, ``LENGTH`` part is left out for clarity. - - ``PADDING`` has value ``0``. - - ``string`` type structure: + - In following sections, ``LENGTH`` and ``OPT_ID`` are left out for clarity. + - ``PADDING``: + + :: + + +--1b--+ + | 0x00 | + +------+ + + - ``string`` type: :: @@ -33,178 +40,193 @@ Piztor Transmission Protocol v1.0b | STRING_CONTENT | PADDING | +----------------+---------+ - - ``AUTH_HEAD`` structure: + - ``AUTH_HEAD`` : :: +----32b-----+----?b----+ | USER_TOKEN | USERNAME | +----raw-----+--string--+ + + - ``GROUP_ID`` : + + :: + + +---1b----+---1b---+ + | COMP_ID | SEC_ID | + +--uchar--+-uchar--+ + + - ``USER_ENTRY`` : + + :: - - Authentication + +----1b---+------?b-----+-----+---------+ + | USER_ID | INFO_ENTRY | ... | PADDING | + +--uchar--+-------------+-----+---------+ + + - ``INFO_ENTRY`` : + + :: + + +----1b----+-----?b-----+ + | INFO_KEY | INFO_VALUE | + +--uchar---+------------+ + + - ``INFO_KEY`` : + + :``0x01``: uid (value is a 4-byte ``integer``) + :``0x02``: username (value is a ``string``) + :``0x03``: nickname (value is a ``string``) + :``0x04``: sex (value is a 1-byte ``boolean``: ``0x01`` for male, ``0x00`` for female) + :``0x05``: gid (value is a 2-byte ``GROUP_ID``) + :``0x06``: latitude (value is a 8-byte ``double`` ) + :``0x07``: longtitude( value is a 8-byte ``double`` ) + + - ``SUB_LIST`` : + + :: + + +----------+-----+ + | GROUP_ID | ... | + +----------+-----+ + + - Authentication ``0x00`` - Request :: - +--1b---+-----?b---+----?b----+ - | 0x00 | USERNAME | PASSWORD | - +-uchar-+--string--+--string--+ + +-----?b---+----?b----+ + | USERNAME | PASSWORD | + +--string--+--string--+ - Response :: - +--1b---+---1b---+---4b----+----32b-----+ - | 0x00 | STATUS | USER_ID | USER_TOKEN | - +-uchar-+--uchar-+---int---+----raw-----+ + +---1b---+----32b-----+------------+----------+ + | STATUS | USER_TOKEN | USER_ENTRY | SUB_LIST | + +--uchar-+----raw-----+------------+----------+ ``STATUS`` : - ``0x00`` for success - ``0x01`` for failure - - Location Update + - Location Update ``0x01`` - Request :: - +--1b---+-----?b------+----8b------+------8b-----+ - | 0x01 | AUTH_HEAD | LATITUDE | LONGITUDE | - +-uchar-+-------------+---double---+---double----+ + +-------------+----8b------+------8b-----+ + | AUTH_HEAD | LATITUDE | LONGITUDE | + +-------------+---double---+---double----+ - Response :: - +--1b---+---1b---+ - | 0x01 | STATUS | - +-uchar-+--uchar-+ + +--------+ + | STATUS | + +--uchar-+ ``STATUS`` : - ``0x00`` for success - ``0x01`` for invalid token - - Location Information - - - Request - - :: - - +--1b---+------?b------+------2b-----+ - | 0x02 | AUTH_HEAD | GROUP_ID | - +-uchar-+--------------+-------------+ - ``GROUP_ID``: - - :: - - +---1b----+---1b---+ - | COMP_ID | SEC_ID | - +--uchar--+-uchar--+ - - - Response - - :: - - +--1b---+---1b---+------20b-------+-----+ - | 0x02 | STATUS | LOCATION_ENTRY | ... | - +-uchar-+-uchar--+----------------+-----+ - - ``LOCATION_ENTRY`` : - - :: - - +---4b----+----8b----+-----8b----+ - | USER_ID | LATITUDE | LONGITUDE | - +---int---+--double--+--double---+ - - - User Information + - User Information (by group) ``0x02`` - Request :: - +--1b---+------?b------+------4b-----+ - | 0x03 | AUTH_HEAD | USER_ID | - +-uchar-+--------------+-----int-----+ + +--------------+------4b-----+ + | AUTH_HEAD | GROUP_ID | + +--------------+-----int-----+ - Response :: - +--1b---+---1b---+------?b-----+-----+ - | 0x03 | STATUS | UINFO_ENTRY | ... | - +-uchar-+-uchar--+-------------+-----+ - - ``UINFO_ENTRY`` : - + +--------+------?b-----+-----+ + | STATUS | USER_ENTRY | ... | + +-uchar--+-------------+-----+ + + + - Update Subscription ``0x03`` + + - Request + :: + + +-----------+----------+ + | AUTH_HEAD | SUB_LIST | + +-----------+----------+ + + - Response + + :: + + +--------+ + | STATUS | + +--------+ - +----1b----+-----?b-----+ - | INFO_KEY | INFO_VALUE | - +--uchar---+------------+ - - ``INFO_KEY`` : - - :``0x00``: gid (value is a 2-byte ``GROUP_ID``) - :``0x01``: sex (value is a 1-byte ``boolean``: ``0x01`` for male, ``0x00`` for female) - - - User Logout + - User Logout ``0x04`` - Request :: - +--1b--+-----?b------+ - | 0x04 | AUTH_HEAD | - +------+-------------+ + +-----------+ + | AUTH_HEAD | + +-----------+ - Response :: - +--1b--+---1b---+ - | 0x04 | STATUS | - +------+--------+ + +--------+ + | STATUS | + +--------+ - - Open Push Tunnel + - Open Push Tunnel ``0x05`` - Request :: - +--1b--+-----?b------+ - | 0x05 | AUTH_HEAD | - +------+-------------+ + +-----------+ + | AUTH_HEAD | + +-----------+ - Response :: - +--1b--+---1b---+ - | 0x05 | STATUS | - +------+--------+ + +--------+ + | STATUS | + +--------+ - - Send Text Message + - Send Text Message ``0x06`` - Request :: - +--1b--+----?b-----+----?b----+ - | 0x06 | AUTH_HEAD | MESSAGE | - +------+-----------+--string--+ + +-----------+----?b----+ + | AUTH_HEAD | MESSAGE | + +-----------+--string--+ - Response :: - +--1b--+---1b---+ - | 0x06 | STATUS | - +------+--------+ + +--------+ + | STATUS | + +--------+ - Push Notification @@ -232,11 +254,11 @@ Piztor Transmission Protocol v1.0b ... | MESSAGE | ----+--string--+ - - User Location Update + - Location Update :: - ----+-------?b-------+ - ... | LOCATION_ENTRY | - ----+----------------+ + ----+---4b----+----8b----+----8b-----+ + ... | USER_ID | LATITUDE | LONGITUDE | + ----+---------+----------+-----------+ diff --git a/server/piztor/server.py b/server/piztor/server.py index ed4e0b9..3bd1a2c 100644 --- a/server/piztor/server.py +++ b/server/piztor/server.py @@ -19,10 +19,7 @@ from model import * def get_hex(data): return "".join([hex(ord(c))[2:].zfill(2) for c in data]) -def get_sec_id(comp_id, sec_no): - return comp_id * 256 + sec_no - -db_path = "root:helloworld@localhost/piztor" +db_path = "root:helloworld@localhost/piztor2" #db_path = "piztor.sqlite" FORMAT = "%(asctime)-15s %(message)s" logging.basicConfig(format = FORMAT) @@ -292,10 +289,22 @@ class LocationUpdateHandler(RequestHandler): self.session.commit() pt = RequestHandler.push_tunnels - ulist = self.session.query(UserModel) \ - .filter(UserModel.sec_id == uauth.user.sec_id).all() - pdata = PushLocationData(uauth.uid, lat, lng) - for user in ulist: + 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() + + 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): @@ -327,13 +336,13 @@ class LocationInfoHandler(RequestHandler): username, tail = RequestHandler.trunc_padding(tr_data[32:]) if username is None: raise struct.error - comp_id, sec_no = struct.unpack("!BB", tail) + comp_no, sec_no = struct.unpack("!BB", tail) except struct.error: raise BadReqError("Location request: Malformed request body") logger.info("Trying to request locatin with " \ - "(token = {0}, comp_id = {1}, sec_no = {2})" \ - .format(get_hex(token), comp_id, sec_no)) + "(token = {0}, comp_no = {1}, sec_no = {2})" \ + .format(get_hex(token), comp_no, sec_no)) uauth = RequestHandler.get_uauth(token, username, self.session) # Auth failure @@ -343,13 +352,9 @@ class LocationInfoHandler(RequestHandler): _OptCode.location_info, _StatusCode.failure) - if sec_no == 0xff: # All members in the company - ulist = self.session.query(UserModel) \ - .filter(UserModel.comp_id == comp_id).all() - else: - sec_id = get_sec_id(comp_id, sec_no) - ulist = self.session.query(UserModel) \ - .filter(UserModel.sec_id == sec_id).all() + ulist = self.session.query(UserModel) \ + .filter(UserModel.sec_id == + UserModel.to_gid(comp_no, sec_no)).all() reply = struct.pack( "!LBB", self._response_size(len(ulist)), @@ -363,7 +368,7 @@ class LocationInfoHandler(RequestHandler): return reply def pack_gid(user): - return struct.pack("!BB", user.comp_id, user.sec_no) + return struct.pack("!H", user.sec_id) def pack_sex(user): return struct.pack("!B", 0x01 if user.sex else 0x00) @@ -557,9 +562,8 @@ class SendTextMessageHandler(RequestHandler): pt = RequestHandler.push_tunnels u = uauth.user - sec_id = get_sec_id(u.comp_id, u.sec_no) ulist = self.session.query(UserModel) \ - .filter(UserModel.sec_id == sec_id).all() + .filter(UserModel.sec_id == u.sec_id).all() for user in ulist: uid = user.id -- cgit v1.2.3-70-g09d2