-
Notifications
You must be signed in to change notification settings - Fork 0
/
verifier.py
157 lines (136 loc) · 5.13 KB
/
verifier.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import tkinter as tk
from tkinter import messagebox
import io
import threading
from PIL import Image, ImageTk
MAX_INIT_SIZE = 10
USAGE = """USAGE: Enter = Accept
USAGE: Escape = Decline
INFO: If you decline once the program will be stopped
INFO: The image will be saved only if both parties accept at all stages"""
class Verifier(tk.Frame):
def __init__(self, master, conn, role, images):
super().__init__(master)
self.master = master
self.conn = conn
self.role = role
self.images = images
self.stage = 0
self.stages = len(images)
self.stages_other = 0
self.successful = False
self.paniced = False
self.busy = False
self.forcequit = False
self.image_gui = ImageTk.PhotoImage(self.images[self.stage])
self.active = tk.Label(self, image=self.image_gui)
self.active.pack()
self.thread = threading.Thread(target=self.init2)
self.thread.start()
def init2(self):
print("STATUS: Waiting for partner to finish editing...")
print("INFO: The program might become unresponsive for a while")
try:
self.stages_other = int(self.exchange_text(str(self.stages)))
self.image = self.exchange_image(self.images[self.stage])
except:
self.panic()
return
self.image_gui = ImageTk.PhotoImage(self.image)
self.active["image"] = self.image_gui
if self.stages < self.stages_other:
for _ in range(self.stages_other - self.stages):
self.images.insert(-2, self.images[-2])
self.bind("<Return>", lambda _: self.start("ACCEPT"))
self.bind("<Escape>", lambda _: self.start("DECLINE"))
self.focus_force()
print(USAGE)
def start(self, arg):
if self.busy: return
self.busy = True
self.thread = threading.Thread(target=self.verify, args=(arg,))
self.thread.start()
def verify(self, msg_send):
print(f"STATUS: Stage {self.stage + 1} -> {msg_send}")
try: msg_recv = self.exchange_text(msg_send)
except:
self.panic()
return
if msg_send == "ACCEPT" and msg_recv == "ACCEPT":
self.stage += 1
else:
if msg_recv == "DECLINE":
messagebox.showinfo("Info", "Your image was declined")
print("STATUS: Image was declined")
print("STATUS: Operation aborted")
self.master.quit()
if self.stage == len(self.images):
print("STATUS: Operation successful")
self.successful = True
self.master.quit()
else:
try: self.image = self.exchange_image(self.images[self.stage])
except:
self.panic()
return
self.image_gui = ImageTk.PhotoImage(self.image)
self.active["image"] = self.image_gui
if self.stages_other - 1 <= self.stage < self.stages - 1:
self.verify("ACCEPT")
else:
self.busy = False
def exchange_text(self, msg_send):
msg_recv = self.exchange(msg_send.encode())
return msg_recv.decode()
def exchange_image(self, img_send):
fd = io.BytesIO()
img_send.save(fd, "png")
img_recv = self.exchange(fd.getvalue())
if self.stage != 0: self.image.close()
fd.close()
return Image.open(io.BytesIO(img_recv))
def exchange(self, to_send):
size_send = str(len(to_send))
size_send = "0" * (MAX_INIT_SIZE - len(size_send)) + size_send
if self.role == "client":
self.conn.sendall(size_send.encode())
size_recv = int(self.recvall(MAX_INIT_SIZE).decode())
self.conn.sendall(to_send)
return self.recvall(size_recv)
elif self.role == "server":
size_recv = int(self.recvall(MAX_INIT_SIZE).decode())
self.conn.sendall(size_send.encode())
received = self.recvall(size_recv)
self.conn.sendall(to_send)
return received
def recvall(self, size):
msg = bytes()
while len(msg) < size:
recv = self.conn.recv(size - len(msg))
if not recv: raise IOError
msg += recv
return msg
def ask_resume(self):
print("STATUS: Waiting for partner to make up his mind...")
print("INFO: The program might become unresponsive for a while")
try: other = self.exchange_text("RESUME")
except: return False
return other == "RESUME"
def panic(self):
if not self.forcequit:
print("ERROR: Connection lost")
print("STATUS: Operation aborted")
self.paniced = True
messagebox.showerror("Error", "Connection lost")
self.master.quit()
def cleanup(self):
self.forcequit = True
for stage in range(self.stages):
self.images[stage].close()
self.conn.close()
def has_paniced(self):
return self.paniced
def is_successful(self):
return self.successful
def get_results(self):
return self.image