Esempio n. 1
0
	def __init__(self):
		FBRconProtocol.__init__(self)
		# need to move some (all?) of these handlers into the parent class, or a mixin, should probably evict the 
		# modehash/levelhash too
		self.handlers = {
			"player.onJoin":          self.player_onJoin,
			"player.onLeave":         self.player_onLeave,
			"player.onAuthenticated": self.player_onAuthenticated,
			"player.onChat":          self.player_onChat,
			"player.onTeamChange":    self.player_onTeamChange,
			"player.onSquadChange":   self.player_onSquadChange,
			"player.onKill":          self.player_onKill,
			"server.onLevelLoaded":   self.server_onLevelLoaded,
			"punkBuster.onMessage":   self.nullop,
			"player.onSpawn":         self.nullop,
			"version":                self.nullop,
			"serverInfo":             self.nullop,
			"listPlayers":            self.nullop,
			"server.onRoundOver":     self.nullop,
			"server.onRoundOverPlayers": self.nullop,
			"server.onRoundOverTeamScores": self.nullop,
			"login.hashed": self.nullop,
			"admin.say": self.nullop,
			"vars.preset": self.nullop,
		}
		self.seq = 1
		self.callbacks = {}
		self.server = Server(self)
Esempio n. 2
0
	def __init__(self):
		FBRconProtocol.__init__(self)
		self.handlers = {
			"player.onJoin":          self.player_onJoin,
			"player.onLeave":         self.player_onLeave,
			"player.onAuthenticated": self.player_onAuthenticated,
			"player.onChat":          self.player_onChat,
			"player.onTeamChange":    self.player_onTeamChange,
			"player.onSquadChange":   self.player_onSquadChange,
			"player.onKill":          self.nullop, # temporary
			"server.onLevelLoaded":   self.server_onLevelLoaded,
			"punkBuster.onMessage":   self.nullop,
			"player.onSpawn":         self.nullop,
			"version":                self.nullop,
			"serverInfo":             self.nullop,
			"listPlayers":            self.nullop,
			"server.onRoundOver":     self.nullop,
			"server.onRoundOverPlayers": self.nullop,
			"server.onRoundOverTeamScores": self.nullop,
		}
		self.seq = 1
		self.callbacks = {}
		self.server = Server(self)
