diff --git a/network/http_client.py b/network/http_client.py index e7a8651..0380b09 100644 --- a/network/http_client.py +++ b/network/http_client.py @@ -4,6 +4,7 @@ import os import json import time +import fnmatch import hashlib import urllib.request import urllib.parse @@ -60,19 +61,19 @@ def down(win, website, filename, fsize=100000): # If it is a blend file, we are in trouble. - if filename.endswith(".blend"): - dp = go(win, website, "/blend"+filename) - dplen = len(dp.get("files", {})) - for f in dp.get("files", {}): - try: - hashis = hashlib.md5(open(win.project+f,'rb').read()).hexdigest() - except: - hashis = "" - if hashis != dp.get("files", {}).get(f, {}).get("md5"): - win.current["http-server"]["message"] = f[f.rfind("/")+1:] - filesize = dp.get("files", {}).get(f, {}).get("filesize") - print("trying to get:", f) - pp = down(win, website, f, filesize) + # if filename.endswith(".blend"): + # dp = go(win, website, "/blend"+filename) + # dplen = len(dp.get("files", {})) + # for f in dp.get("files", {}): + # try: + # hashis = hashlib.md5(open(win.project+f,'rb').read()).hexdigest() + # except: + # hashis = "" + # if hashis != dp.get("files", {}).get(f, {}).get("md5"): + # win.current["http-server"]["message"] = f[f.rfind("/")+1:] + # filesize = dp.get("files", {}).get(f, {}).get("filesize") + # print("trying to get:", f) + # pp = down(win, website, f, filesize) # Making folder for the files @@ -99,6 +100,96 @@ def down(win, website, filename, fsize=100000): savef.close() +def get_folder_info(win, folders, cur): + + # This function gets an information of what files should be changed. And outputs + # the found data into the the global win thing, so it could accessed later. + + # Making sure we have the infrastructure. + + print("Getting Update Info About Folders") + website = win.analytics["remote-server-url"] + + + if "remote-folder-data" not in win.current: + win.current["remote-folder-data"] = {} + + if cur not in win.current["remote-folder-data"]: + win.current["remote-folder-data"][cur] = {"missing":{}, + "changed":{}} + + def sort_file(filename, files, f): + filedata = files.get(f, {}) + try: + hashis = hashlib.md5(open(win.project+filename,'rb').read()).hexdigest() + except: + hashis = "" + if not os.path.exists(win.project+filename): + win.current["remote-folder-data"][cur]["missing"][filename] = filedata + elif hashis != filedata.get("md5"): + filedata["to_download"] = True + win.current["remote-folder-data"][cur]["changed"][filename] = filedata + + + # Part one: Getting all the data about the files. + + for foldername in folders: + + try: + answer = go(win, website, "/list"+foldername) + files = list(answer.get("files", {}).keys()) + for f in fnmatch.filter(files, folders.get(foldername, "*")): + + # Now we need to figure out whether we have the file + # , whether we don't even have it , + # or whether we have a different version. + + fullfilename = foldername+"/"+f + sort_file(fullfilename, answer.get("files", {}), f) + + + + + except Exception as e: + error = "Error: "+ str(e) + print(error) + + + # Part two: Unwrapping all the blend dependancies data. + + # Here we are going to store blend file that were checked already. + win.current["remote-folder-data"][cur]["blend_checked"] = [] + + # A function checking if we still have some unchecked .blends + def not_checked(): + for t in ["missing", "changed"]: + for i in win.current["remote-folder-data"][cur][t]: + if i not in win.current["remote-folder-data"][cur]["blend_checked"] and i.endswith(".blend"): + return i + return False + + nc = not_checked() + + while nc: + dp = go(win, website, "/blend"+nc) + + for f in dp.get("files", {}): + try: + sort_file(f, + dp.get("files", {}), + f[f.rfind("/")+1:]) + except Exception as e: + print(e) + + win.current["remote-folder-data"][cur]["blend_checked"].append(nc) + + nc = not_checked() + + for t in ["missing", "changed"]: + print(t+":") + for i in win.current["remote-folder-data"][cur][t]: + print(" "+i) + def get_folders(win): # This function will get specified subfolders @@ -244,6 +335,7 @@ def get_files(win): try: hashis = hashlib.md5(open(win.project+filename,'rb').read()).hexdigest() except: + print("missing", filename) hashis = "" if hashis != answer.get("files", {}).get(i, {}).get("md5"): @@ -386,3 +478,193 @@ def layer(win, call): 10,) return surface + +def prompt_layer(win, call): + + # Making the layer + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'], + win.current['h']) + layer = cairo.Context(surface) + + + #text setting + layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + + UI_color.set(layer, win, "dark_overdrop") + layer.rectangle( + 0, + 0, + win.current["w"], + win.current["h"], + ) + layer.fill() + + # So it's going to be like a little window in the center of the VCStudio + # with a simple UI. Probably like 2 things. Folder and a projectname. + + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + win.current["w"]/2-350, + 100, + 700, + win.current["h"]-200, + 10) + + # Exit button + def do(): + win.current["calls"][call]["var"] = False + + + UI_elements.roundrect(layer, win, + win.current["w"]/2+310, + win.current["h"]-140, + 40, + 40, + 10, + button=do, + icon="cancel", + tip=talk.text("cancel")) + + # Clipping everything + UI_elements.roundrect(layer, win, + win.current["w"]/2-350, + 100, + 700, + win.current["h"]-260, + 10, + fill=False) + layer.clip() + + clip = [ + win.current["w"]/2-350, + 100, + 700, + win.current["h"]-260] + + # Setting up the scroll + if "http-prompt" not in win.scroll: + win.scroll["http-prompt"] = 0 + + cur = win.current["remote-folder-data"]["prompt"] + + current_Y = 0 + + # Missing files + + if "missing_active" not in win.current["remote-folder-data"][cur]: + win.current["remote-folder-data"][cur]["missing_active"] = False + + + + icon = "closed" + if win.current["remote-folder-data"][cur]["missing_active"]: + icon = "open" + + def do(): + win.current["remote-folder-data"][cur]["missing_active"] = not win.current["remote-folder-data"][cur]["missing_active"] + + + UI_elements.roundrect(layer, win, + win.current["w"]/2-340, + 110 + current_Y + win.scroll["http-prompt"], + 680, + 40, + 10, + button=do, + icon=icon, + tip=talk.text("MissingFiles")) + + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to(win.current["w"]/2-290, + current_Y + win.scroll["http-prompt"] + 135) + layer.show_text(talk.text("MissingFiles")+" ( "+str(len(win.current["remote-folder-data"][cur]["missing"]))+" ) ") + + current_Y += 50 + + if win.current["remote-folder-data"][cur]["missing_active"]: + for f in win.current["remote-folder-data"][cur]["missing"]: + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to(win.current["w"]/2-270, + current_Y + win.scroll["http-prompt"] + 135) + layer.show_text(f) + + current_Y += 50 + + + # Updated files + + if "changed_active" not in win.current["remote-folder-data"][cur]: + win.current["remote-folder-data"][cur]["changed_active"] = True + + + + icon = "closed" + if win.current["remote-folder-data"][cur]["changed_active"]: + icon = "open" + + def do(): + win.current["remote-folder-data"][cur]["changed_active"] = not win.current["remote-folder-data"][cur]["changed_active"] + + + UI_elements.roundrect(layer, win, + win.current["w"]/2-340, + 110 + current_Y + win.scroll["http-prompt"], + 680, + 40, + 10, + button=do, + icon=icon, + tip=talk.text("ChangedFiles")) + + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to(win.current["w"]/2-290, + current_Y + win.scroll["http-prompt"] + 135) + layer.show_text(talk.text("ChangedFiles")+" ( "+str(len(win.current["remote-folder-data"][cur]["changed"]))+" ) ") + + current_Y += 50 + + if win.current["remote-folder-data"][cur]["changed_active"]: + for f in win.current["remote-folder-data"][cur]["changed"]: + + fdata = win.current["remote-folder-data"][cur]["changed"][f] + + icon = "unchecked" + if fdata["to_download"]: + icon = "checked" + + def do(): + fdata["to_download"] = not fdata["to_download"] + + UI_elements.roundrect(layer, win, + win.current["w"]/2-315, + 110 + current_Y + win.scroll["http-prompt"], + 660, + 40, + 10, + button=do, + icon=icon) + + + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to(win.current["w"]/2-270, + current_Y + win.scroll["http-prompt"] + 135) + layer.show_text(f) + + current_Y += 50 + + UI_elements.scroll_area(layer, win, "http-prompt", + int(win.current["w"]/2-350), + 100, + 700, + win.current["h"]-260, + current_Y, + bar=True, + mmb=True, + url="http-server-prompt" + ) + + return surface diff --git a/network/http_server.py b/network/http_server.py index d0be060..90baeb5 100644 --- a/network/http_server.py +++ b/network/http_server.py @@ -116,7 +116,6 @@ class handler(BaseHTTPRequestHandler): "files":{}} for i in walk[2]: - fd = fileinfo(folder+"/"+i) data["files"][i] = fd @@ -127,6 +126,30 @@ class handler(BaseHTTPRequestHandler): self.end_headers() self.wfile.write(senddata) + # THIS WAS A GOOD IDEA ON PAPER, BUT WITH A 100 GB PROJECT + # IT TOOK FOREVER TO DO THIS FOR ONE PART OF THIS PROJECT. + + # elif self.path.startswith("/tree/"): + # foldername = self.path[5:] + # folder = PROJECT+foldername + + # walk = list(os.walk(folder)) + # data = {"folders":[], + # "files":{}} + # for i in walk: + # fol = i[0].replace(PROJECT, "")[1:] + # data["folders"].append(fol) + # for fil in i[2]: + + # fd = fileinfo(PROJECT+"/"+fol+"/"+fil) + # data["files"][fol+"/"+fil] = fd + + # senddata = json.dumps(data).encode("utf-8") + # self.start_page(200) + # self.send_header('Content-type', 'application/json') + # self.end_headers() + # self.wfile.write(senddata) + elif self.path.startswith("/blend/"): filename = self.path[6:] diff --git a/settings/languages/English.data b/settings/languages/English.data index 6b8cc3d..8e532f1 100644 --- a/settings/languages/English.data +++ b/settings/languages/English.data @@ -284,4 +284,7 @@ remote-update-initial = [Update Project] remote-update-initial-tip = [Download initial project files and replace the ones on the computer with the downloaded files.] -remote-server-url = [The hostname of the remote server.] \ No newline at end of file +remote-server-url = [The hostname of the remote server.] +MissingFiles = [Missing Files] +ChangedFiles = [Changed Files] +RemoteAssetUpdates = [Remote Asset Updates] \ No newline at end of file diff --git a/studio/studio_assetLayer.py b/studio/studio_assetLayer.py index e8b0823..5a37dd1 100644 --- a/studio/studio_assetLayer.py +++ b/studio/studio_assetLayer.py @@ -4,6 +4,7 @@ # This a console project manager. import os +import threading # GTK module ( Graphical interface import gi @@ -143,22 +144,24 @@ def layer(win): def do(): win.current["asset_cur_folder"] = cur - - # Why? - if win.current["asset_cur_folder"] == "idea": - fl = "reference" - elif win.current["asset_cur_folder"] == "texture": - fl = "tex" - elif win.current["asset_cur_folder"] == "render": - fl = "renders" - else: - fl = "" - # Remote Server Stuff - if win.analytics["from-remote-server"]: - def after(win, var): - UI_elements.reload_images(win) - studio_dialogs.http_client_dialog(win, "http-client", after, http_client.get_files, "/dev/"+win.cur+"/"+fl) + # FUNCTIONS PER THINGS + + # # Why? + # if win.current["asset_cur_folder"] == "idea": + # fl = "reference" + # elif win.current["asset_cur_folder"] == "texture": + # fl = "tex" + # elif win.current["asset_cur_folder"] == "render": + # fl = "renders" + # else: + # fl = "" + + # # Remote Server Stuff + # if win.analytics["from-remote-server"]: + # def after(win, var): + # UI_elements.reload_images(win) + # studio_dialogs.http_client_dialog(win, "http-client", after, http_client.get_files, "/dev/"+win.cur+"/"+fl) UI_elements.roundrect(layer, win, @@ -171,9 +174,51 @@ def layer(win): cur, tip=talk.text(folds[cur])) + + # Little Remote Server thing + if win.analytics["from-remote-server"]: + + if "remote-folder-data" not in win.current: + win.current["remote-folder-data"] = {} + + if win.cur not in win.current["remote-folder-data"]: + win.current["remote-folder-data"][win.cur] = {"missing":{}, + "changed":{}} + + def do(): + + def after(win, var): + UI_elements.reload_images(win) + win.current["remote-folder-data"]["prompt"] = win.cur + studio_dialogs.http_client_update_prompt(win, "http-client-prompt", after) + + + UI_elements.roundrect(layer, win, + win.current["w"]/4+60, + 350, + 40, + 40, + 10, + do, + "multiuser", + tip=talk.text("RemoteAssetUpdates")) - - + if win.current["remote-folder-data"][win.cur]["missing"] or win.current["remote-folder-data"][win.cur]["changed"]: + count = str(len(win.current["remote-folder-data"][win.cur]["missing"])+len(win.current["remote-folder-data"][win.cur]["changed"])) + UI_color.set(layer, win, "progress_active") + UI_elements.roundrect(layer, win, + win.current["w"]/4+60+25, + 350, + len(count)*12+6, + 25, + 5) + layer.fill() + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to(win.current["w"]/4+60+28,370) + layer.show_text(count) + + # Preview # Making the layer @@ -438,13 +483,38 @@ def layer(win): os.getcwd()+"/new_file/"+acur+".blend", "/dev"+win.cur+"/", name+".blend") + + + # This is executed on the first frame when you click onto an asset. if win.current["in-asset-remote-server"]: + + # First we gonna change the active folder to view the Blend files. + # This is important for the function for the remote server. + win.current["asset_cur_folder"] = "blender" + + # Let's also check for updates on the file + + + # Remote Server Stuff if win.analytics["from-remote-server"]: - def after(win, var): - UI_elements.reload_images(win) - studio_dialogs.http_client_dialog(win, "http-client", after, http_client.get_asset_files, "/dev/"+win.cur+"/") + + # Checking date [ FOLDER NAME ] [ FILES TO CHECK FOR ] + check_folders = {"/dev"+win.cur : "*", + "/ast/"+acur : name+"*", + "/dev"+win.cur+"/renders" : "*", + "/dev"+win.cur+"/reference" : "*", + "/dev"+win.cur+"/tex" : "*", + } + + check_updates = threading.Thread(target=http_client.get_folder_info, + args=(win, check_folders, win.cur, )) + check_updates.setDaemon(True) + check_updates.start() + + + win.current["in-asset-remote-server"] = False diff --git a/studio/studio_dialogs.py b/studio/studio_dialogs.py index 6056149..9286bf0 100644 --- a/studio/studio_dialogs.py +++ b/studio/studio_dialogs.py @@ -365,3 +365,20 @@ def http_client_dialog(win, name, call, function, args=""): function_run = threading.Thread(target=function, args=(win,)) function_run.setDaemon(True) function_run.start() + +def http_client_update_prompt(win, name, call): + + # This function is going to be the UI for http-client. + + if name not in win.current["calls"]: + win.current["calls"][name] = { + "var" :None, # This is the variable that we are waiting for + "call":call, # This is what it's going to run when it's done + "url" :"http-server-prompt", + "back":win.url,# This is where it's going to come back when it's done + "draw":http_client.prompt_layer + } + + # Let's clear the LMB just in case + win.previous["LMB"] = False +