aler-aler 3 years ago
parent
commit
695c644d80
2 changed files with 384 additions and 0 deletions
  1. 61 0
      server.py
  2. 323 0
      szablon_gui.py

+ 61 - 0
server.py

@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+
+import sys
+import socket
+import selectors
+import types
+
+sel = selectors.DefaultSelector()
+
+
+def accept_wrapper(sock):
+    conn, addr = sock.accept()  # Should be ready to read
+    print("accepted connection from", addr)
+    conn.setblocking(False)
+    data = types.SimpleNamespace(addr=addr, inb=b"", outb=b"")
+    events = selectors.EVENT_READ | selectors.EVENT_WRITE
+    sel.register(conn, events, data=data)
+
+
+def service_connection(key, mask):
+    sock = key.fileobj
+    data = key.data
+    if mask & selectors.EVENT_READ:
+        recv_data = sock.recv(1024)  # Should be ready to read
+        if recv_data:
+            data.outb += recv_data
+        else:
+            print("Closing connection to", data.addr)
+            sel.unregister(sock)
+            sock.close()
+    if mask & selectors.EVENT_WRITE:
+        if data.outb:
+            print("Echoing", repr(data.outb), "to", data.addr)
+            sent = sock.send(data.outb)  # Should be ready to write
+            data.outb = data.outb[sent:]
+
+
+if len(sys.argv) < 3:
+    print("Usage:", sys.argv[0], "<host> <port>")
+    sys.exit(1)
+
+host, port = sys.argv[1], int(sys.argv[2])
+lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+lsock.bind((host, port))
+lsock.listen()
+print("Listening on", (host, port))
+lsock.setblocking(False)
+sel.register(lsock, selectors.EVENT_READ, data=None)
+
+try:
+    while True:
+        events = sel.select(timeout=None)
+        for key, mask in events:
+            if key.data is None:
+                accept_wrapper(key.fileobj)
+            else:
+                service_connection(key, mask)
+except KeyboardInterrupt:
+    print("caught keyboard interrupt, exiting")
+finally:
+    sel.close()

+ 323 - 0
szablon_gui.py

