Skip to content

Commit 1a16790

Browse files
Add auto update from server
1 parent bd435e7 commit 1a16790

File tree

6 files changed

+138
-12
lines changed

6 files changed

+138
-12
lines changed

lelonmo/persist_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
save_file = input("Please enter the location of your save file : ")
1717

1818
default_data = dict(
19-
version="00.4.8",
19+
version="00.4.9",
2020
update_url='https://github.com/claj-ndc/LeLonMo/releases/latest',
2121
online=dict(
2222
uuid=str(uuid.uuid4()),

lelonmo/socket_client.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from lelonmo.main_offline import human_to_bool
1313

1414
PORT = 11111
15+
BUFFER_SIZE = 4096
1516

1617

1718
def _send_data(data: str, host: str):
@@ -31,7 +32,7 @@ def _send_data(data: str, host: str):
3132
)
3233
)
3334
# UUID is never shared with other players
34-
v = s.recv(1024)
35+
v = s.recv(BUFFER_SIZE)
3536
s.close()
3637
return v
3738
except ConnectionRefusedError:
@@ -78,10 +79,14 @@ def _join_game(wb, ip="localhost"): # Initiate the connexion between client and
7879
webbrowser.open(persist_data.DATA["update_url"])
7980
exit_server()
8081
elif player_id == b"outdated%update":
81-
wb.add("Your client is outdated and automatic update install is not available")
82-
import webbrowser
83-
webbrowser.open(persist_data.DATA["update_url"])
82+
wb.add(f"You are about to receive an update from {ip}.")
83+
if human_to_bool("Do you trust this server ?\n"):
84+
import lelonmo.updater as updater
85+
updater.auto_update(ip, wb)
86+
else:
87+
wb.add("Aborted update, you cannot play on this server. ")
8488
exit_server()
89+
8590
else:
8691
try:
8792
int(player_id)
@@ -274,6 +279,7 @@ def exit_server():
274279
pass
275280
finally:
276281
s.close()
282+
sys.exit()
277283

278284

279285
if __name__ == "__main__":

lelonmo/updater.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import socket
2+
from zipfile import ZipFile
3+
import os, sys, imp
4+
from lelonmo import persist_data
5+
6+
BUFFER_SIZE = 4096
7+
SERVER_PORT = 11111
8+
9+
def _send_data(data: str, host: str):
10+
socket.timeout = 2
11+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
12+
try:
13+
s.connect((host, SERVER_PORT))
14+
s.send(
15+
bytearray(
16+
"%llm_client%" \
17+
f"{persist_data.DATA['version'].replace('.', str())}%" \
18+
f"{persist_data.DATA['online']['uuid']}%" \
19+
f"{data}",
20+
"utf-8"
21+
)
22+
)
23+
v = s.recv(BUFFER_SIZE)
24+
s.close()
25+
return v
26+
except ConnectionRefusedError:
27+
print("Server error : Connexion refused")
28+
s.close()
29+
exit()
30+
except Exception as e:
31+
s.close()
32+
print("Server error :", e)
33+
exit(0)
34+
35+
36+
def auto_update(ip, wb):
37+
size = int(_send_data("size%", ip))
38+
wb.add("The update is available")
39+
tmp_file = open("tmp_update.zip", "wb")
40+
s = socket.socket()
41+
s.connect((ip, SERVER_PORT))
42+
s.send(bytearray(f"%llm_client%{persist_data.DATA['version'].replace('.', str())}%{persist_data.DATA['online']['uuid']}%latest_file%","utf-8"))
43+
data = b'1'
44+
wb.add("Downloading ...")
45+
while data:
46+
data = s.recv(BUFFER_SIZE)
47+
if not data:
48+
break
49+
# write data to a file
50+
tmp_file.write(data)
51+
tmp_file.close()
52+
wb.add("Done")
53+
ziph = ZipFile('tmp_update.zip', 'r')
54+
wb.add("Extracting update ...")
55+
for file in ziph.namelist():
56+
ziph.extract(file, os.path.realpath(os.path.join(__file__, f"..{os.path.sep}..")))
57+
wb.add("Update successful")
58+
exit(0)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import os, sys
2+
import zipfile
3+
4+
PACKAGE_PARENT = '..'
5+
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
6+
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))
7+
from lelonmo.persist_data import DATA
8+
9+
10+
def zipdir(path, zip_handle):
11+
for root, dirs, files in os.walk(path):
12+
for file in files:
13+
if not "__pycache__" in file:
14+
zip_handle.write(
15+
os.path.join(root, file),
16+
os.path.relpath(
17+
os.path.join(root, file),
18+
os.path.join(path, '..')
19+
)
20+
)
21+
22+
23+
if __name__ == '__main__':
24+
version = DATA["version"].replace(".", "")
25+
zipf = zipfile.ZipFile(
26+
f'server{os.path.sep}LeLonMo_client_v{version}.zip', 'w', zipfile.ZIP_DEFLATED)
27+
zipdir(f'lelonmo', zipf)
28+
zipf.write(f"main.py", "main.py")
29+
zipf.close()

