SLBRV2/server.py

146 lines
6.0 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import docker
import ipaddress
from twisted.protocols.basic import LineReceiver
from twisted.internet.protocol import Factory, Protocol
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet import reactor
class SLBRManager(Protocol):
def __init__(self, config):
self.client_addr = None
self.config = config
def suicide(self):
slbr_containers = self.config['docker_client'].containers.list(
filters = {'label': 'description=SLBR User Container'}
)
for container in slbr_containers:
if container.attrs['NetworkSettings']['Networks']['slbr']['IPAddress'] == self.client_addr:
container.remove(force=True)
def connectionMade(self):
self.client_addr = self.transport.getPeer().host
if (
ipaddress.ip_address(self.client_addr)
not in
ipaddress.ip_network(self.config['docker_netmask'])
):
print('Dropping client {} not in docker network'.format(self.client_addr))
self.transport.loseConnection()
def dataReceived(self, data):
message = data.decode('utf8').split(' ')
command = message[0].replace('\n', '')
if len(message) > 1:
args = message[1:]
if command == 'LOG':
entry = '[{}]: {}'.format(self.client_addr, ' '.join(args))
print(entry)
elif command == 'DEAD':
print('Killing {}'.format(self.client_addr))
self.suicide()
self.transport.loseConnection()
elif command == 'SCORE':
message = 'PLAYER | CHALLENGES COMPLETED\n' + ('-' * 30) + '\n'
slbr_containers = self.config['docker_client'].containers.list(
filters = {'label': 'description=SLBR User Container'}
)
for player_addr in os.listdir('./scores'):
player_name = 'err'
for container in slbr_containers:
if container.attrs['NetworkSettings']['Networks']['slbr']['IPAddress'] == player_addr:
player_name = container.attrs['Config']['Image'].replace('slbr:', '')
break
message += player_name + ': '
with open('./scores/{}'.format(player_addr)) as score_file:
completed_challenges = ', '.join(score_file.readlines()).replace('\n', '')
message += completed_challenges + '\n'
self.transport.write(bytes(message, 'utf8'))
self.transport.loseConnection()
elif command == 'SUBMIT' and len(args) == 2:
try:
challenge_num = int(args[0])
except ValueError:
self.transport.loseConnection()
return
submitted_solution = args[1].replace('\n', '')
with open(self.config['solutions_file']) as solutions_file:
correct_solutions = solutions_file.readlines()
correct_solutions = list(map(lambda x: x.replace('\n', ''), correct_solutions))
num_solutions = len(correct_solutions)
print(
'{} submitted \"{}\" as solution for challenge {}'.format(
self.client_addr,
submitted_solution,
challenge_num
)
)
game_ended = False
if challenge_num <= num_solutions:
print('(Correct answer is {})'.format(correct_solutions[challenge_num -1]))
if correct_solutions[challenge_num -1] == submitted_solution:
message = 'w00t! You got the right answer!!!'
with open(
'{}/{}'.format(
self.config['scores_folder'],
self.client_addr
), 'a+'
) as score_file:
score_file.seek(0)
completed_challenges = score_file.readlines()
completed_challenges = list(
map(lambda x: x.replace('\n', ''), completed_challenges)
)
if str(challenge_num) in completed_challenges:
message = 'You already submitted the correct answer for that challenge!'
else:
score_file.write(str(challenge_num) + '\n')
if len(completed_challenges) + 1 == num_solutions:
message = (
'w00t! You got the right answer!!!\n'
+ 'Hey! thats all {}! that means YOU WIN!\n'.format(num_solutions)
+ '!!!!!!!CONGRATULATIONS!!!!!!!\n'
+ 'THIS CONTAINER WILL NOW SELF DESTRUCT'
)
game_ended = True
else:
message = '|X_x| answer was rejected!!!.'
else:
message = ('What? You tried to submit a solution for challenge '
+ '{} but there are only {} challenges!'.format(
challenge_num,
num_solutions
))
print(message.replace('You', 'User'))
self.transport.write(bytes(message + '\n', 'utf8'))
self.transport.loseConnection()
if game_ended:
self.suicide()
class SLBRManagerFactory(Factory):
def __init__(self, config):
self.config = config
def buildProtocol(self, addr):
return SLBRManager(self.config)
docker_client = docker.from_env()
endpoint = TCP4ServerEndpoint(reactor, 1337)
endpoint.listen(SLBRManagerFactory({
'docker_client': docker_client,
'docker_netmask': '172.19.0.0/16',
'scores_folder': './scores',
'solutions_file': './solutions.txt',
'log_file': './log.txt'
}))
reactor.run()