diff --git a/seafile_client/__init__.py b/seafile_client/__init__.py new file mode 100644 index 0000000..67c78e1 --- /dev/null +++ b/seafile_client/__init__.py @@ -0,0 +1 @@ +from .client import SeafileClient \ No newline at end of file diff --git a/seafile_client/client.py b/seafile_client/client.py new file mode 100644 index 0000000..f084c61 --- /dev/null +++ b/seafile_client/client.py @@ -0,0 +1,82 @@ +import os +import subprocess +import time + +import requests + +from .misc import create_dir + +DEFAULT_USERNAME = "seafile" + + +class SeafileClient: + def __init__(self, host: str, port: int, user: str, passwd: str): + self.url = f"https://{host}:{port}" + self.user = user + self.password = passwd + self.__token = None + + def __str__(self): + return f"SeafileClient({self.user}@{self.url})" + + @property + def token(self): + if self.__token is None: + url = f"{self.url}/api2/auth-token/" + r = requests.post(url, data={"username": self.user, + "password": self.password}) + if r.status_code != 200: + raise RuntimeError(f"Can't get token: {r.text}") + self.__token = r.json()['token'] + return self.__token + + def get_lib_name(self, lib_id: str) -> str: + url = f"{self.url}/api2/repos/{lib_id}" + auth_header = {"Authorization": f"Token {self.token}"} + r = requests.get(url, headers=auth_header) + if r.status_code != 200: + raise RuntimeError(r.text) + return r.json()['name'] + + def sync_lib(self, lib_id: str, data_dir: str): + lib_name = self.get_lib_name(lib_id) + lib_dir = os.path.join(data_dir, lib_name.replace(' ', '_')) + create_dir(lib_dir) + cmd = ['seaf-cli', 'sync', + '-l', lib_id, + '-s', self.url, + '-d', lib_dir, + '-u', self.user, + '-p', self.password] + cmd = ' '.join(cmd) + subprocess.run(['su', '-', DEFAULT_USERNAME, '-c', cmd]) + + def get_status(self): + cmd = 'seaf-cli status' + out = subprocess.check_output(['su', '-', DEFAULT_USERNAME, '-c', cmd]) + out = out.decode().splitlines() + + statuses = dict() + for line in out: + if line.startswith('#') or not line.strip(): + continue + lib, status = line.split(sep='\t', maxsplit=1) + status = status.replace('\t', ' ') + statuses[lib] = status + return statuses + + def watch_status(self): + prev_status = dict() + while True: + time.sleep(5) + cur_status = self.get_status() + for folder, state in cur_status.items(): + if state != prev_status.get(folder): + print(f"Synced folder {folder}: {state}") + prev_status[folder] = cur_status[folder] + + +def start_seaf_daemon(): + cmd = 'seaf-cli start' + subprocess.run(['su', '-', DEFAULT_USERNAME, '-c', cmd]) + time.sleep(5) \ No newline at end of file diff --git a/seafile_client/misc.py b/seafile_client/misc.py new file mode 100644 index 0000000..78ffb12 --- /dev/null +++ b/seafile_client/misc.py @@ -0,0 +1,25 @@ +import os +import pwd +import subprocess + +from .client import DEFAULT_USERNAME + + +def setup_uid(uid: int, gid: int): + user_pwinfo = pwd.getpwnam(DEFAULT_USERNAME) + if user_pwinfo.pw_uid != uid or user_pwinfo.pw_gid != gid: + subprocess.call(["usermod", "-o", "-u", str(uid), "-g", str(gid), DEFAULT_USERNAME]) + + +def create_dir(dir_path: str): + if not os.path.exists(dir_path): + os.mkdir(dir_path) + user_pwinfo = pwd.getpwnam(DEFAULT_USERNAME) + os.chown(dir_path, user_pwinfo.pw_uid, user_pwinfo.pw_gid) + else: + if not os.path.isdir(dir_path): + raise RuntimeError(f"Data dir {dir_path} is not a directory") + + +def tail_f(fpath): + os.system(f"tail -f {fpath}") diff --git a/start.py b/start.py index f6a7f2b..2a17a20 100755 --- a/start.py +++ b/start.py @@ -3,107 +3,11 @@ import argparse import os import os.path -import pwd -import subprocess import sys -import time -import requests - -DEFAULT_USERNAME = "seafile" - - -def setup_uid(uid: int, gid: int): - user_pwinfo = pwd.getpwnam(DEFAULT_USERNAME) - if user_pwinfo.pw_uid != uid or user_pwinfo.pw_gid != gid: - subprocess.call(["usermod", "-o", "-u", str(uid), "-g", str(gid), DEFAULT_USERNAME]) - - -def start_seaf_daemon(): - cmd = 'seaf-cli start' - subprocess.run(['su', '-', DEFAULT_USERNAME, '-c', cmd]) - time.sleep(5) - - -def create_dir(dir_path: str): - if not os.path.exists(dir_path): - os.mkdir(dir_path) - user_pwinfo = pwd.getpwnam(DEFAULT_USERNAME) - os.chown(dir_path, user_pwinfo.pw_uid, user_pwinfo.pw_gid) - else: - if not os.path.isdir(dir_path): - raise RuntimeError(f"Data dir {dir_path} is not a directory") - - -def tail_f(fpath): - os.system(f"tail -f {fpath}") - - -class SeafileClient: - def __init__(self, host: str, port: int, user: str, passwd: str): - self.url = f"https://{host}:{port}" - self.user = user - self.password = passwd - self.__token = None - - def __str__(self): - return f"SeafileClient({self.user}@{self.url})" - - @property - def token(self): - if self.__token is None: - url = f"{self.url}/api2/auth-token/" - r = requests.post(url, data={"username": self.user, - "password": self.password}) - if r.status_code != 200: - raise RuntimeError(f"Can't get token: {r.text}") - self.__token = r.json()['token'] - return self.__token - - def get_lib_name(self, lib_id: str) -> str: - url = f"{self.url}/api2/repos/{lib_id}" - auth_header = {"Authorization": f"Token {self.token}"} - r = requests.get(url, headers=auth_header) - if r.status_code != 200: - raise RuntimeError(r.text) - return r.json()['name'] - - def sync_lib(self, lib_id: str, data_dir: str): - lib_name = self.get_lib_name(lib_id) - lib_dir = os.path.join(data_dir, lib_name.replace(' ', '_')) - create_dir(lib_dir) - cmd = ['seaf-cli', 'sync', - '-l', lib_id, - '-s', self.url, - '-d', lib_dir, - '-u', self.user, - '-p', self.password] - cmd = ' '.join(cmd) - subprocess.run(['su', '-', DEFAULT_USERNAME, '-c', cmd]) - - def get_status(self): - cmd = 'seaf-cli status' - out = subprocess.check_output(['su', '-', DEFAULT_USERNAME, '-c', cmd]) - out = out.decode().splitlines() - - statuses = dict() - for line in out: - if line.startswith('#') or not line.strip(): - continue - lib, status = line.split(sep='\t', maxsplit=1) - status = status.replace('\t', ' ') - statuses[lib] = status - return statuses - - def watch_status(self): - prev_status = dict() - while True: - time.sleep(5) - cur_status = self.get_status() - for folder, state in cur_status.items(): - if state != prev_status.get(folder): - print(f"Synced folder {folder}: {state}") - prev_status[folder] = cur_status[folder] +from seafile_client import SeafileClient +from seafile_client.client import start_seaf_daemon +from seafile_client.misc import setup_uid, create_dir def main():