Esempio n. 3
0
class ClientRconProtocol(FBRconProtocol):
	"""a unique instance of this spawns for each rcon connection. i think."""
	
	def __init__(self):
		FBRconProtocol.__init__(self)
		self.handlers = {
			"player.onJoin":          self.player_onJoin,
			"player.onLeave":         self.player_onLeave,
			"player.onAuthenticated": self.player_onAuthenticated,
			"player.onChat":          self.player_onChat,
			"player.onTeamChange":    self.player_onTeamChange,
			"player.onSquadChange":   self.player_onSquadChange,
			"player.onKill":          self.nullop, # temporary
			"server.onLevelLoaded":   self.server_onLevelLoaded,
			"punkBuster.onMessage":   self.nullop,
			"player.onSpawn":         self.nullop,
			"version":                self.nullop,
			"serverInfo":             self.nullop,
			"listPlayers":            self.nullop,
			"server.onRoundOver":     self.nullop,
			"server.onRoundOverPlayers": self.nullop,
			"server.onRoundOverTeamScores": self.nullop,
		}
		self.seq = 1
		self.callbacks = {}
		self.server = Server(self)
	
	### "OK" "Kentucky Fried Server" "64" "64" "ConquestLarge0" "XP1_001" "0" "2" "2" "60.563736" "109.1357" "0" "" "true" "true" "false" "6972" "781" "" "" "" "NAm" "iad" "US"
	@defer.inlineCallbacks
	def serverInfo(self):
		sinfo = yield self.sendRequest(["serverInfo"])
		retval = {
			'serverName': sinfo[1],
			'curPlayers': int(sinfo[2]),
			'maxPlayers': int(sinfo[3]),
			'mode': modehash[sinfo[4]],
			'level': levelhash[sinfo[5]],
			'roundsPlayed': int(sinfo[6]) + 1,
			'roundsTotal': int(sinfo[7]),
		}
		defer.returnValue(retval)
	
	def nullop(self, packet):
		pass

	### IsFromClient,  Response,  Sequence: 2  Words: "OK" "7" "name" "guid" "teamId" "squadId" "kills" "deaths" "score" "0" 
	@defer.inlineCallbacks
	def admin_listPlayers(self):
		players = yield self.sendRequest(["admin.listPlayers", "all"])
		retval = {}
		fields = []
		status = players.pop(0)
		numparams = int(players.pop(0)) 
		for i in range(numparams):
			fields.append(players.pop(0))
		numplayers = int(players.pop(0))
		for i in range(numplayers):
			tmp = {}
			for val in fields:
				tmp[val] = players.pop(0)
			retval[tmp['name']] = tmp
		# print "listPlayers:",retval
		defer.returnValue(retval)
	
	@defer.inlineCallbacks
	def admin_listOnePlayer(self, player):
		players = yield self.sendRequest(["admin.listPlayers", "player", player])
		retval = None
		fields = []
		status = players.pop(0)
		numparams = int(players.pop(0)) 
		for i in range(numparams):
			fields.append(players.pop(0))
		numplayers = int(players.pop(0))
		tmp = {}
		for val in fields:
			tmp[val] = players.pop(0)
		retval = tmp
		defer.returnValue(retval)

	
	@defer.inlineCallbacks
	def admin_kickPlayer(self, player, reason):
		retval = yield self.sendRequest(["admin.kickPlayer", player, reason])

	@defer.inlineCallbacks
	def admin_killPlayer(self, player):
		retval = yield self.sendRequest(["admin.killPlayer", player])
	
	@defer.inlineCallbacks
	def admin_say(self, message, players):
		retval = yield self.sendRequest(["admin.say", message, players])
	
	### Unhandled event: IsFromServer, Request, Sequence: 132, Words: "server.onLevelLoaded" "MP_007" "ConquestLarge0" "0" "2"
	def server_onLevelLoaded(self, packet): 
		params = {
		'level':    levelhash[packet.words[1]],
		'mode':     modehash[packet.words[2]],
		'curRound': int(packet.words[3]) + 1,
		'maxRound': int(packet.words[4]),
		}
		self.postMessage("server.onLevelLoaded", params)

	@defer.inlineCallbacks
	def player_onJoin(self, packet):
		normal = str(packet.words[1]).lower()
		isgoon = yield self.mongo.bf3names.count({'bf3name': normal})
		self.postMessage("player.onJoin", {'player': packet.words[1], 'guid': packet.words[2], 'isgoon': isgoon != 0})

	def player_onAuthenticated(self, packet):
		self.postMessage("player.onAuthenticated", {'player': packet.words[1]})
		
	def player_onLeave(self, packet):
		self.postMessage("player.onLeave", {'player': packet.words[1]})
	
	def player_onChat(self, packet):
		self.postMessage("player.onChat", {'player': packet.words[1], 'message': packet.words[2]})
	
	# "player.onTeamChange" "toomuchmoney678" "2" "0"
	def player_onTeamChange(self, packet):
		pass
	
	# "player.onSquadChange" "toomuchmoney678" "2" "3"
	def player_onSquadChange(self, packet):
		pass
		
	@defer.inlineCallbacks
	def connectionMade(self):
		self.params = self.factory.params
		self.mongo  = self.factory.rm.mongo
		FBRconProtocol.connectionMade(self)
		ver   = yield self.sendRequest(["version"])
		salt  = yield self.sendRequest(["login.hashed"])
		m = hashlib.md5()
		m.update(salt[1].decode("hex"))
		m.update(self.factory.params["secret"])
		login = yield self.sendRequest(["login.hashed", m.digest().encode("hex").upper()])
		event = yield self.sendRequest(["admin.eventsEnabled", "true"])
		players = yield self.admin_listPlayers()
		for player in players:
			pl = players[player]
			ph = self.server.addPlayer(pl['name'], pl['guid'])
		self.postMessage("status", "connectionMade")
	
	def postMessage(self, facility, message):
		self.factory.rm.postMessage("servers.%s.%s" % (self.params["tag"], facility), message)
	
	def connectionLost(self, reason):
		self.postMessage("status", "connectionLost")
		FBRconProtocol.connectionLost(self, reason)
	
	def sendRequest(self, strings):
		"""sends something to the other end, returns a Deferred"""
		### TODO: this needs to add items to a cache so we can fire the deferred later
		###       we should probably also track command rtt
		cb = Deferred()
		seq = self.peekSeq()
		self.callbacks[seq] = cb
		self.transport.write(self.EncodeClientRequest(strings))
		return cb
	
	def gotResponse(self, packet):
		"""handles incoming response packets"""
		if packet.sequence in self.callbacks:
			self.callbacks[packet.sequence].callback(packet.words)
			del self.callbacks[packet.sequence]
		else:
			print "gotResponse WITHOUT callback"
	
	def sendResponse(self, pkt, words=["OK"]):
		"""called by gotRequest to send a response"""
		self.transport.write(self.EncodeServerResponse(pkt.sequence, words))
	
	def gotRequest(self, packet):
		"""handles incoming request packets
		   in client mode, these are events
		"""
		handler = None
		command = packet.words[0]
		if command in self.handlers:
			handler = self.handlers[command]
			try:
				handler(packet)
			except Exception, E:
				print "Caught Exception in gotRequest:",E
		else:
