somewhat functioning flees client
This commit is contained in:
49
code/app.py
49
code/app.py
@@ -215,6 +215,30 @@ def send(name):
|
||||
return render_template('send.html',name=name)
|
||||
|
||||
|
||||
@app.route('/file/list/<name>/<token>', methods=['GET'])
|
||||
def file_list(name, token):
|
||||
(ok,share) = get_share(name, token = token)
|
||||
if not ok:
|
||||
return share
|
||||
files = []
|
||||
for file in iter_folder_files(share['path']):
|
||||
files.append(path2url(file))
|
||||
files.append("")
|
||||
return "\n".join(files), 200
|
||||
|
||||
|
||||
@app.route('/file/details/<name>/<token>', methods=['GET'])
|
||||
def file_details(name, token):
|
||||
(ok,share) = get_share(name, token = token)
|
||||
if not ok:
|
||||
return share
|
||||
files = []
|
||||
for file in iter_folder_files(share['path']):
|
||||
status = file_stat(share['path'],file)
|
||||
files.append(status)
|
||||
return jsonify(files), 200
|
||||
|
||||
|
||||
@app.route('/file/size/<name>/<token>/<path:filename>', methods=['GET'])
|
||||
def file_size(name, token, filename):
|
||||
(ok,share) = get_share(name, token = token)
|
||||
@@ -230,18 +254,6 @@ def file_size(name, token, filename):
|
||||
return str(size), 200
|
||||
|
||||
|
||||
@app.route('/file/list/<name>/<token>', methods=['GET'])
|
||||
def list_files(name, token):
|
||||
(ok,share) = get_share(name, token = token)
|
||||
if not ok:
|
||||
return share
|
||||
files = []
|
||||
for file in iter_folder_files(share['path']):
|
||||
files.append(path2url(file))
|
||||
files.append("")
|
||||
return "\n".join(files), 200
|
||||
|
||||
|
||||
@app.route('/list/<name>/<token>', methods=['GET'])
|
||||
@app.route('/list/<name>', methods=['GET'])
|
||||
def list_view(name, token = None):
|
||||
@@ -350,6 +362,19 @@ def download_zip(name, token = None):
|
||||
)
|
||||
|
||||
|
||||
@app.route('/script/client/<name>/<token>', methods=['GET'])
|
||||
def script_client(name = None, token = None):
|
||||
(ok,share) = get_share(name, token = token)
|
||||
if not ok:
|
||||
return share
|
||||
return render_template(
|
||||
"client.py",
|
||||
name = name,
|
||||
token = token,
|
||||
rooturl = request.url_root
|
||||
)
|
||||
|
||||
|
||||
@app.route('/script/upload/<name>/<token>', methods=['GET'])
|
||||
def script_upload(name = None, token = None):
|
||||
(ok,share) = get_share(name, token = token)
|
||||
|
||||
@@ -402,7 +402,7 @@ def print_rest_api_upload(config, share, token):
|
||||
share['name'],
|
||||
token
|
||||
))
|
||||
print("\nLink to upload multiple files to the share, splitting large files (default 512Mb):")
|
||||
print("\nLink to upload multiple files to the share, splitting large files:")
|
||||
print("\n# curl -s %s/script/upload_split/%s/%s | python - [-s split_size_in_Mb] file_to_upload.ext [second.file.ext]"%(
|
||||
config['public_url'],
|
||||
share['name'],
|
||||
|
||||
301
code/templates/client.py
Normal file
301
code/templates/client.py
Normal file
@@ -0,0 +1,301 @@
|
||||
#!/usr/bin/env python
|
||||
import argparse, sys, os, subprocess, time, re, json
|
||||
from subprocess import call, Popen, PIPE, STDOUT
|
||||
import threading
|
||||
import readline
|
||||
from tabulate import tabulate
|
||||
import glob
|
||||
from io import StringIO
|
||||
|
||||
ROOTURL="{{ rooturl }}"
|
||||
SHARE="{{ name }}"
|
||||
TOKEN="{{ token }}"
|
||||
|
||||
|
||||
class Completer(object):
|
||||
|
||||
def __init__(self, choices = []):
|
||||
self.choices = choices
|
||||
self.space = re.compile('.*\s+$', re.M)
|
||||
|
||||
def _listdir(self, path):
|
||||
"List directory 'root' appending the path separator to subdirs."
|
||||
files = []
|
||||
for name in os.listdir(path):
|
||||
file_path = os.path.join(path, name)
|
||||
if os.path.isdir(file_path):
|
||||
name += os.sep
|
||||
files.append(name)
|
||||
return files
|
||||
|
||||
def _complete_path(self, path=None):
|
||||
"Perform completion of filesystem path."
|
||||
if not path:
|
||||
return self._listdir('.')
|
||||
path = os.path.expanduser(path)
|
||||
dirname, rest = os.path.split(path)
|
||||
tmp = dirname if dirname else '.'
|
||||
res = [os.path.join(dirname, p)
|
||||
for p in self._listdir(tmp) if p.startswith(rest)]
|
||||
# more than one match, or single match which does not exist (typo)
|
||||
if len(res) > 1 or not os.path.exists(path):
|
||||
return res
|
||||
# resolved to a single directory, so return list of files below it
|
||||
if os.path.isdir(path):
|
||||
return [os.path.join(path, p) for p in self._listdir(path)]
|
||||
# exact file match terminates this completion
|
||||
return [path + ' ']
|
||||
|
||||
|
||||
def complete(self, text, state):
|
||||
"Generic readline completion entry point."
|
||||
buffer = readline.get_line_buffer()
|
||||
if len(self.choices) == 0:
|
||||
return (self._complete_path(buffer) + [None])[state]
|
||||
|
||||
# show all commands
|
||||
if len(buffer) == 0:
|
||||
return [c + ' ' for c in self.choices][state]
|
||||
# resolve command to the implementation function
|
||||
cmd = buffer.strip()
|
||||
results = [c + ' ' for c in self.choices if c.startswith(cmd)] + [None]
|
||||
return results[state]
|
||||
|
||||
|
||||
def download_file(file, opts):
|
||||
print("Download "+file['name'])
|
||||
cmd = [
|
||||
'curl','--create-dirs',
|
||||
'-o', file['name'],
|
||||
'%s%s/%s/%s/%s'%(
|
||||
opts.rooturl,
|
||||
"download",
|
||||
opts.share,
|
||||
opts.token,
|
||||
file['url']
|
||||
),
|
||||
]
|
||||
p = Popen(
|
||||
cmd,
|
||||
stderr = PIPE,
|
||||
)
|
||||
for char in iter(lambda: p.stderr.read(1), ''):
|
||||
if not char:
|
||||
return
|
||||
sys.stderr.write(char)
|
||||
sys.stderr.flush()
|
||||
return
|
||||
|
||||
|
||||
def menu(opts):
|
||||
commands = [
|
||||
'Download',
|
||||
'Upload'
|
||||
]
|
||||
print_title("Main")
|
||||
for i,command in enumerate(commands):
|
||||
print(" %d. %s"%( i+1, command, ))
|
||||
comp = Completer(choices = ["1","2"])
|
||||
readline.set_completer(comp.complete)
|
||||
choice = user_input("Number of action: ").strip()
|
||||
if choice == "1":
|
||||
menu_download(opts)
|
||||
if choice == "2":
|
||||
menu_upload(opts)
|
||||
if choice == "":
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def menu_download(opts):
|
||||
while True:
|
||||
print_title("Download files")
|
||||
files = json.loads(run_command("file/details", opts))
|
||||
file_table = []
|
||||
for f in files:
|
||||
file_table.append((f['name'], float(f['size'].replace(",","")), f['mtime']))
|
||||
print(tabulate(file_table, headers = ("Name", "Size [Mb]", "Modified")))
|
||||
name_list = [x['name'] for x in files]
|
||||
comp = Completer(choices = name_list)
|
||||
# we want to treat '/' as part of a word, so override the delimiters
|
||||
readline.set_completer(comp.complete)
|
||||
print("\n[Empty to return, * globs]")
|
||||
choice = user_input('Download file: ').strip()
|
||||
if choice == "":
|
||||
return
|
||||
if "*" in choice:
|
||||
choice = choice.replace('*','.*')
|
||||
choice_re = re.compile(choice)
|
||||
choices = [i for i,x in enumerate(name_list) if choice_re.match(x)]
|
||||
else:
|
||||
if choice not in name_list:
|
||||
print("No such file")
|
||||
continue
|
||||
choices = [ name_list.index(choice) ]
|
||||
for choice in choices:
|
||||
download_file(files[choice], opts)
|
||||
|
||||
|
||||
def menu_upload(opts):
|
||||
while True:
|
||||
print_title("Upload")
|
||||
comp = Completer(choices = [])
|
||||
# we want to treat '/' as part of a word, so override the delimiters
|
||||
|
||||
readline.set_completer(comp.complete)
|
||||
print("\n[Empty to return, * globs]")
|
||||
choice = user_input('Upload file: ').strip()
|
||||
if choice == "":
|
||||
return
|
||||
if "*" in choice:
|
||||
choices = glob.glob(choice)
|
||||
else:
|
||||
if not os.path.exists(choice):
|
||||
print("No such file")
|
||||
continue
|
||||
choices = [ choice ]
|
||||
for choice in choices:
|
||||
upload_file(choice, opts)
|
||||
|
||||
|
||||
def parse_options():
|
||||
parser = argparse.ArgumentParser(description='Flees client')
|
||||
parser.add_argument('-s', action="store", type=int, dest="split", default = 32,
|
||||
help = "Split size in megabytes [%(default)s]"
|
||||
)
|
||||
parser.add_argument('--rooturl', action="store", dest="rooturl",
|
||||
default = ROOTURL,
|
||||
help = "Address of Flees server [%(default)s]"
|
||||
)
|
||||
parser.add_argument('--share', action="store", dest="share",
|
||||
default = SHARE,
|
||||
help = "Name of Flees share [%(default)s]"
|
||||
)
|
||||
parser.add_argument('--token', action="store", dest="token",
|
||||
default = TOKEN,
|
||||
help = "API token for the share [%(default)s]"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def print_title(title):
|
||||
print("%s\n%s\n"%(
|
||||
title,
|
||||
"="*len(title)
|
||||
))
|
||||
|
||||
|
||||
def read_output(stream):
|
||||
for char in iter(lambda: stream.read(1), ''):
|
||||
if not char:
|
||||
break
|
||||
sys.stderr.write(char)
|
||||
sys.stderr.flush()
|
||||
stream.close()
|
||||
|
||||
|
||||
def run_command(command, opts):
|
||||
p = Popen(
|
||||
[
|
||||
'curl','-s',
|
||||
'%s%s/%s/%s'%(opts.rooturl, command, opts.share, opts.token)
|
||||
],
|
||||
stdout=PIPE,
|
||||
stderr=PIPE
|
||||
)
|
||||
stdout_data, stderr_data = p.communicate()
|
||||
return stdout_data
|
||||
|
||||
|
||||
def run_loop(opts):
|
||||
while True:
|
||||
menu(opts)
|
||||
|
||||
|
||||
def upload_file(file, opts):
|
||||
print("Upload "+file)
|
||||
p = Popen(
|
||||
"curl -s %s%s/%s/%s | python -u - -s %d %s"%(
|
||||
opts.rooturl,
|
||||
"script/upload_split",
|
||||
opts.share,
|
||||
opts.token,
|
||||
opts.split,
|
||||
file
|
||||
),
|
||||
stdout = PIPE,
|
||||
shell = True
|
||||
)
|
||||
read_output(p.stdout)
|
||||
return
|
||||
|
||||
|
||||
cmd1 = [
|
||||
'curl','-s',
|
||||
'%s%s/%s/%s'%(
|
||||
opts.rooturl,
|
||||
"script/upload_split",
|
||||
opts.share,
|
||||
opts.token,
|
||||
),
|
||||
]
|
||||
cmd2 = [
|
||||
'python', '-',
|
||||
'-s', str(opts.split),
|
||||
file
|
||||
]
|
||||
p1 = Popen(
|
||||
cmd1,
|
||||
stderr = PIPE,
|
||||
stdout = PIPE,
|
||||
)
|
||||
script, stderr = p1.communicate()
|
||||
p2 = Popen(
|
||||
cmd2,
|
||||
stdin = PIPE,
|
||||
stdout = PIPE,
|
||||
stderr = PIPE,
|
||||
bufsize = 1
|
||||
)
|
||||
p2.stdin.write(script)
|
||||
p2.stdin.close()
|
||||
for char in iter(lambda: p2.stderr.read(1), ''):
|
||||
if not char:
|
||||
break
|
||||
sys.stderr.write(char)
|
||||
sys.stderr.flush()
|
||||
|
||||
#~ read_output(p2.stdout)
|
||||
#~ tin = threading.Thread(
|
||||
#~ target=write_input, args=(p2.stdin, script)
|
||||
#~ )
|
||||
#~ tout = threading.Thread(
|
||||
#~ target=read_output, args=(p2.stdout,)
|
||||
#~ )
|
||||
#~ terr = threading.Thread(
|
||||
#~ target=read_output, args=(p2.stderr,)
|
||||
#~ )
|
||||
#~ for t in (tin, tout, terr):
|
||||
#~ t.daemon = True
|
||||
#~ t.start()
|
||||
#~ p2.wait()
|
||||
return
|
||||
|
||||
|
||||
def user_input(arg):
|
||||
try:
|
||||
return raw_input(arg)
|
||||
except NameError:
|
||||
return input(arg)
|
||||
|
||||
|
||||
def write_input(stream, string):
|
||||
stream.write(string)
|
||||
stream.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
readline.set_completer_delims(' \t\n;')
|
||||
readline.parse_and_bind("tab: complete")
|
||||
opts = parse_options()
|
||||
run_loop(opts)
|
||||
|
||||
Reference in New Issue
Block a user