155 lines
4.1 KiB
Python
155 lines
4.1 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 = {}
|
|
coords = [Position(coor[0], coor[1]) for coor in coords]
|
|
|
|
with self.pool as pool:
|
|
pool.load_list(coords)
|
|
|
|
for pos in coords:
|
|
chunk = pool.get(pos)
|
|
diff = chunk.as_diff()
|
|
diffs[pos] = 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 pos, diff in diffs.items():
|
|
if diff.legitimate():
|
|
legitimate_diffs[pos] = diff
|
|
else:
|
|
illegitimate_diffs[pos] = diff
|
|
|
|
if legitimate_diffs:
|
|
with self.pool as pool:
|
|
pool.load_list(legitimate_diffs.keys())
|
|
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):
|
|
with self.pool as pool:
|
|
pool.load_list(diffs.keys())
|
|
|
|
reverse_diffs = {}
|
|
for pos, diff in diffs.items():
|
|
chunk = pool.get(pos)
|
|
reverse_diff = diff.diff(chunk.as_diff())
|
|
reverse_diffs[pos] = reverse_diff
|
|
|
|
return reverse_diffs
|
|
|
|
def send_changes(self, diffs):
|
|
diffs = {pos: diff for pos, diff in diffs.items() if pos 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]}")
|
|
print("{} {}".format(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(" {} dbfile [port]".format(argv[0]))
|
|
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("Cleaning up empty chunks from db.")
|
|
WotServer.pool.remove_empty()
|
|
print("Stopped.")
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv)
|