@@ -0,0 +1,323 @@
+#!/usr/bin/env python3
+
+import configparser
+import sys
+import tkinter as tk
+import tkinter.messagebox
+from tkinter.constants import NSEW
+import threading
+import os
+import socket
+import selectors
+import json
+from functools import partial
+
+config_fname = "config.txt"
+
+sel = selectors.DefaultSelector()
+messages = [b"Message 1 from client.", b"Message 2 from client."]
+
+class Client(threading.Thread):
+    def __init__(self, host, port, username, gui):
+        super().__init__()
+        self.host = host
+        self.port = port
+        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.name = username
+        self.gui = gui
+        self.start()
+
+    def start(self):
+        self.sock.connect((self.host, self.port))
+        print('Connected to {}:{}'.format(self.host, self.port))
+
+        # Send the username as a welcome message
+        self.sock.sendall(self.name.encode('utf8'))
+        super().start()
+
+    def close(self):
+        try:
+            self.sock.close()
+        except:
+            pass
+
+    def send(self, message):
+        self.sock.sendall(message.encode('utf8'))
+
+    def vote(self, player):
+        self.sock.sendall(str(player).encode('utf8'))
+
+    def run(self):
+        try:
+            while True:
+                message = self.sock.recv(4096).decode('utf8')
+                if message:
+                    data = json.loads(message)
+                    if "playerid" in data:
+                        self.gui.player_id = int(data["playerid"])
+                    self.gui.server_data = data
+                    if data["state"] == "vote":
+                        self.gui.messages = []
+                        for key in data["messages"]:
+                            self.gui.messages.append((key, data["messages"][key]))
+                    self.gui.switch_to(data["state"])
+
+                else:
+                    self.close()
+        except:
+            self.close()
+
+class GUI(tk.Frame):
+    def __init__(self, master=None):
+        self.config= configparser.ConfigParser()
+        self.config.read(config_fname, "UTF8")
+        tk.Frame.__init__(self, master)
+        self.parent=master
+        self.parent.protocol("WM_DELETE_WINDOW", self.quit)
+        domyslne=self.config["DEFAULT"]
+        self.geometria_baza=domyslne.get('bazowa_geometria',"1000x800+50+50")
+        self.parent.geometry(self.geometria_baza)
+        self.parent.minsize(1024, 768)
+        self.utworz_bazowe_menu()
+        # self.utworz_pasek_narzedzi()
+        self.utworz_status()
+
+        self.dodaj_menu_custom()
+        self.dodaj_menu_help()
+        # self.utworz_dodatki()
+        self.parent.columnconfigure(0, weight=999)
+        self.parent.columnconfigure(1, weight=1)
+        self.parent.rowconfigure(0, weight=1)
+        self.parent.rowconfigure(1, weight=9999)
+        self.parent.rowconfigure(2, weight=1)
+
+        self.client = None
+
+        self.bg_color = '#36393f'
+        self.font_color = '#cccccc'
+
+        self.frames = {}
+        self.frames["wait"] = self.draw_wait_screen()
+        self.frames["game"] = self.draw_game_screen()
+        self.frames["welcome"] = self.draw_welcome_screen()
+        self.switch_to("welcome")
+
+        self.messages = []
+        self.player_id = -1
+        self.server_data = {}
+
+        self.master.title("AFORYZMY")
+
+    def utworz_pasek_narzedzi(self):
+        self.toolbar_images = []   #muszą być pamiętane stale
+        self.toolbar = tk.Frame(self.parent)
+        for image, command in (
+                ("res/filenew.gif", self.file_new),
+                ("res/fileopen.gif", self.file_open),
+                ("res/filesave.gif", self.file_save)):
+            image = os.path.join(os.path.dirname(__file__), image)
+            try:
+                image = tkinter.PhotoImage(file=image)
+                self.toolbar_images.append(image)
+                button = tkinter.Button(self.toolbar, image=image,
+                                        command=command)
+                button.grid(row=0, column=len(self.toolbar_images) -1) #KOLEJNE ELEMENTY
+            except tkinter.TclError as err:
+                print(err)  # gdy kłopoty z odczytaniem pliku
+        self.toolbar.grid(row=0, column=0, columnspan=2, sticky=tkinter.NSEW)
+        
+    
+    def utworz_dodatki(self):
+        pass
+    
+    def utworz_status(self):
+        self.statusbar = tk.Label(self.parent, text="Status...",
+                                       anchor=tkinter.W)
+        self.statusbar.after(5000, self.clearStatusBar)
+        self.statusbar.grid(row=2, column=0, columnspan=2,
+                            sticky=tkinter.EW)
+        pass
+    
+    def ustawStatusBar(self, txt):
+        self.statusbar["text"] = txt
+        
+    def clearStatusBar(self):
+        self.statusbar["text"] = ""
+    
+    def utworz_bazowe_menu(self):
+        self.menubar = tk.Menu(self.parent)
+        self.parent["menu"] = self.menubar
+        fileMenu = tk.Menu(self.menubar)
+        for label, command, shortcut_text, shortcut in (
+                ("Rozłącz", self.disconnect, None, None),
+                ("Quit", self.quit, "Ctrl+Q", "<Control-q>")):
+            if label is None:
+                fileMenu.add_separator()
+            else:
+                fileMenu.add_command(label=label, underline=0,
+                        command=command, accelerator=shortcut_text)
+                self.parent.bind(shortcut, command)
+        self.menubar.add_cascade(label="File", menu=fileMenu, underline=0) 
+        pass
+    
+    def dodaj_menu_help(self):
+        fileMenu = tk.Menu(self.menubar)
+        fileMenu.add_command(label="About...", underline=0,
+                command=self.file_new, accelerator="Ctrl+B")
+        self.parent.bind("<Control-b>", self.file_new)
+        self.menubar.add_cascade(label="Help", menu=fileMenu, underline=0) 
+        pass    
+
+    def close(self):
+        geometria = self.parent.winfo_geometry()
+        self.config["DEFAULT"]["bazowa_geometria"] = geometria
+        with open(config_fname, 'w') as config_plik:
+            self.config.write(config_plik)
+        self.parent.destroy()
+
+    def disconnect(self, event= None):
+        if self.client is not None:
+            self.client.close()
+            self.client = None
+            self.switch_to("welcome")
+
+    def quit(self, event= None):
+        reply = tkinter.messagebox.askyesno(
+                        "Wyjście",
+                        "Naprawdę wyjść?", parent=self.parent)
+        event=event
+        if reply:
+            if (self.client is not None):
+                self.client.close()
+            self.close()
+    
+    def dodaj_menu_custom(self):
+        pass
+    def file_new(self, event=None):
+        event=event
+    def file_open(self,event=None):
+        event=event
+        pass
+    def file_save(self,event=None):
+        event=event
+        pass
+    def connect(self):
+        self.client = Client(self.address_entry.get(), 7312, self.username_entry.get(), self)
+
+    def upload(self):
+        self.switch_to("wait")
+        self.client.send(self.aphorism_entry.get())
+
+    def vote(self, player):
+        self.switch_to("wait")
+        self.client.vote(player)
+
+    def switch_to(self, state):
+        for frame in self.frames:
+            self.frames[frame].grid_forget()
+        if state == "vote" or state == "display":
+            self.frames[state] = self.draw_screen(state)
+        self.frames[state].grid(row=1, column=0, columnspan=1, rowspan=1, sticky=NSEW)
+
+
+    def draw_wait_screen(self):
+        frame = tk.Frame(self.parent, background=self.bg_color)
+        label = tk.Label(frame, text="Waiting for other players", pady=100, bg=self.bg_color, fg=self.font_color)
+        label.pack()
+        return frame
+
+    def draw_screen(self, type):
+        if(type == "vote"):
+            frame = tk.Frame(self.parent, background=self.bg_color)
+            title_label = tk.Label(frame, text="AFORYZMY", bg=self.bg_color, fg=self.font_color, font="Helvetica 22")
+            title_label.pack()
+
+            tk.Label(frame, text="Wybierz najlepszą definicję ASS", fg=self.font_color, bg=self.bg_color, font="Helvetica 12", height="2", anchor="n").pack()
+
+            for message in self.messages:
+                player, text = message
+                if str(player) != str(self.player_id):
+                    tk.Button(frame, text=text, fg=self.font_color, bg=self.bg_color, font="Helvetica 12", width="80", height="3", pady="2", relief="flat", command=partial(self.vote, player)).pack()
+
+            return frame
+        if (type == "display"):
+            frame = tk.Frame(self.parent, background=self.bg_color)
+            title_label = tk.Label(frame, text="AFORYZMY", bg=self.bg_color, fg=self.font_color, font="Helvetica 22")
+            title_label.pack()
+
+            tk.Label(frame, text="Wyniki", fg=self.font_color, bg=self.bg_color,
+                     font="Helvetica 12", height="2", anchor="n").pack()
+
+            for message in self.messages:
+                player, text = message
+                total_score = 0
+                score = 0
+                if player in self.server_data["total_scores"]:
+                    total_score = self.server_data["total_scores"][player]
+                if player in self.server_data["scores"]:
+                    score = self.server_data["scores"][player]
+                tk.Label(frame, text="{} ({}):\n{} ({})".format(self.server_data["users"][player], total_score, text, score), fg=self.font_color, bg=self.bg_color, font="Helvetica 12", width="100", anchor="nw",
+                          height="3", pady="2").pack()
+
+            tk.Label(frame, text="Kolejna runda rozpocznie się za chwilę", fg=self.font_color, bg=self.bg_color,
+                     font="Helvetica 12", height="3", anchor="s").pack()
+
+            return frame
+
+    def draw_game_screen(self):
+        frame = tk.Frame(self.parent, background=self.bg_color)
+        title_label = tk.Label(frame, text="AFORYZMY", bg=self.bg_color, fg=self.font_color, font="Helvetica 22")
+        title_label.pack()
+
+        tk.Label(frame, text="Describe the word: ASS", fg=self.font_color, bg=self.bg_color, font="Helvetica 12").pack()
+        sv = tk.StringVar()
+        self.aphorism_entry = tk.Entry(frame, width=80, textvariable=sv)
+        sv.trace_add("write", lambda x, y, z: self.key_fix(sv, 100))
+        self.aphorism_entry.pack()
+
+        send_button = tk.Button(frame, text="Send", command=self.upload)
+        send_button.pack()
+        return frame
+    
+    def draw_welcome_screen(self):
+        frame = tk.Frame(self.parent, background=self.bg_color)
+        title_label = tk.Label(frame, text="AFORYZMY", bg=self.bg_color, fg=self.font_color, font="Helvetica 22")
+        title_label.pack()
+
+        tk.Label(frame, text="Login", fg=self.font_color, bg=self.bg_color, font="Helvetica 12").pack()
+        sv = tk.StringVar()
+        self.username_entry = tk.Entry(frame, textvariable=sv)
+        sv.trace_add("write", lambda x,y,z: self.key_fix(sv, 20))
+        self.username_entry.pack()
+
+        tk.Label(frame, text="Address", fg=self.font_color, bg=self.bg_color, font="Helvetica 12").pack()
+        self.address_entry = tk.Entry(frame)
+        self.address_entry.insert(0,"localhost")
+        self.address_entry.pack()
+
+        title_button = tk.Button(frame, text="Connect", command=self.connect)
+        title_button.pack()
+        return frame
+
+
+    def key_fix(self, sv, limit):
+        str = sv.get()
+        list = [
+            ('ę', 'ê'), ('Ę', 'Ê'),
+            ('ś', 'œ'), ('Ś', 'Œ'),
+            ('ć', 'æ'), ('Ć', 'Æ'),
+            ('ł', '³'), ('Ł', '£'),
+            ('ń', 'ñ'), ('Ń', 'Ñ'),
+            ('ą', '¹'), ('Ą', '¥'),
+            ('ż', '¿'), ('Ż', '¯'),
+            ('ź', 'Ÿ'), #('Ź', '')
+        ]
+        for (pl, k) in list:
+            str = str.replace(k, pl)
+        sv.set(str[:limit])
+    
+if __name__ == '__main__':
+    root = tk.Tk()
+    app = GUI(master=root)
+    app.mainloop()
+    pass