Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (2)
from abc import abstractmethod, ABCMeta
import json
import socket
from game.game import Game, GameMap
from game.player import Player
from game.item import Item
class Command(object):
__metaclass__ = ABCMeta
"""
Abstract base class for commands
"""
METHOD_JOIN = "join"
METHOD_SERVERSTATUS = "serverStatus"
METHOD_SIGNUP = "signup"
METHOD_LOGIN = "login"
METHOD_INVENTORY = "inventory"
METHOD_MIXITEM = "mixitem"
METHOD_MAP = "map"
METHOD_MOVE = "move"
METHOD_FIELD = "field"
METHOD_OFFER = "offer"
METHOD_TRADEBOX = "tradebox"
METHOD_SENDFIND = "sendfind"
METHOD_FINDOFFER = "findoffer"
METHOD_SENDACCEPT = "sendaccept"
METHOD_ACCEPT = "accept"
METHOD_FETCHITEM = "fetchitem"
METHOD_CANCELOFFER = "canceloffer"
def __init__(self):
super().__init__()
self.__error = None
"""
Executes the command
"""
@abstractmethod
def execute(self):
raise NotImplementedError("You need to implement the method for your Command class")
def getStatus(self):
"""
Gets the status of the command's execution
Any error should be assigned to the self.__error variable.
If the self.__error object is a str, fail status will be returned
else, error status will be returned
returns dict object
"""
if not self.__error:
return {'status': 'ok'}
else:
if isinstance(self.__error, str):
return {'status': 'fail', 'description': self.__error}
else:
return {'status': 'error'}
class CommandFactory(object):
def __init__(self, **jsonObject):
super().__init__()
self.__json = jsonObject
self.game = Game.getInstance()
def getCommand(self):
method = self.__json["method"]
if method == Command.METHOD_JOIN:
if 'ip' in self.__json and 'port' in self.__json:
return JoinCommand(self.__json['ip'], self.__json['port'])
else:
return JoinCommand()
elif method == Command.METHOD_SERVERSTATUS:
return ServerStatusCommand(self.__json['server'])
elif method == Command.METHOD_SIGNUP:
return SignupCommand(self.game, self.__json["username"], self.__json["password"])
elif method == Command.METHOD_LOGIN:
return LoginCommand(self.game, self.__json["username"], self.__json["password"])
elif method == Command.METHOD_INVENTORY:
return InventoryQueryCommand(self.game, self.__json["token"])
elif method == Command.METHOD_MIXITEM:
return MixItemCommand(self.game, self.__json["token"], self.__json["item1"], self.__json["item2"])
elif method == Command.METHOD_MAP:
return MapQueryCommand(self.game, self.__json["token"])
elif method == Command.METHOD_MOVE:
return MoveCommand(self.game, self.__json["token"], self.__json["x"], self.__json["y"])
elif method == Command.METHOD_FIELD:
return GetItemFromFieldCommand(self.game, self.__json["token"])
elif method == Command.METHOD_OFFER:
return MakeItemOfferCommand(self.game,
self.__json["token"],
self.__json["offered_item"],
self.__json["n1"],
self.__json["demanded_item"],
self.__json["n2"])
elif method == Command.METHOD_TRADEBOX:
return TradeboxQueryCommand(self.game, self.__json["token"])
elif method == Command.METHOD_SENDFIND:
return SendFindCommand(self.game, self.__json["token"], self.__json["item"])
elif method == Command.METHOD_FINDOFFER:
return FindOfferCommand(self.__json["item"], self.__json["ip"], self.__json["port"])
elif method == Command.METHOD_SENDACCEPT:
return SendAcceptCommand(self.game, self.__json["token"], self.__json["offer_token"])
elif method == Command.METHOD_ACCEPT:
return AcceptItemOfferCommand(self.__json["offer_token"], self.__json["ip"], self.__json["port"])
elif method == Command.METHOD_FETCHITEM:
return FetchOfferedItemCommand(self.game, self.__json["token"], self.__json["offer_token"])
elif method == Command.METHOD_CANCELOFFER:
return CancelItemOfferCommand(self.game, self.__json["token"], self.__json["offer_token"])
else:
raise ValueError("Unknown method: {}".format(method))
# SERVER COMMANDS #
class JoinCommand(Command):
DEFAULT_TRACKER_IP, DEFAULT_TRACKER_PORT = '167.205.32.46', 8000
def __init__(self, ip = JoinCommand.DEFAULT_TRACKER_IP, port = JoinCommand.DEFAULT_TRACKER_PORT):
super().__init__()
self.ip = ip
self.port = port
self.result = None
def execute(self):
sock = socket.socket()
try:
sock.connect((self.ip, self.port))
sock.sendall(json.dumps({
'method': Command.METHOD_JOIN,
'ip': self.ip,
'port': self.port
}))
"""
This assumes that the server is going to send some small data.
Maybe in the future this needs to be revised, to handle arbitary-sized data.
"""
data = sock.recv(4096, 'utf-8')
if data:
self.result = json.loads(data)
else:
self.__error = True
except Exception, e:
self.__error = str(e)
finally:
sock.close()
def getStatus(self):
if self.result:
return self.result
else:
if not self.__error:
self.__error = True
super().getStatus()
class ServerStatusCommand(Command):
DB_COLLECTION_SERVER = 'activeServers'
def __init__(self, serverList):
super().__init__()
self.servers = serverList
def execute(self):
try:
with pymongo.MongoClient().get_database(Game.DB_NAME) as db:
collection = db.get_collection(ServerStatusCommand.DB_COLLECTION_SERVER)
for server in enumerate(self.servers):
collection.update_one({'ip': server['ip']}, {'$set': {'port': server['port']} })
except Exception:
self.__error = True
class SignupCommand(Command):
def __init__(self, game, username, password):
super().__init__()
self.game = game
self.username = username
self.password = password
def execute(self):
try:
game.playerSignup(self.username, self.password)
with pymongo.MongoClient().get_database(Game.DB_NAME) as db:
db.users.insert({
Player.KEY_USERNAME: self.username,
Player.KEY_PASSWORD: bcrypt.hashpw(self.password, bcrypt.gensalt()),
Player.KEY_ITEMS: [],
Player.KEY_CURRENTLOCATION: {
'x': 0,
'y': 0
},
Player.KEY_OFFERS: []
})
except Exception, e:
self.__error = str(e)
class LoginCommand(Command):
def __init__(self, game, username, password):
super().__init__()
self.game = game
self.username = username
self.password = password
self.token = None
def execute(self):
try:
self.token = game.playerLogin(self.username, self.password)
# should not fail. Not yet tested though .__.
self.player = game.getPlayer(token = self.token)
if not self.player:
self.__error = True
except Exception, e:
self.__error = str(e)
def getStatus(self):
if not self.error and self.token:
return {
'status': 'ok',
'token': self.token,
'x': self.player.currentLocation.x,
'y': self.player.currentLocation.y,
'time': int(time.time())
}
else:
if not self.__error:
self.__error = True
super().getStatus()
class InventoryQueryCommand(Command):
"""
docstring for InventoryQueryCommand
"""
def __init__(self, game, token):
super().__init__()
self.game = game
self.token = token
self.inventory = []
def execute(self):
player = game.getPlayer(token = self.token)
if not player:
self.__error = True
else:
self.inventory = player.getInventory()
def getStatus(self):
if not self.error and self.inventory:
return {
'status': 'ok',
'inventory': self.inventory
}
else:
if not self.__error:
self.__error = True
super().getStatus()
class MixItemCommand(Command):
def __init__(self, game, token, item1_id, item2_id):
super().__init__()
self.game = game
self.token = token
self.item1 = item1_id
self.item2 = item2_id
self.result = None
def execute(self):
player = game.getPlayer(token = self.token)
if player:
else:
self.__error = True
def getStatus(self):
if self.result:
return {
'status': 'ok',
'item': self.result
}
else:
if not self.__error:
self.__error = True
super().getStatus()
class MapQueryCommand(Command):
def __init__(self, game, token):
super().__init__()
self.game = game
self.token = token
self.map = None
def execute(self):
if player.getPlayer(token = self.token):
self.map = game.map
else:
self.__error = True
def getStatus(self):
if self.map:
return {
'status': 'ok',
'name': self.map.name,
'width': self.map.width,
'height': self.map.height
}
else:
if not self.__error:
self.__error = True
super().getStatus()
class MoveCommand(Command):
def __init__(self, game, token, x, y):
super().__init__()
self.game = game
self.token = token
self.x = x
self.y = y
def execute(self):
player = self.game.getPlayer(token = self.token)
if not player:
self.__error = True
else:
try:
player.moveTo(x = x, y = y)
# TODO: update the player's position in the db
except Exception, e:
self.__error = str(e)
def getStatus(self):
if not self.__error:
return {
'status': 'ok',
'time': int(time.time())
}
else:
super().getStatus()
# alias: Field
class GetItemFromFieldCommand(Command):
def __init__(self, game, token):
super().__init__()
self.game = game
self.token = token
self.item = None
def execute(self):
player = self.game.getPlayer(token = self.token)
if not player:
self.__error = True
else:
try:
self.item = player.takeItem(location = player.currentLocation)
# TODO: update the player's inventory in the db
except Exception, e:
self.__error = str(e)
def getStatus(self):
if not self.__error and self.result:
return {
'status': ok,
'item': self.item
}
else:
if not self.__error:
self.__error = True
super().getStatus()
class MakeItemOfferCommand(Command):
def __init__(self, game, token, offer_item, offer_itemCount, demand_item, demand_itemCount):
super().__init__()
self.game = game
self.token = token
self.offer_item = Item(id=offer_item, count=offer_itemCount)
self.demand_item = Item(id=demand_item, count=demand_itemCount)
def execute(self):
try:
player = self.game.getPlayer(self.token)
if player:
player.makeOffer(self.offer_item, self.demand_item)
# TODO: add the offer to the global offer table, and update the player's offer table
else:
self.__error = True
except Exception, e:
self.__error = e
class TradeboxQueryCommand(Command):
def __init__(self, game, token):
super().__init__()
self.game = game
self.token = token
self.result = []
def execute(self):
try:
player = self.game.getPlayer(self.token)
if player:
for offer in enumerate(player.getTradebox()):
self.result.append(offer.asList())
else:
self.__error = True
except Exception, e:
self.__error = e
def getStatus(self):
if not self.__error and self.result:
return {
'status': 'ok',
'offers': self.result
}
else:
if not self.__error:
self.__error = True
super().getStatus()
class SendFindCommand(Command):
def __init__(self, game, token, itemId):
super().__init__()
self.game = game
self.token = token
self.item = itemId
self.result = None
def execute(self):
# TODO: get the offers for an item
pass
def getStatus(self):
if not self.__error and self.result:
return {
'status': 'ok',
'offers': self.result
}
else:
if not self.__error:
self.__error = True
super().getStatus()
# NOTE: this is something that is sent by the server, not received by the server
class FindOfferCommand(Command):
def __init__(self, item, ip, port):
super().__init__()
self.item = item
self.ip = ip
self.port = port
self.result = None
def execute(self):
sock = socket.socket()
try:
sock.connect((self.ip, self.port))
sock.sendAll(json.dumps({
'method': Command.METHOD_FINDOFFER,
'item': self.item
}))
"""
This assumes that the server is going to send small-sized data.
Maybe in the future this needs to be revised, to handle arbitary-sized data.
"""
data = sock.recv(4096, 'utf-8')
self.result = json.loads(data)
except Exception, e:
self.__error = str(e)
finally:
sock.close()
def getStatus(self):
if not self.__error and self.result:
return self.result
else:
if not self.__error:
self.__error = True
super().getStatus()
class SendItemAcceptOfferCommand(Command):
def __init__(self, game, token, offer_token):
super().__init__()
self.game = game
self.token = token
self.offer_token = offer_token
def execute(self):
# TODO: accept the player's offer
pass
# NOTE: this is something that is sent by the server, not received by the server
class AcceptItemOfferCommand(Command):
def __init__(self, offer_token, ip, port):
super().__init__()
self.token = token
self.offer_token = offer_token
self.ip = ip
self.port = port
self.result = None
def execute(self):
# TODO: accept the player's offer from other server
# Question: do we need to duplicate?
pass
class FetchOfferedItemCommand(Command):
def __init__(self, game, token, offer_token):
super().__init__()
self.game = game
self.token = token
self.offer_token = offer_token
def execute(self):
# TODO: fetch the player's offer
pass
class CancelItemOfferCommand(Command):
def __init__(self, game, token, offer_token):
super().__init__()
self.game = game
self.token = token
self.offer_token = offer_token
def execute(self):
# TODO: cancel the player's offer
pass
\ No newline at end of file
import pymongo
import json
import bcrypt
class Location(object):
def __init__(self, x, y):
super().__init__()
self.x = int(x)
self.y = int(y)
class GameMap(object):
def __init__(self, name, width, height, locations = None):
assert width > 0 and height > 0
super().__init__()
self.name = name
self.width = int(width)
self.height = int(height)
if not locations:
self.locations = [[None] * height] * width
else:
assert len(locations) == width and len(locations[0]) == height
self.locations = []
for elem in locations:
self.locations.append(elem)
class Game(object):
FILE_MAP = 'map.json'
DB_NAME = 'if3230-sister'
DB_COLLECTION_USERS = 'users'
__instance = None
def __init__(self, mapFile = FILE_MAP):
super().__init__()
# the attributes
self.players = []
self.map = None
with open(mapFile) as map_file:
self.__loadMap(json.load(mapFile))
self.__loadPlayers()
@classmethod
def getInstance(self):
if not Game.__instance:
Game.__instance = Game()
return Game.__instance
def __loadMap(self, json):
assert isinstance(json, dict)
self.map = GameMap(json['name'], json['width'], json['height'], json['map'])
def __loadPlayers(self):
self.players = []
with pymongo.MongoClient().get_database(Game.DB_NAME) as db:
# load the players from the db
cursor = db.get_collection(Game.DB_COLLECTION_USERS)
for player in cursor.find():
location = Location(player['location']['x'], player['location']['y'])
players.append(Player(self, player['username'], player['password'], location))
"""
Do a player login
Attributes:
username -- the Player's username
password -- the Player's password in plaintext
Returns the authentication token
"""
def playerLogin(self, username, password):
for player in enumerate(self.players):
if player.username == username:
break
else:
raise LookupError('user not found: {}'.format(username))
if isinstnace(password, str):
password = password.encode()
assert isinstance(password, bytes)
if bcrypt.hashpw(password, player.password) != player.password:
raise ValueError('invalid password')
token = Player.__generateToken(username, password)
player.token = token
return token
"""
Signup a new user
Attributes:
username -- the Player's username
password -- the Player's password in plaintext
"""
def playerSignup(self, username, password):
for player in enumerate(self.players):
if player.username == username:
raise ValueError('Username already exists')
else:
if isinstance(password, str):
password = password.encode()
hashed_pass = bcrypt.hashpw(password, bcrypt.gensalt())
self.players.append(Player(username, hashed_pass))
"""
Get a player object
Attributes:
token: the login token
username: the Player's username
"""
def getPlayer(self, token = None, username = None):
if token or username:
for player in enumerate(self.players):
assert isinstance(player.username, str)
if player.username == username or (token and player.token == token):
return player
else:
return None
else:
raise TypeError('No search argument (token or username) defined')
\ No newline at end of file
import abc
class GameObject(object):
__metaclass__ = abc.ABCMeta;
"""Represents a basic GameObject, with an id
Attributes:
id -- the GameObject's id
"""
def __init__(self, id=None, gameObject=None):
super().__init__()
if isinstance(gameObject, GameObject):
self.__copyInit(gameObject)
elif GameObject.isValidId(id):
self.__selfInit(id)
else:
raise ValueError('Invalid parameters')
def __selfInit(self, id):
this.__id = id
def __copyInit(self, gameObject):
this.__id = gameObject.__id
"""Generate the id of the GameObject"""
@classmethod
def generateId(self):
raise NotImplementedError();
@classmethod
def isValidId(self, id):
return isinstance(id, str) or isinstance(id, int)
def __str__(self):
return "[GameObject {id}]".format(id = self.id)
\ No newline at end of file
from game_object import GameObject
from enum import Enum
from player import Player
class ItemId(Enum):
HONEY = (0, 'R11')
HERBS = (1, 'R12')
CLAY = (2, 'R13')
MINERAL = (3, 'R14')
POTION = (4, 'R21')
INCENSE = (5, 'R22')
GEMS = (6, 'R23')
LIFE_ELIXIR = (7, 'R31')
MANA_CRYSTAL = (8, 'R32')
PHILOSOPHER_STONE = (9, 'R41')
def __init__(self, index: int, idStr: str):
assert isinstance(index, int) and isinstance(idStr, str)
this.index = index
this.id = idStr
class Item(GameObject):
"""docstring for Item"""
def __init__(self,
id: int = None,
itemId: ItemId = None,
item: Item = None,
count: int = None):
if isinstance(item, Item):
super().__init__(item.id)
super().__copyInit(item)
self.__copyInit(item)
elif isinstance(itemId, ItemId):
super().__init__(itemId.id)
if isinstance(count, int):
self.__selfInit(count)
else:
self.__selfInit(1)
elif GameObject.isValidId(id):
super().__init__(id)
if isinstance(count, int):
self.__selfInit(count)
else:
self.__selfInit(1)
else:
raise TypeError('Invalid constructor parameter(s) for Item')
def __selfInit(self, count: int):
if count > 0:
self.__count = count
else:
self.__count = 1
def __copyInit(self, item: Item):
self.__count = item.__count
def count(self, newVal: int = None):
if isinstance(newVal, int): # setter
if newVal >= 0:
self.__count = newVal
else:
raise ValueError('Item count cannot be negative')
elif not newVal: # getter
return __count
else: # some other param
raise TypeError('Invalid parameter for newVal')
"""Number of items used in a single mix"""
__MIX_USAGE = 3
@classmethod
def mixItems(self, item1: Item, item2: Item) -> Item:
if not isinstance(item1, Item):
raise TypeError('item1 is not an Item')
if not isinstance(item2, Item):
raise TypeError('item2 is not an Item')
if item1.__count >= Item.__MIX_USAGE and item2.__count >= Item.__MIX_USAGE:
# define the recipe here
result = None
# Level 1 mix
if ((Item.isEqual(item1, ItemId.HONEY) and Item.isEqual(item2, ItemId.HERBS)) or
(Item.isEqual(item1, ItemId.HERBS) and Item.isEqual(item2, ItemId.HONEY))):
result = Item(itemId=ItemId.POTION)
elif ((Item.isEqual(item1, ItemId.HERBS) and Item.isEqual(item2, ItemId.CLAY)) or
(Item.isEqual(item1, ItemId.CLAY) and Item.isEqual(item2, ItemId.HERBS))):
result = Item(itemId=ItemId.INCENSE)
elif ((Item.isEqual(item1, ItemId.CLAY) and Item.isEqual(item2, ItemId.MINERAL)) or
(Item.isEqual(item1, ItemId.MINERAL) and Item.isEqual(item2, ItemId.CLAY))):
result = Item(itemId=ItemId.GEMS)
# Level 2 mix
elif ((Item.isEqual(item1, ItemId.POTION) and Item.isEqual(item2, ItemId.INCENSE)) or
(Item.isEqual(item1, ItemId.INCENSE) and Item.isEqual(item2, ItemId.POTION))):
result = Item(itemId=ItemId.LIFE_ELIXIR)
elif ((Item.isEqual(item1, ItemId.INCENSE) and Item.isEqual(item2, ItemId.GEMS)) or
(Item.isEqual(item1, ItemId.GEMS) and Item.isEqual(item2, ItemId.INCENSE))):
result = Item(itemId=ItemId.MANA_CRYSTAL)
# Level 3 mix
elif ((Item.isEqual(item1, ItemId.LIFE_ELIXIR) and Item.isEqual(item2, ItemId.MANA_CRYSTAL)) or
(Item.isEqual(item1, ItemId.MANA_CRYSTAL) and Item.isEqual(item2, ItemId.LIFE_ELIXIR))):
result = Item(itemId=ItemId.PHILOSOPHER_STONE)
else:
raise ValueError('Unknown recipe for item {} and {}'.format(item1.id, item2.id))
# reduce
item1.__count -= Item.__MIX_USAGE
item2.__count -= Item.__MIX_USAGE
return result
else:
if item1.__count < Item.__MIX_USAGE:
raise ValueError('not enough items for item1')
else:
raise ValueError('not enough items for item2')
@classmethod
def isEqual(self, item: Item, itemId: ItemId) -> boolean:
if isinstance(item, Item) and isinstance(itemId, ItemId):
return item.__id == itemId.index || item.__id == itemId.id
else:
raise TypeError('Invalid parameter(s)')
class ItemOffer(GameObject):
"""docstring for ItemOffer"""
def __init__(self, player: Player, offer: Item, demand: Item):
super().__init__(ItemOffer.generateId())
self.offerer_id = player.id
self.offer = offer
self.demand = demand
# Available means that this offer is available to be get
self.available = True
@classmethod
def generateId(self):
import hashlib
import random
import string
result = str(int(time.time()))
# generate a random string with length of 6
result += (''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(6)))
md5hash = hashlib.md5()
md5hash.update(result)
return str(md5hash.hexdigest())
def asList(self):
return [self.offer.__id, self.offer.count, self.demand.__id, self.demand.__count, self.avaliable, self.__id]
from game_object import GameObject
from game import Game, Location
import json
import time
import pymongo
class Player(GameObject):
COUNT = 0
KEY_USERNAME = 'username'
KEY_PASSWORD = 'password'
KEY_CURRENTLOCATION = 'location'
KEY_ITEMS = 'items'
KEY_OFFERS = 'offers'
"""Creates a Player object, for logging in purposes
Attributes:
game -- the Game object related to the player
username -- the Player's username, for identification purposes
password -- the Player's password
location -- the Player's avatar's current position in the map
"""
def __init__(self,
game : Game
username : str,
password : str,
location : Location = None
):
super().__init__(Player.generateId())
self.game = game
self.username = username
self.password = password
# some protos
self.token = None
self.items = []
self.offers = []
if not location:
# new user implied
self.currentLocation = Location(0, 0)
else:
# user already exists in db
self.currentLocation = location
self.__loadProperties()
def __loadProperties(self):
with pymongo.MongoClient().get_database(Game.DB_NAME) as db:
cursor = db.get_collection(Game.DB_COLLECTION_USERS).find({'username': self.username})
if cursor.count() == 1:
userDict = cursor.next()
__loadItems(db, userDict)
__loadOffers(db, userDict)
else:
if cursor.count() == 0:
raise LookupError('player not found: {}'.format(self.username))
else: # some error: multiple users found
raise LookupError('multiple players found for {}:{}'.format(self.username, cursor.count()))
def __loadItems(self, db, userDict):
if 'items' in userDict:
for item in enumerate(userDict['items']):
self.items.append(Item(id = item['id'], count = item['count']))
else:
# initialize empty inventory
db.get_collection(Game.DB_COLLECTION_USERS).update(
{
'_id': obj['_id']
},
{
'$set': {
'items': []
}
}
)
def __loadOffers(self, db, userDict):
if 'offers' in userDict:
for offer in enumerate(userDict['offers']):
self.offers.append()
else:
# initialize empty inventory
db.get_collection(Game.DB_COLLECTION_USERS).update(
{
'_id': obj['_id']
},
{
'$set': {
'offers': []
}
}
)
def getInventory(self):
inventory = []
for item in enumerate(self.items):
for count in range(item.count):
inventory.append(item.id)
return inventory
def moveTo(self,
x : int = None,
y : int = None,
location : Location = None):
if x is int and y is int:
if x in range(0, self.game.map.width) and y in range(0, self.game.map.height):
self.currentLocation.x = x
self.currentLocation.y = y
else: raise ValueError('Position out of bounds: ({},{})'.format(x, y))
elif location is Location:
if location.x in range(0, self.game.map.width) and y in range(0, self.game.map.height):
self.currentLocation = location
else:
raise ValueError('Position out of bounds: ({},{})'.format(location.x, location.y))
else:
raise ValueError('Invalid parameter')
def takeItem(self,
x : int = None,
y : int = None,
location : Location = None,
offerId : str = None):
if (x and y) or location:
# take item at position x, y
if not (x and y):
x = location.x
y = location.y
return self.game.map.locations[x][y]
elif offerId is str:
# do lookup
pass
else:
raise TypeError('Invalid parameter')
def addItem(self,
item: Item = None,
itemId: string = None,
count: int = 1):
if isinstance(item, Item):
self.items.append(item)
elif isinstance(id, str) and isinstance(count, int):
self.items.append(Item(id = itemId, count = count))
else:
raise TypeError('Invalid parameter')
def getTradebox(self):
return self.offers
def mixItems(self,
item1: Item,
item2: Item):
pass
def makeOffer(self,
offer: Item,
demand: Item):
pass
def cancelOffer(self, offerId: str):
pass
def acceptOffer(self, offerId: str):
pass
@classmethod
def generateId(self):
Player.COUNT += 1
return "P-{:03d}".format(Player.COUNT)
@classmethod
def __generateToken(self, username, password):
assert isinstance(self.password, str) and isinstance(self.username, str)
text = username
text += ':'
text += password
text += str(int(time.time()))
return bcrypt.hashpw(text.encode(), bcrypt.gensalt())
\ No newline at end of file
import socket
import threading
import socketserver
import json
import time
import sys
import sched
from command import CommandFactory, Command
class RequestHandler(socketserver.BaseRequestHandler):
BUFSIZE = 4096
def handle(self):
data = self.getData()
# check if the request is not empty (aka pings)
if not data:
pass
else:
try:
jsonObject = json.loads(data)
# throw it into the command processor
factory = CommandFactory(jsonObject)
command = factory.getCommand()
command.execute()
response = command.getStatus()
assert(isinstance(response, dict))
self.request.sendall(json.dumps(response))
except Exception, e:
pass # TODO: log the error
def getData(self, timeout = 3):
total_data = []
end = False
self.request.setblocking(0)
begin = time.time()
while not end:
# if got some data, break after wait sec
if total_data and time.time() - begin > timeout:
end = True
else:
# if no data, break after 2x the timeout
if time.time() - begin > timeout * 2:
end = True
else:
try:
data = self.request.recv(RequestHandler.BUFSIZE, 'utf-8')
if not data:
time.sleep(0.1)
else:
total_data.append(data)
begin = time.time()
except Exception, e:
# TODO: log the error
end = True
return ''.join(total_data)
class ThreadedTcpServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def connectTracker():
factory = CommandFactory({
'method': Command.METHOD_JOIN
})
command = factory.getCommand()
command.execute()
# TODO: get the status, then add the servers to the activeServers list
def findItem(server, ip, port):
pass
if __name__ == '__main__':
HOST, PORT = 'localhost', sys.argv[1]
server = ThreadedTcpServer((HOST, PORT), RequestHandler)
# start a server thread
server_thread = threading.Thread(target=server.serve_forever)
# exit the server thread when the main thread ends
server_thread.daemon = True
server_thread.start()
print("Server running on thread: ", server_thread.name)
server_thread.stop()
\ No newline at end of file