Esempio n. 4
0
class ClientRconProtocol(FBRconProtocol):
	"""a unique instance of this spawns for each rcon connection. i think."""
	
	def __init__(self):
		FBRconProtocol.__init__(self)
		# need to move some (all?) of these handlers into the parent class, or a mixin, should probably evict the 
		# modehash/levelhash too
		self.handlers = {
			"player.onJoin":          self.player_onJoin,
			"player.onLeave":         self.player_onLeave,
			"player.onAuthenticated": self.player_onAuthenticated,
			"player.onChat":          self.player_onChat,
			"player.onTeamChange":    self.player_onTeamChange,
			"player.onSquadChange":   self.player_onSquadChange,
			"player.onKill":          self.player_onKill,
			"server.onLevelLoaded":   self.server_onLevelLoaded,
			"punkBuster.onMessage":   self.nullop,
			"player.onSpawn":         self.nullop,
			"version":                self.nullop,
			"serverInfo":             self.nullop,
			"listPlayers":            self.nullop,
			"server.onRoundOver":     self.nullop,
			"server.onRoundOverPlayers": self.nullop,
			"server.onRoundOverTeamScores": self.nullop,
			"login.hashed": self.nullop,
			"admin.say": self.nullop,
			"vars.preset": self.nullop,
		}
		self.seq = 1
		self.callbacks = {}
		self.server = Server(self)
	
	### OK <serverName: string> <current playercount: integer> <effective max playercount: integer> <current gamemode: string> 
	### <current map: string> <roundsPlayed: integer> <roundsTotal: string> <scores: team scores> <onlineState: online state> 
	### <ranked: boolean> <punkBuster: boolean> <hasGamePassword: boolean> <serverUpTime: seconds> <roundTime: seconds> 
	### <gameIpAndPort: IpPortPair> <punkBusterVersion: string> <joinQueueEnabled: boolean> <region: string> 
	### <closestPingSite: string> <country: string> <matchMakingEnabled: boolean> <blazePlayerCount: integer> 
	### <blazeGameState: string> 
	@defer.inlineCallbacks
	def serverInfo(self):
		sinfo = yield self.sendRequest(["serverInfo"])
		deflevel = { 'name': sinfo[5], 'factions': ['T1', 'T2'] }
		retval = {
			'serverName': sinfo[1],
			'curPlayers': int(sinfo[2]),
			'maxPlayers': int(sinfo[3]),
			'mode': modehash[sinfo[4]],
			'level': levelhash.get(sinfo[5], deflevel)['name'],
			'roundsPlayed': int(sinfo[6]) + 1,
			'roundsTotal': int(sinfo[7]),
			'numTeamScores': int(sinfo[8]),
		}
		# process team scores

		if retval['numTeamScores'] == 2:
			retval['teams'] = [
				{ 'faction': levelhash.get(sinfo[5], deflevel)['factions'][0], 'score': int(floor(float(sinfo[9])))},
				{ 'faction': levelhash.get(sinfo[5], deflevel)['factions'][1], 'score': int(floor(float(sinfo[10])))},
			]
		else:
			retval['teams'] = []

		off = 9 + retval['numTeamScores'] # 9 = offset + 1 to get us past the teamScores
		retval.update({
			'targetScore':       int(sinfo[off+0]),
			'onlineState':       sinfo[off+1],
			'ranked':            sinfo[off+2] == 'true',
			'punkBuster':        sinfo[off+3] == 'true',
			'hasGamePassword':   sinfo[off+4] == 'true',
			'serverUpTime':      int(sinfo[off+5]),
			'roundTime':         int(sinfo[off+6]),
			'gameIpAndPort' :    sinfo[off+7],
			'punkBusterVersion': sinfo[off+8],
			'joinQueueEnabled':  sinfo[off+9] == 'true',
			'region':            sinfo[off+10],
			'closestPingSite':   sinfo[off+11],
			'country':           sinfo[off+12],
			# 'matchMakingEnabled' # not enabled yet?
			'blazePlayerCount':  int(sinfo[off+13]),
			'blazeGameState':    sinfo[off+14],
		})
		defer.returnValue(retval)
	
	def nullop(self, packet):
		pass

	### IsFromClient,  Response,  Sequence: 2  Words: "OK" "7" "name" "guid" "teamId" "squadId" "kills" "deaths" "score" "0" 
	@defer.inlineCallbacks
	def admin_listPlayers(self):
		players = yield self.sendRequest(["admin.listPlayers", "all"])
		retval = {}
		fields = []
		status = players.pop(0)
		numparams = int(players.pop(0)) 
		for i in range(numparams):
			fields.append(players.pop(0))
		numplayers = int(players.pop(0))
		for i in range(numplayers):
			tmp = {}
			for val in fields:
				tmp[val] = players.pop(0)
			retval[tmp['name']] = tmp
		# print "listPlayers:",retval
		defer.returnValue(retval)
	
	@defer.inlineCallbacks
	def admin_listOnePlayer(self, player):
		players = yield self.sendRequest(["admin.listPlayers", "player", player])
		retval = None
		fields = []
		status = players.pop(0)
		numparams = int(players.pop(0)) 
		for i in range(numparams):
			fields.append(players.pop(0))
		numplayers = int(players.pop(0))
		tmp = {}
		for val in fields:
			tmp[val] = players.pop(0)
		retval = tmp
		defer.returnValue(retval)

	@defer.inlineCallbacks
	def admin_kickPlayer(self, player, reason):
		retval = yield self.sendRequest(["admin.kickPlayer", player, reason])

	@defer.inlineCallbacks
	def admin_killPlayer(self, player):
		retval = yield self.sendRequest(["admin.killPlayer", player])
	
	@defer.inlineCallbacks
	def admin_say(self, message, players):
		retval = yield self.sendRequest(["admin.say", message, players])
	
	### Unhandled event: IsFromServer, Request, Sequence: 132, Words: "server.onLevelLoaded" "MP_007" "ConquestLarge0" "0" "2"
	def server_onLevelLoaded(self, packet): 
		params = {
		'level':    levelhash.get(packet.words[1], {name: packet.words[1]})['name'],
		'mode':     modehash[packet.words[2]],
		'curRound': int(packet.words[3]) + 1,
		'maxRound': int(packet.words[4]),
		}
		self.postMessage("server.onLevelLoaded", params)

	# todo: refactor mongo to use upsert?
	@defer.inlineCallbacks
	def player_onJoin(self, packet):
		_now = datetime.now()
		# try to find existing bf3name/eaguid
		normal = str(packet.words[1]).lower()
		bf3name = yield self.mongo.bf3names.find_one({'bf3name': normal}) # a mongo document, or {} on no match
		eaguid = yield self.mongo.eaguids.find_one({'eaguid': packet.words[2]}) # mongo document, or {} on no match
		# create eaguid/bf3name if none exist
		if eaguid == {}:
			retval = yield self.mongo.eaguids.insert({'eaguid': packet.words[2], 'seen': None})
			eaguid = yield self.mongo.eaguids.find_one({'eaguid': packet.words[2]})
		if bf3name == {}:
			retval = yield self.mongo.bf3names.insert({'bf3name': normal, 'safname': None, 'bf3state': 0, 
				'eaguid': None, 'seen': None})
			bf3name = yield self.mongo.bf3names.find_one({'bf3name': normal})

		# update last seen timestamps, and the eaguid
		bf3name['eaguid'] = DBRef(self.mongo.eaguids, eaguid['_id'])
		bf3name['seen'] = _now
		eaguid['seen'] = _now
		retval = yield self.mongo.bf3names.save(bf3name)
		retval = yield self.mongo.eaguids.save(eaguid)

		self.postMessage("player.onJoin", {'player': packet.words[1], 'guid': packet.words[2], 'isgoon': bf3name['bf3state'] != 0})

	def player_onAuthenticated(self, packet):
		self.postMessage("player.onAuthenticated", {'player': packet.words[1]})
		
	def player_onLeave(self, packet):
		self.postMessage("player.onLeave", {'player': packet.words[1]})
	
	# "player.onKill" "tanketernal" "-nrr-" "Death" "true" 
	@defer.inlineCallbacks
	def player_onKill(self, packet):
		retval = yield self.elasticLog('onkill',  {
			'player': packet.words[1].lower(),
			'target': packet.words[2].lower(),
			'weapon': packet.words[3],
			'headshot': packet.words[4] == 'true',
			})

	# "player.onChat" "Server" "Welcome to KFS Trever9191." "player" "Trever9191" 
	@defer.inlineCallbacks
	def player_onChat(self, packet):
		self.postMessage("player.onChat", {'player': packet.words[1], 'message': packet.words[2]})
		if packet.words[1] == 'Server':
			defer.succeed(None)
			return
		retval = yield self.elasticLog('onchat', {
			'player':  packet.words[1].lower(),
			'message': packet.words[2],
			'target':  '/'.join(packet.words[3:]).lower(),
			})
	
	# "player.onTeamChange" "toomuchmoney678" "2" "0"
	def player_onTeamChange(self, packet):
		pass
	
	# "player.onSquadChange" "toomuchmoney678" "2" "3"
	def player_onSquadChange(self, packet):
		pass
	
	@defer.inlineCallbacks
	def elasticLog(self, doctype, doc):
		utcnow = datetime.utcnow()
		url = utcnow.strftime('http://localhost:9200/watbf3-%Y%m%d/') + doctype + '/'
		doc['timestamp'] = utcnow.isoformat() + 'Z'
		retval = yield fetch(url, postdata=dumps(doc))
		defer.returnValue(retval)
		
	@defer.inlineCallbacks
	def connectionMade(self):
		self.params = self.factory.params
		self.mongo  = self.factory.rm.mongo
		FBRconProtocol.connectionMade(self)
		ver   = yield self.sendRequest(["version"])
		salt  = yield self.sendRequest(["login.hashed"])
		m = hashlib.md5()
		m.update(salt[1].decode("hex"))
		m.update(self.factory.params["secret"])
		login = yield self.sendRequest(["login.hashed", m.digest().encode("hex").upper()])
		event = yield self.sendRequest(["admin.eventsEnabled", "true"])
		players = yield self.admin_listPlayers()
		for player in players:
			pl = players[player]
			ph = self.server.addPlayer(pl['name'], pl['guid'])
		self.postMessage("status", "connectionMade")
		self.factory.resetDelay()
	
	def postMessage(self, facility, message):
		self.factory.rm.postMessage("servers.%s.%s" % (self.params["tag"], facility), message)
	
	def connectionLost(self, reason):
		self.postMessage("status", "connectionLost")
		FBRconProtocol.connectionLost(self, reason)
	
	def sendRequest(self, strings):
		"""sends something to the other end, returns a Deferred"""
		### TODO: this needs to add items to a cache so we can fire the deferred later
		###       we should probably also track command rtt
		cb = Deferred()
		seq = self.peekSeq()
		self.callbacks[seq] = cb
		self.transport.write(self.EncodeClientRequest(strings))
		return cb
	
	def gotResponse(self, packet):
		"""handles incoming response packets"""
		if packet.sequence in self.callbacks:
			self.callbacks[packet.sequence].callback(packet.words)
			del self.callbacks[packet.sequence]
		else:
			print "gotResponse WITHOUT callback"
	
	def sendResponse(self, pkt, words=["OK"]):
		"""called by gotRequest to send a response"""
		self.transport.write(self.EncodeServerResponse(pkt.sequence, words))
	
	def gotRequest(self, packet):
		"""handles incoming request packets
		   in client mode, these are events
		"""
		handler = None
		command = packet.words[0]
		if command in self.handlers:
			handler = self.handlers[command]
			try:
				handler(packet)
			except Exception, E:
				print "Caught Exception in gotRequest:",E
		else: