From f60b410124145c932a89435d482d0225a6933ef8 Mon Sep 17 00:00:00 2001 From: kirbylife <gabriel13m@gmail.com> Date: Sun, 28 Jul 2019 11:18:49 -0500 Subject: [PATCH] Initial commit --- client.py | 359 ++++++++++++++++++++++++++++++++++++++++++++++++ compare_json.py | 49 +++++++ config.py | 43 ++++++ dir_to_json.py | 50 +++++++ first_test.py | 42 ++++++ http_server.py | 67 +++++++++ img/logo.png | Bin 0 -> 42462 bytes second_test.py | 117 ++++++++++++++++ 8 files changed, 727 insertions(+) create mode 100755 client.py create mode 100644 compare_json.py create mode 100644 config.py create mode 100644 dir_to_json.py create mode 100644 first_test.py create mode 100644 http_server.py create mode 100644 img/logo.png create mode 100644 second_test.py diff --git a/client.py b/client.py new file mode 100755 index 0000000..0b901d9 --- /dev/null +++ b/client.py @@ -0,0 +1,359 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import ftplib +import json +import os +import pathlib +import socket +import sys +from copy import deepcopy +from random import randint +from shutil import rmtree +from threading import Thread +from time import sleep +from tkinter import Button, Entry, Label, StringVar, Tk + +from PIL import Image, ImageTk +from requests import post + +# import rethinkdb as r +from compare_json import compare_json +from dir_to_json import get_json + +# from tcping import Ping + +#ORIGINAL = "/home/kirbylife/Proyectos/munyal_test/another" +ORIGINAL = "/home/kirbylife/Proyectos/munyal_test/" +IP = "localhost" +USERNAME = "munyal" +PASSWORD = "123" +HOSTNAME = socket.gethostname() + str(randint(1, 100000000)) +SKIP_UPLOAD = [] +FLAG_DOWNLOAD = False +pending_routes = [] + + +def check_network(port): + ping = Ping(IP, port, 20) + ping.ping(1) + print(SKIP_UPLOAD) + return ping.result.rows[0].successed == 1 + + +def watch_dir(): + global pending_routes + folder = os.path.join(os.getenv("HOME"), ".munyal") + if not os.path.exists(folder): + pathlib.Path(folder).mkdir(parents=True) + + actual_file = os.path.join(folder, "actual.json") + if not os.path.exists(actual_file): + with open(actual_file, "w") as f: + f.write(json.dumps([])) + pending_file = os.path.join(folder, "pending_routes.json") + if not os.path.exists(pending_file): + with open(pending_file, "w") as f: + f.write(json.dumps([])) + + with open(actual_file, "r") as f: + actual = json.loads(f.read()) + actual = get_json(ORIGINAL) + new = deepcopy(actual) + with open(pending_file, "r") as f: + pending_routes = json.loads(f.read()) + new = get_json(ORIGINAL) + while True: + sleep(0.2) + while True: + try: + jsons = compare_json(deepcopy(actual), deepcopy(new)) + except: + new = get_json(ORIGINAL) + else: + break + changes = get_changes(jsons) + + pending_routes = pending_routes + changes + with open(pending_file, "w") as f: + f.write(json.dumps(pending_routes, indent=4)) + + actual = deepcopy(new) + with open(actual_file, "w") as f: + f.write(json.dumps(actual, indent=4)) + while True: + try: + new = get_json(ORIGINAL) + except: + pass + else: + break + + +def need_deleted(items, route): + out = [] + for item in items: + if item.get("is_file"): + out.append({ + "action": "delete", + "route": os.path.join(route, item.get('name')) + }) + else: + if item.get('content'): + out = out + need_deleted(item.get("content"), + os.path.join(route, item.get('name'))) + else: + out.append({ + "action": "delete_folder", + "route": os.path.join(route, item.get('name')) + }) + return out + + +def need_added(items, route): + out = [] + for item in items: + if item.get("is_file"): + out.append({ + "action": "add", + "route": os.path.join(route, item.get('name')) + }) + else: + if item.get('content'): + out = out + need_added(item.get("content"), + os.path.join(route, item.get('name'))) + else: + out.append({ + "action": "add_folder", + "route": os.path.join(route, item.get('name')) + }) + return out + + +def get_changes(jsons, route=''): + delete, add = jsons + out = need_deleted(delete, route) + need_added(add, route) + return out + + +def _is_ftp_dir(ftp_handle, name): + original_cwd = ftp_handle.pwd() + try: + ftp_handle.cwd(name) + ftp_handle.cwd(original_cwd) + return True + except: + return False + + +def _make_parent_dir(fpath): + #dirname = os.path.dirname(fpath) + dirname = os.path.join(ORIGINAL, fpath) + while not os.path.exists(dirname): + try: + os.makedirs(dirname) + print("created {0}".format(dirname)) + except: + _make_parent_dir(dirname) + + +def _download_ftp_file(ftp_handle, name, dest, overwrite): + if not os.path.exists(dest) or overwrite is True: + try: + with open(dest, 'wb') as f: + ftp_handle.retrbinary("RETR {0}".format(name), f.write) + print("downloaded: {0}".format(dest)) + except FileNotFoundError: + print("FAILED: {0}".format(dest)) + else: + print("already exists: {0}".format(dest)) + + +def _mirror_ftp_dir(ftp_handle, name, overwrite): + for item in ftp_handle.nlst(name): + SKIP_UPLOAD.append(item) + if _is_ftp_dir(ftp_handle, item): + _make_parent_dir(item.lstrip("/")) + _mirror_ftp_dir(ftp_handle, os.path.join(name, item), overwrite) + else: + _download_ftp_file(ftp_handle, item, os.path.join(ORIGINAL, item), + overwrite) + + +def download_ftp_tree(overwrite=False): + FLAG_DOWNLOAD = True + ftp_handle = ftplib.FTP(IP, USERNAME, PASSWORD) + path = "" + original_directory = os.getcwd() + os.chdir(ORIGINAL) + _mirror_ftp_dir(ftp_handle, path, overwrite) + os.chdir(original_directory) + ftp_handle.close() + FLAG_DOWNLOAD = False + + +def upload(*args): + global SKIP_UPLOAD + global pending_routes + print("Modulo de subida listo") + while True: + sleep(0.1) + if check_network('21') and pending_routes: + change = pending_routes.pop(0) + if change['route'] not in SKIP_UPLOAD: + ftp = ftplib.FTP(IP, USERNAME, PASSWORD) + route = os.path.join(ORIGINAL, change['route']) + success = False + while not success: + try: + if change['action'] == 'add': + while FLAG_DOWNLOAD: + print("Wait") + print("Agregar archivo") + with open(route, "rb") as f: + ftp.storbinary("STOR /" + change['route'], f) + elif change['action'] == 'add_folder': + print("Agregar carpeta") + ftp.mkd(change['route']) + elif change['action'] == 'delete': + print("Borrar archivo") + ftp.delete(change['route']) + elif change['action'] == 'delete_folder': + print("Borrar carpeta") + ftp.rmd(change['route']) + else: + print("Unexpected action") + except: + print("Error uploading\n") + r = post("http://" + IP + ':8000/upload', + data={ + 'host': HOSTNAME, + 'action': change['action'], + 'route': change['route'] + }) + r = json.loads(r.text) + print(json.dumps(r, indent=4)) + success = r['status'] == 'ok' + ftp.close() + else: + SKIP_UPLOAD.pop() + return 0 + + +def download(*args): + global SKIP_UPLOAD + while True: + sleep(1) + if check_network(28015) and check_network(21): + try: + download_ftp_tree(overwrite=False) + + print("Modulo de descarga listo") + print("Carpeta " + ORIGINAL) + r.connect(IP, 28015).repl() + cursor = r.table("changes").changes().run() + for document in cursor: + change = document['new_val'] + #print(change) + if change['host'] != HOSTNAME: + route = os.path.join(ORIGINAL, change['route']) + SKIP_UPLOAD.append(change['route']) + try: + if change['action'] == 'add': + print("Agregar archivo") + FLAG_DOWNLOAD = True + ftp = ftplib.FTP(IP, USERNAME, PASSWORD) + with open(route, "wb") as f: + ftp.retrbinary("RETR /" + change['route'], + f.write) + ftp.close() + FLAG_DOWNLOAD = False + elif change['action'] == 'add_folder': + print("Agregar carpeta") + pathlib.Path(route).mkdir(parents=True) + elif change['action'] == 'delete': + print("Borrar archivo") + pathlib.Path(route).unlink() + elif change['action'] == 'delete_folder': + print("Borrar carpeta") + rmtree(route) + else: + print("Unexpected action") + except OSError as e: + print("Error en el sistema operativo") + except: + print("Error en el servidor FTP") + except r.errors.ReqlDriverError as e: + print("Conection refused with rethinkdb") + return 0 + + +def run_client(window, password, username, host, folder): + global PASSWORD + global IP + global USERNAME + global ORIGINAL + + PASSWORD = password.get() + USERNAME = username.get() + IP = host.get() + ORIGINAL = folder.get() + + if not os.path.exists(ORIGINAL): + pathlib.Path(ORIGINAL).mkdir(parents=True) + + download_thread = Thread(target=download, args=[window]) + download_thread.setDaemon(True) + download_thread.start() + + upload_thread = Thread(target=upload, args=[window]) + upload_thread.setDaemon(True) + upload_thread.start() + + watch_dir_thread = Thread(target=watch_dir) + watch_dir_thread.setDaemon(True) + watch_dir_thread.start() + + +def main(args): + root = Tk() + root.geometry("250x400") + + img_logo = Image.open("img/logo.png") + img_tk = ImageTk.PhotoImage(img_logo.resize((200, 150), Image.ANTIALIAS)) + + host = StringVar() + host.set("localhost") + host_field = Entry(root, textvariable=host) + + passwd = StringVar() + passwd_field = Entry(root, textvariable=passwd, show="*") + + folder = StringVar() + folder.set(os.path.join(os.getenv("HOME"), "Munyal")) + folder_field = Entry(root, textvariable=folder) + + connect = Button(root, + text="Conectar", + command=lambda: run_client(root, passwd, host, folder)) + + Label(root, text="MUNYAL").pack() + Label(root, image=img_tk).pack() + Label(root, text="").pack() + Label(root, text="Ruta del servidor").pack() + host_field.pack() + Label(root, text="").pack() + Label(root, text="ContraseƱa").pack() + passwd_field.pack() + Label(root, text="").pack() + Label(root, text="Carpeta a sincronizar").pack() + folder_field.pack() + Label(root, text="").pack() + connect.pack() + + root.mainloop() + + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv)) diff --git a/compare_json.py b/compare_json.py new file mode 100644 index 0000000..77c1d15 --- /dev/null +++ b/compare_json.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import json + +from dir_to_json import get_json + +def compare_json(json1, json2): + bckup1, bckup2 = json1[:], json2[:] + items1 = list(enumerate(json1)) + items2 = list(enumerate(json2)) + for i, item1 in items1: + for j, item2 in items2: + if item1["name"] == item2["name"]: + if item1["is_file"] == True == item2["is_file"]: + if item1["checksum"] == item2["checksum"]: + json1[i] = None + json2[j] = None + ''' + else: + json1[i]["tag"] = "update" + json2[j] = None + ''' + elif item1["is_file"] == False == item2["is_file"]: + new_json1, new_json2 = compare_json(item1["content"], item2["content"]) + if len(new_json1) == 0: + json1[i] = None + else: + json1[i]["content"] = new_json1 + if len(new_json2) == 0: + json2[j] = None + else: + json2[j]["content"] = new_json2 + elif item1["is_file"] != item2["is_file"]:##### Caso hipotetico imposible ##### + json1[i]["tag"] == "delete" + json1 = list(filter(None, json1)) + json2 = list(filter(None, json2)) + return json1, json2 +if __name__ == "__main__": + try: + json1 = get_json("/home/kirbylife/Proyectos/munyal_test/original") + json2 = get_json("/home/kirbylife/Proyectos/munyal_test/copy") + except: + print("error outside") + json1, json2 = compare_json(json1, json2) + #print(len(json1), len(json2)) + print(json.dumps(json1, indent=4)) + print("\n============\n") + print(json.dumps(json2, indent=4)) diff --git a/config.py b/config.py new file mode 100644 index 0000000..6b7a7ec --- /dev/null +++ b/config.py @@ -0,0 +1,43 @@ +import os +from tkinter import Button, Entry, Label, StringVar, PhotoImage, Tk, Canvas + + +def main(args): + root = Tk() + root.title("Munyal") + root.geometry("320x500") + + logo = PhotoImage(file="img/logo.png") + + host = StringVar() + host_field = Entry(root, textvariable=host, width=30) + + passwd = StringVar() + passwd_field = Entry(root, textvariable=passwd, show="*", width=30) + + folder = StringVar() + folder.set(os.path.join(os.getenv("HOME"), "Munyal")) + folder_field = Entry(root, textvariable=folder, width=30) + + connect = Button(root, text="Conectar", command=lambda: None, width=10) + + Label(root, image=logo).pack() + Label(root, text="MUNYAL", font=("", 30)).pack() + Label(root, text="").pack() + Label(root, text="Nombre del servidor").pack() + host_field.pack() + Label(root, text="").pack() + Label(root, text="ContraseƱa").pack() + passwd_field.pack() + Label(root, text="").pack() + Label(root, text="Carpeta a sincronizar").pack() + folder_field.pack() + Label(root, text="").pack() + connect.pack() + + root.mainloop() + + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv)) diff --git a/dir_to_json.py b/dir_to_json.py new file mode 100644 index 0000000..5f59b1a --- /dev/null +++ b/dir_to_json.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from hashlib import md5 + +import os +import json + + +def md5sum(filename): + try: + hash = md5() + with open(filename, "rb") as f: + for chunk in iter(lambda: f.read(128 * hash.block_size), b""): + hash.update(chunk) + return hash.hexdigest() + except: + return None + +def get_json(path): + out = [] + items = os.listdir(path) + try: + for item in items: + if item[0] != ".": + item_json = { + "name": item + } + route = os.path.join(path, item) + if os.path.isdir(route): + item_json["is_file"] = False + item_json["content"] = get_json(route) + elif os.path.isfile(route): + item_json["is_file"] = True + item_json["size"] = os.path.getsize(route) + item_json["last_modified"] = os.path.getmtime(route) + item_json["created_at"] = os.path.getctime(route) + checksum = md5sum(route) + if checksum: + item_json["checksum"] = checksum + else: + item = None + out.append(item_json) + except: + return get_json(path) + return out + +if __name__ == "__main__": + output = get_json("/media/kirbylife/DATOS/Proyectos/PyCharmProjects/Munyal/folder_test") + print(json.dumps(output, indent=4)) diff --git a/first_test.py b/first_test.py new file mode 100644 index 0000000..38d97ba --- /dev/null +++ b/first_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from compare_json import compare_json +from dir_to_json import get_json + +from copy import deepcopy +from time import sleep + +ORIGINAL = "/home/kirbylife/Proyectos/munyal_test/original" + +def main(args): + actual = get_json(ORIGINAL) + new = deepcopy(actual) + + while True: + delete, add = compare_json(deepcopy(actual), deepcopy(new)) + for item in delete: + if item.get("tag"): + if item.get("tag") == "update": + print("Actualizado el archivo {}".format(item.get("name"))) + else: + print("borrado el archivo {}".format(item.get("name"))) + + for item in add: + print("Agregado el archivo {}".format(item.get("name"))) + actual = deepcopy(new) + new = get_json(ORIGINAL) + return 0 + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv)) + + + + + + + + + diff --git a/http_server.py b/http_server.py new file mode 100644 index 0000000..fa9ce25 --- /dev/null +++ b/http_server.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from flask import Flask +from flask import request +from flask import jsonify + +import rethinkdb as r + +from random import randint +from time import time + +import json + +app = Flask(__name__) + +def md5sum(filename): + try: + hash = md5() + with open(filename, "rb") as f: + for chunk in iter(lambda: f.read(128 * hash.block_size), b""): + hash.update(chunk) + return hash.hexdigest() + except: + return None + +@app.route("/", methods=["GET"]) +def index(): + return(''' + <html> + <head> + <title>Munyal API</title> + </head> + <body> + <h1>Munyal private API</h1> + </body> + </html> + ''') + +@app.route("/upload", methods=["POST"]) +def upload(): + try: + r.connect( "localhost", 28015).repl() + cursor = r.table("changes") + + host = request.form.get("host") + action = request.form.get("action") + route = request.form.get("route") + obj = { + 'id' : str(time()).split('.')[0] + str(randint(1, 1000000)), + 'action': action, + 'route': route, + 'host': host + } + status = 'ok' + try: + cursor.insert(obj).run() + except: + status = 'error' + except: + status = 'error' + obj['status'] = status + return jsonify(obj) + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ab5f196ec4840c996b0ffaaa769535a46b0b35a8 GIT binary patch literal 42462 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 HSnT;9VqEC@ literal 0 HcmV?d00001 diff --git a/second_test.py b/second_test.py new file mode 100644 index 0000000..869acdd --- /dev/null +++ b/second_test.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from compare_json import compare_json +from dir_to_json import get_json + +from copy import deepcopy +from time import sleep +from requests import post + +import os +import socket +import json +import ftplib + +def need_deleted(items, route): + out = [] + for item in items: + if item.get("is_file"): + out.append({"action": "delete", "route": os.path.join(route, item.get('name'))}) + else: + if item.get('content'): + out = out + need_deleted(item.get("content"), os.path.join(route, item.get('name'))) + else: + out.append({"action": "delete_folder", "route": os.path.join(route, item.get('name'))}) + return out + +def need_added(items, route): + out = [] + for item in items: + if item.get("is_file"): + out.append({"action": "add", "route": os.path.join(route, item.get('name'))}) + else: + if item.get('content'): + out = out + need_added(item.get("content"), os.path.join(route, item.get('name'))) + else: + out.append({"action": "add_folder", "route": os.path.join(route, item.get('name'))}) + return out + +def get_changes(jsons, route=''): + delete, add = jsons + out = need_deleted(delete, route) + need_added(add, route) + return out + ''' + out = [] + + delete, add = jsons + for item in delete: + if item.get("is_file"): + + if item.get("tag"): + if item.get("tag") == "update": + out.append({"action": "update", "file": os.path.join(route, item.get('name'))}) + elif item.get("tag") == "delete":##### Caso hipotetico imposible ##### + if item.get("is_file"): + out.append({"action": "delete", "file": os.path.join(route, item.get('name'))}) + else: + out.append({"action": "delete_folder", "file": os.path.join(route, item.get('name'))}) + + else: + out.append({"action": "delete", "file": os.path.join(route, item.get('name'))}) + + out.append({"action": "delete", "file": os.path.join(route, item.get('name'))}) + else: + return out + ''' + +ORIGINAL = "/home/kirbylife/Proyectos/munyal_test/original" + +def main(args): + ftp = ftplib.FTP('localhost', 'munyal', '123') + actual = get_json(ORIGINAL) + new = deepcopy(actual) + switch = lambda x,o,d=None: o.get(x) if o.get(x) else d if d else lambda *args: None + while True: + sleep(1) + jsons = compare_json(deepcopy(actual), deepcopy(new)) + changes = get_changes(jsons) + for change in changes: + route = os.path.join(ORIGINAL, change['route']) + success = False + while not success: + # ~ try: + x = change['route'] + if change['action'] == 'add': + print("Agregar archivo") + with open(route, "rb") as f: + ftp.storbinary("STOR /" + x, f) + elif change['action'] == 'add_folder': + print("Agregar carpeta") + ftp.mkd(x) + elif change['action'] == 'delete': + print("Borrar archivo") + ftp.delete(x) + elif change['action'] == 'delete_folder': + print("Borrar carpeta") + ftp.rmd(x) + else: + print("Unexpected action") + r = post('http://127.0.0.1:5000/upload', data={ + 'host': socket.gethostname(), + 'action': change['action'], + 'route': change['route'] + } + ) + r = json.loads(r.text) + print(json.dumps(r, indent=4)) + success = r['status'] == 'ok' + # ~ except: + # ~ print("Error uploading, retrying again\n") + actual = deepcopy(new) + new = get_json(ORIGINAL) + return 0 + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv))