wot/server.py
Joscha 9e5b5f874a Start work on server-side saving worlds
This commit includes a a few more changes because I'm too lazy to
clean them up:
 - fix chunk modification times
 - improve command line arguments
 - load multiple chunks at once
2017-04-16 13:52:39 +00:00

152 lines
3.9 KiB
Python

# import from chunks, dbchunkpool
import json
import sys
import threading
from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket
from utils import Position
from chunks import ChunkDiff, jsonify_diffs, dejsonify_diffs
from dbchunkpool import DBChunkPool
from chunks import ChunkPool
class WotServer(WebSocket):
def handle_request_chunks(self, coords):
diffs = []
with self.pool as pool:
coords = [Position(coor[0], coor[1]) for coor in coords]
pool.load_list(coords)
for pos in coords:
chunk = pool.get(pos)
diffs.append((pos, chunk.as_diff()))
self.loaded_chunks.add(pos)
ddiffs = jsonify_diffs(diffs)
message = {"type": "apply-changes", "data": ddiffs}
self.sendMessage(json.dumps(message))
def handle_unload_chunks(self, coords):
for coor in coords:
pos = Position(coor[0], coor[1])
if pos in self.loaded_chunks:
self.loaded_chunks.remove(pos)
def handle_save_changes(self, ddiffs):
diffs = dejsonify_diffs(ddiffs)
# check whether changes are correct (exclude certain characters)
# if not correct, send corrections them back to sender
legitimate_diffs = []
illegitimate_diffs = []
for dchunk in diffs:
if dchunk[1].legitimate():
legitimate_diffs.append(dchunk)
else:
illegitimate_diffs.append(dchunk)
if legitimate_diffs:
with self.pool as pool:
pool.apply_diffs(legitimate_diffs)
for client in self.clients:
if client:
client.send_changes(legitimate_diffs)
if illegitimate_diffs:
reverse_diffs = self.reverse_diffs(illegitimate_diffs)
reverse_ddiffs = jsonify_diffs(reverse_diffs)
message = {"type": "apply-changes", "data": reverse_ddiffs}
self.sendMessage(json.dumps(message))
def reverse_diffs(self, diffs):
coords = [dchunk[0] for dchunk in diffs]
with self.pool as pool:
pool.load_list(coords)
reverse_diffs = []
for dchunk in diffs:
pos = dchunk[0]
diff = dchunk[1]
chunk = pool.get(pos)
reverse_diff = diff.diff(chunk.as_diff())
reverse_diffs.append((pos, reverse_diff))
return reverse_diffs
def send_changes(self, diffs):
diffs = [dchunk for dchunk in diffs if dchunk[0] in self.loaded_chunks]
ddiffs = jsonify_diffs(diffs)
if ddiffs:
message = {"type": "apply-changes", "data": ddiffs}
self.sendMessage(json.dumps(message))
def handleMessage(self):
message = json.loads(self.data)
if message["type"] == "request-chunks":
self.handle_request_chunks(message["data"])
elif message["type"] == "unload-chunks":
self.handle_unload_chunks(message["data"])
elif message["type"] == "save-changes":
self.handle_save_changes(message["data"])
def handleConnected(self):
self.loaded_chunks = set()
try:
i = self.clients.index(None)
self.clients[i] = self
except ValueError:
self.clients.append(self)
i = len(self.clients) - 1
graphstr = "".join(["" if j == i else ("" if v else " ") for j, v in enumerate(self.clients)])
print(f"{graphstr} {self.address[0]}")
def handleClose(self):
i = self.clients.index(self)
graphstr = "".join(["" if j == i else ("" if v else " ") for j, v in enumerate(self.clients)])
print(graphstr)
#print(f"{graphstr} {self.address[0]}")
self.clients[i] = None
while self.clients and not self.clients[-1]:
self.clients.pop()
def main(argv):
if len(argv) == 1 or len(argv) > 3:
print("Usage:")
print(f" {argv[0]} dbfile [port]")
print(" default port: 8000")
return
dbfile = argv[1]
if len(argv) >= 3:
try:
port = int(argv[2])
except ValueError:
print("Invalid port")
return
else:
port = 8000
print("Connecting to db")
WotServer.pool = DBChunkPool(dbfile)
WotServer.clients = []
server = SimpleWebSocketServer('', port, WotServer)
try:
server.serveforever()
except KeyboardInterrupt:
print("")
print("Saving recent changes.")
WotServer.pool.save_changes()
print("Stopped.")
if __name__ == "__main__":
main(sys.argv)