diff --git a/__main__.py b/__main__.py deleted file mode 100644 index b295943..0000000 --- a/__main__.py +++ /dev/null @@ -1,455 +0,0 @@ -import tkinter as tk -from tkinter import ttk -from tkinter import messagebox, font -from ttkthemes import ThemedTk -from tkinter.scrolledtext import ScrolledText -import json -import webbrowser -from subprocess import Popen, PIPE -from pathlib import Path -import threading -from sys import platform -import requests -from hashlib import sha256 -from os import listdir -from os.path import isfile, join, exists -import shutil - -logarr = [] -with open('lang.json') as f: lang=json.load(f) - -class menus: - def clientmenu(file, mainframe): - for child in mainframe.winfo_children(): child.destroy() - checkclient = str(helpers.check4client(helpers.getclientpath(file))) - clientdetect = ttk.Label(mainframe, text=f"Was Bootstrapper found: {checkclient}", anchor=tk.W) - clientdetect.grid(row=0, sticky=tk.W) - #not threading this prob stalls the gui, but it's not like the server, where I actually need it to run in the background; in otherwords, I do not care :) - dlldownload = ttk.Button(mainframe, text="Download Latest Bootstrapper", command=lambda: helpers.downloadlatestdll(helpers.getclientpath(file))) - dlldownload.grid(row=1, sticky=tk.W) - - #menu for pluto scripts; running them is not currently implemented - def plutomenu(file, mainframe): - for child in mainframe.winfo_children(): child.destroy() - openwfpath = helpers.getclientpath(file) + "/OpenWF/scripts/" - def openfolder(folder): - Popen(['xdg-open', folder]) - - onlyfiles = [f for f in listdir(openwfpath) if isfile(join(openwfpath, f))] - i = 0 - for file in onlyfiles: - filelabel = ttk.Label(mainframe, text=file, anchor=tk.W) - filelabel.grid(row = i, column = 0, sticky = tk.W, pady = 2) - plutorun = ttk.Button(mainframe, text="Running not implemented yet", command=lambda: runpluto(file)) - plutorun.grid(row = i, column = 1, sticky = tk.W, pady = 2, padx=10) - i += 1 - - # Input would be a json file - def settingsmenu(file, mainframe, vcmd): - - for child in mainframe.winfo_children(): child.destroy() - if Path(file).is_file(): - with open(file) as f: - settings = json.load(f) - i = 0 - frameunder = ttk.Frame(mainframe) - tempsettings = {} - print(settings) - for key in settings.keys(): - if key in lang.keys(): - item = ttk.Label(frameunder, text=(lang[key] + " : ")) - else: - item = ttk.Label(frameunder, text=(key + " : ")) - item.grid(row = i, column = 0, sticky = tk.W, pady = 2) - print (type(settings[key])) - if type(settings[key]) is str: - value = ttk.Entry(frameunder, width=50) - value.insert(0,settings[key]) - - elif type(settings[key]) not in [str, bool, int, dict]: - value = ttk.Label(frameunder, text="N/A") - elif type(settings[key]) is bool: - boeol = tk.StringVar() - value = ttk.OptionMenu(frameunder, boeol, settings[key], True, False) - - elif type(settings[key]) is int: - value = ttk.Entry(frameunder, width=50, validate='key', validatecommand=(vcmd, '%P')) - value.insert(0,settings[key]) - #stupid ass nested dicts eat my whole balls - elif type(settings[key]) is dict: - value = {} - for k in settings[key].keys(): - value[k] ={} - if type(settings[key][k]) is str: - value[k]["value"] = ttk.Entry(frameunder, width=50) - value[k]["value"].insert(0,settings[key][k]) - elif type(settings[key][k]) not in [str, bool, int]: - value[k]["value"] = ttk.Label(frameunder, text="N/A") - elif type(settings[key][k]) is bool: - boeol = tk.BooleanVar() - value[k]["value"] = ttk.OptionMenu(frameunder, boeol, settings[key][k], True, False) - boeol.set(settings[key][k]) - value[k]["valueop"] = boeol - elif type(settings[key][k]) is int: - value[k]["value"] = ttk.Entry(frameunder, width=50, validate='key', validatecommand=(vcmd, '%P')) - value[k]["value"].insert(0,settings[key][k]) - value[k]["type"] = type(settings[key][k]) - - - if type(value) is not dict: - value.grid(row = i, column = 1, sticky = tk.W, pady = 2) - i += 1 - else: - i+=1 - sp1=ttk.Separator(mainframe,orient='horizontal') - sp1.grid(row=i,column=1,sticky='ew') - i+=1 - for k in value.keys(): - print(k) - dictlabel = ttk.Label(frameunder, text=(k + " : ")) - dictlabel.grid(row = i, column = 0, sticky = tk.E, pady = 2) - value[k]["value"].grid(row = i, column = 1, sticky = tk.W, pady = 2) - i+=1 - ttk.Separator(mainframe, orient=tk.HORIZONTAL).grid(row=i) - i+=1 - if type(settings[key]) is bool: - tempsettings[key] = { - "value" : boeol, - "type" : type(settings[key]) - } - else: - tempsettings[key] = { - "value" : value, - "type" : type(settings[key]) - } - - save = ttk.Button(frameunder, command=lambda: helpers.savefile(file, tempsettings), text="SAVE") - save.grid(row=i, column=2, sticky=tk.E, pady=2) - frameunder.grid() - - - def servermenu(mainframe, configfile): - for child in mainframe.winfo_children(): child.destroy() #oneline to destroy everything in the main frame - side1 = ttk.Frame(mainframe) - side2 = ttk.Frame(mainframe) - # Side one of the 'server' menu - logarea = ScrolledText(side2, - wrap = tk.WORD, - state="disabled") - - startb = ttk.Button(side1, text="Start Server", command=lambda: [helpers.bgthread(helpers.serverbackground, [helpers.getsnpath(configfile), logarea])]) - startb.grid(row = 0, column = 0, sticky = tk.W, pady = 2) - # Side two of the 'server' menu - - logarea.grid(row = 0, column = 0, sticky = tk.E, pady = 2) - - side1.grid(row = 0, column = 0, sticky = tk.N, pady = 2) - side2.grid(row = 0, column = 1, sticky = tk.N, pady = 2) - -class helpers: - def downloadlatestdll(filepath): - x = requests.get('https://openwf.io/supplementals/client%20drop-in/meta') - meta = json.loads(x.text) - url = f"https://openwf.io/supplementals/client%20drop-in/{meta['version']}/dwmapi.dll" - - content = requests.get(url, stream=True).content - hashofdll = sha256() - hashofdll.update(content) - - if hashofdll.hexdigest() == meta['sha256']: - with open(filepath + "dwmapi.dll", "wb") as out_file: - out_file.write(content) - messagebox.showinfo(title="Bootstrapper Downloaded", message="Bootstrapper Downloaded!") - else: - messagebox.showerror(title="Unknown Error.", message="SpaceninGUI could not verify the hash of the Bootstrapper. Sorry :(") - - def check4client(clientpath): - onlyfiles = [f for f in listdir(clientpath) if isfile(join(clientpath, f))] - if "dwmapi.dll" in onlyfiles: - return True - else: - return False - - # Not implemented yet lol - def runpluto(name): - pass - - def is_number(data): - """Validate the contents of an entry widget as a int.""" - if data == '': - return True - try: - rv = int(data) - except ValueError: - return False - return True - - def savefile(file, save): - if Path(file).is_file: - with open(file) as f: - data = json.load(f) - - for key in save.keys(): - if save[key]["type"] is bool: - if save[key]['value'].get() == '1': - data[key] = True - else: - data[key] = False - print(save[key]['value'].get()) - elif save[key]["type"] is str: - data[key] = str(save[key]["value"].get()) - elif save[key]["type"] is int: - data[key] = int(save[key]["value"].get()) - elif save[key]["type"] is dict: - for k in save[key]['value'].keys(): - if save[key]['value'][k]["type"] is bool: - data[key][k] = bool(save[key]['value'][k]["valueop"].get()) - elif save[key]['value'][k]["type"] is str: - data[key][k] = str(save[key]['value'][k]["value"].get()) - elif save[key]['value'][k]["type"] is int: - data[key][k] = int(save[key]['value'][k]["value"].get()) - - with open(file, "w") as f: - json.dump(data, f, indent=2) - - def getclientpath(file): - if Path(file).is_file(): - with open(file) as f: - d = json.load(f) - return d["wfpath"] - else: - return False - - # Grabs the serverpath, returns false if non-existant - def getsnpath(file): - if Path(file).is_file(): - with open(file) as f: - d = json.load(f) - return d["spaceninjapath"] - else: - return False - - def getlogmax(): - file = 'sngconfig.json' - if Path(file).is_file(): - with open(file) as f: - d = json.load(f) - return int(d["maxlogsize"]) - else: - return False - - def bgthread(func, args): - th = threading.Thread(target=func, args=args) - th.daemon = True - th.start() - - def serverbackground(cd, logarea): # To my knowledge, running the server in the main thread would stall the gui, fuck that lol - logmax = helpers.getlogmax() - - def mongo(): - sysctl = Popen(['systemctl', 'start', 'mongodb']) - sysctl.wait() - - - def execute(cd): - popen = Popen(['npm', 'run', 'dev'], stdin=PIPE, stdout=PIPE, universal_newlines=True, cwd=cd) - for stdout_line in iter(popen.stdout.readline, ""): - yield stdout_line - popen.stdout.close() - return_code = popen.wait() - if return_code: - raise subprocess.CalledProcessError(return_code) - - if platform == "linux": - print("Running on linux requires mongodb to be started!") - mongo() - - for path in execute(cd): - if len(logarr) < logmax: - logarr.append(path) - else: - logarr.pop(0) - logarr.append(path) - if logarea: - logarea.configure(state="normal") - logarea.delete(1.0, "end") - for element in logarr: - logarea.insert(tk.INSERT, element) - logarea.configure(state="disabled") - - def check4sn(configfile): - file = helpers.getsnpath(configfile) + "package.json" - if Path(file).is_file(): - with open(file) as f: - d = json.load(f) - if (d["name"] == "wf-emulator"): - return True - else: - return False - - def on_closing(root): - if messagebox.askokcancel("Quit", "Do you want to quit?"): - root.destroy() - -class main: - def __init__(self, configfile): - - root = ThemedTk(theme='black', themebg=True) - root.title('SpaceNinGui Version 1.0') - root.minsize(400, 300) - serverlogs = tk.StringVar() - wfemucheck = str(helpers.check4sn(configfile)) - menubar = tk.Menu(root) - vcmd = root.register(helpers.is_number) - filemenu = tk.Menu(menubar, tearoff=0) - filemenu.add_command(label="Options", command=lambda: menus.settingsmenu(file = configfile, mainframe=mainframe, vcmd=vcmd)) - filemenu.add_separator() - filemenu.add_command(label="Exit", command=lambda: helpers.on_closing(root)) - menubar.add_cascade(label="SpaceNinGUI", menu=filemenu) - menubar.add_separator() - - menubar.add_command(label="\u22EE", activebackground=menubar.cget("background")) - - menubar.add_command(label="Server", command=lambda: menus.servermenu(mainframe, configfile)) - menubar.add_command(label="Settings", command=lambda: menus.settingsmenu(file=(helpers.getsnpath(configfile) + "config.json"), mainframe=mainframe, vcmd=vcmd)) - mainframe = ttk.Frame(root) - menubar.add_command(label="\u22EE", activebackground=menubar.cget("background")) - menubar.add_command(label="Client", command=lambda: menus.clientmenu(file="sngconfig.json", mainframe=mainframe)) - menubar.add_command(label="Settings", command=lambda: menus.settingsmenu(file=(helpers.getclientpath(configfile) + "/OpenWF/client_config.json"), mainframe=mainframe, vcmd=vcmd)) - menubar.add_command(label="Scripts", command=lambda: menus.plutomenu(file="sngconfig.json", mainframe=mainframe)) - - - - - checklabel = ttk.Label(mainframe, text=f"Was Spaceninja Found: {wfemucheck}", anchor=tk.W, font=("Arial", 16, "bold")) - checklabel.grid(row = 0, column = 0, sticky = tk.W, pady = 2) - mainframe.grid(row = 0, column = 0, pady = 2) - root.protocol("WM_DELETE_WINDOW", lambda: helpers.on_closing(root)) - root.config(menu=menubar) - root.mainloop() - -class install(): - - - def __init__(self): - self.step = 1 - - self.config = {} - self.elements = {} - - root = ThemedTk(theme='black', themebg=True) - self.root = root - self.installstep=tk.StringVar() - self.installprog=tk.IntVar() - self.installprog.set(0) - self.installstep.set("Init") - #font options lmao - standard = ('Noto Sans', 10) - standardbold = ('Noto Sans', 10, "bold") - self.standard = standard - self.standardbold = standardbold - - root.title('SpaceNinGui Installer') - root.minsize(400, 300) - leftframe = ttk.Frame(root, borderwidth=10) - rightframe = ttk.Frame(root, borderwidth=1) - steps=["1: Initial Message", "2: Install Spaceninja Server", "3: Install Warframe Bootstrapper", "4: Final Steps"] - ttk.Label(leftframe, text="Steps:").grid(padx=20) - self.steplabel=[] - for step in steps: - label=ttk.Label(leftframe, text=step, anchor=tk.W) - self.steplabel.append(label) - for label in self.steplabel: - label.grid(padx=20, pady=5, sticky=tk.W) - - - self.steplabel[0].config(font=standardbold) - rightinnerframe = ttk.Frame(rightframe) - ttk.Label(rightinnerframe, text="Welcome to SpaceNinGui! \nFirst, We have to get some inital settings setup. \nWe will start with the server configuration.").grid() - leftframe.grid(row=0, column=0, sticky=tk.W) - - rightinnerframe.grid() - rightframe.grid(row=0, column=1, sticky=tk.E) - nextbutton = ttk.Button(rightframe, text="Next", command=lambda: self.next(rightinnerframe)) - nextbutton.grid(row=1, sticky=tk.SE) - root.protocol("WM_DELETE_WINDOW", lambda: helpers.on_closing(root)) - root.mainloop() - - def configsave(self): - with open('sngconfig.json', 'w') as f: - tot = {} - tot["spaceninjapath"] = self.elements['serverpath'].get() - tot["wfpath"] = self.elements['clientpath'].get() - tot['maxlogsize']=10 - json.dump(tot, f, indent=2) - - - - def install(self, clientpath, serverpath): - #first install server - self.installstep.set("Downloading Server Through Git") - sysctl = Popen(['git', 'clone', 'https://openwf.io/SpaceNinjaServer.git', serverpath]) - self.installprog.set(1) - sysctl.wait() - self.installstep.set("Installing Server Requirements (via npm)") - self.installprog.set(25) - sysctl = Popen(["npm", '--prefix', f'{serverpath}', 'install']) - sysctl.wait() - self.installstep.set("Copying Config File") - shutil.copy(serverpath + "/config.json.example", serverpath + "/config.json") - self.installstep.set("Starting Bootstrapper Download") - self.installprog.set(50) - print("Server install worked. ") - helpers.downloadlatestdll(clientpath) - self.installprog.set(99) - self.installstep.set("Install Complete!\nPress next then restart to get started!") - - - def next(self, inner): - if self.step == 1: - self.step+=1 - for child in inner.winfo_children(): child.destroy() - self.elements["serverpath"] = tk.StringVar() - path = ttk.Entry(inner, width=50, textvariable=self.elements["serverpath"]) - flavortext = ttk.Label(inner, text="Please input a path that you would like to install the Server in!") - flavortext.grid(padx=10) - path.grid(padx=10) - self.steplabel[0].config(font=self.standard) - self.steplabel[1].config(font=self.standardbold) - elif self.step == 2: - self.step+=1 - self.elements["clientpath"] = tk.StringVar() - for child in inner.winfo_children(): child.destroy() - path = ttk.Entry(inner, width=50, textvariable=self.elements["clientpath"]) - flavortext = ttk.Label(inner, text="Please input the path that has Warframe installed\nI highly suggest making a copy to prevent potental bans.", anchor=tk.CENTER) - flavortext.grid(padx=10, pady=5) - path.grid(padx=10) - self.elements["wfpath"] = path - self.steplabel[1].config(font=self.standard) - self.steplabel[2].config(font=self.standardbold) - elif self.step == 3: - self.step+= 1 - print("final step!!!") - for child in inner.winfo_children(): child.destroy() - flavortext = ttk.Label(inner, text="Thank you! The OpenWF setup should be downloading in the background!", anchor=tk.CENTER) - flavortext.grid(padx=10, pady=5) - statustext = ttk.Label(inner, textvariable=self.installstep, anchor=tk.CENTER) - statustext.grid(padx=10, pady=5) - statusbar = ttk.Progressbar(inner, variable=self.installprog) - statusbar.grid() - helpers.bgthread(self.install, [self.elements["clientpath"].get(), self.elements["serverpath"].get()]) - elif self.step == 4: - if self.installstep.get() == "Install Complete!\nPress next then restart to get started!": - self.configsave() - self.root.destroy() - - - - - - -if __name__ == "__main__": - if isfile('sngconfig.json'): - main('sngconfig.json') - else: - install() \ No newline at end of file