server/persist_data.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
save_file = home + ".lelonmo_server_save.json"
88

99
default_data = dict(
10-
version="0.4.8",
11-
client_version="0048",
10+
version="0.4.9",
11+
client_version="0049",
1212
online=dict(
1313
uuid=str(uuid.uuid4()),
1414
name="",

server/socket_server.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
import re
44
import threading
55
import socket
6+
import os
67

78
from server import letter_generator, persist_data
89
from server import word_check
910

10-
11+
BUFFER_SIZE = 4096
1112
class Game():
1213
def __init__(self, LANGUAGE, MAX_PLAYERS = 10):
1314
self.state = 0
1415
print("[I] Waiting for admin ...")
1516
self.game_data = dict(players=list())
1617
self.LANGUAGE = LANGUAGE
1718
self.MAX_PLAYERS = MAX_PLAYERS
19+
self.update_file = f'server{os.path.sep}LeLonMo_client_v{persist_data.DATA["client_version"]}.zip'
1820

1921
def _new_player(self, uuid, name, ip, status="Connected"):
2022
if name in [i['name'] for i in self.game_data["players"]]:
@@ -49,6 +51,7 @@ def _delete_player(self, player_id: int, admin: bool):
4951

5052
def _answer(self, msg, socket):
5153
socket.send(bytearray(str(msg), "utf-8"))
54+
socket.close()
5255

5356
def _get_player_id(self, uuid):
5457
for i, j in enumerate(self.game_data["players"]):
@@ -96,13 +99,21 @@ def handle_data(self, data: str, client_socket, client_thread):
9699
except:
97100
print("[W] Invalid request :", data)
98101
return data, client_socket, client_socket
102+
103+
# Allow updates
99104
try:
100-
if int(version) < int(persist_data.DATA["client_version"]):
101-
self._answer("outdated%", client_socket)
102-
return
105+
if not msg in ['size%', 'latest_file%']:
106+
if int(version) < int(persist_data.DATA["client_version"]) and os.path.exists(self.update_file):
107+
self._answer("outdated%update", client_socket)
108+
return
109+
elif int(version) < int(persist_data.DATA["client_version"]):
110+
self._answer("outdated%", client_socket)
111+
return
103112
except:
104113
self._answer("outdated%", client_socket)
105114
return
115+
116+
106117
try:
107118
admin = uuid == self.game_data["admin"]["uuid"]
108119
except KeyError:
@@ -118,6 +129,28 @@ def handle_data(self, data: str, client_socket, client_thread):
118129
self._answer("Nobody", client_socket)
119130
elif msg == "leave%":
120131
self._delete_player(self._get_player_id(uuid), admin)
132+
133+
# Update sending part
134+
elif msg == "latest_file%":
135+
try:
136+
print("[I] Uploading update")
137+
f = open(self.update_file,'rb')
138+
l = f.read(BUFFER_SIZE)
139+
while (l):
140+
client_socket.send(l)
141+
l = f.read(BUFFER_SIZE)
142+
f.close()
143+
client_socket.close()
144+
print("[I] Update done")
145+
except Exception as e:
146+
print("[E] Error while sending update :", e)
147+
elif msg == "size%":
148+
try:
149+
f = open(self.update_file,'rb')
150+
self._answer(len(f.read()), client_socket)
151+
f.close()
152+
except Exception as e:
153+
print("[E] Error while calculating update :", e)
121154
elif self.state == 0 and msg.startswith("join%"):
122155
self.state = 1
123156
self.game_data["admin"] = dict(
@@ -193,7 +226,7 @@ def __init__(self, ip, port, clientsocket, game):
193226
self.clientsocket = clientsocket
194227

195228
def run(self):
196-
data = self.clientsocket.recv(1024).decode("utf-8")
229+
data = self.clientsocket.recv(BUFFER_SIZE).decode("utf-8")
197230
if data.startswith("%llm_client%"):
198231
self.game.handle_data(data, self.clientsocket, self)
199232
else:

0 commit comments

Comments
 (0)