Source code for cmdbox.app.client

from pathlib import Path
from cmdbox.app import common, filer
from cmdbox.app.commons import convert, redis_client
from typing import Dict, Any, List, Tuple
import base64
import logging
import json


[docs] class Client(object): def __init__(self, logger:logging.Logger, redis_host:str = "localhost", redis_port:int = 6379, redis_password:str = None, svname:str = 'server'): """ Redisサーバーとの通信を行うクラス Args: logger (logging): ロガー redis_host (str, optional): Redisサーバーのホスト名. Defaults to "localhost". redis_port (int, optional): Redisサーバーのポート番号. Defaults to 6379. redis_password (str, optional): Redisサーバーのパスワード. Defaults to None. svname (str, optional): サーバーのサービス名. Defaults to 'server'. """ self.logger = logger if svname is None or svname == "": raise Exception("svname is empty.") if svname.find('-') >= 0: raise ValueError(f"Server name is invalid. '-' is not allowed. svname={svname}") self.redis_cli = redis_client.RedisClient(logger, host=redis_host, port=redis_port, password=redis_password, svname=svname) self.is_running = False def __exit__(self, a, b, c): pass
[docs] def stop_server(self, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ Redisサーバーを停止する Args: retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ res_json = self.redis_cli.send_cmd('stop_server', [], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json
[docs] def file_list(self, svpath:str, recursive:bool, scope:str="client", client_data:Path=None, fwpaths:List[str]=None, listregs:str="*", retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバー上のファイルリストを取得する Args: svpath (Path): サーバー上のファイルパス recursive (bool): 再帰的に取得するかどうか scope (str, optional): 参照先のスコープ. Defaults to "client". client_data (Path, optional): ローカルを参照させる場合のデータフォルダ. Defaults to None. fwpaths (List[str], optional): 範囲内かどうかを示すパスのリスト. Defaults to None. listregs (str, optional): リストアップするgrep条件. Defaults to "*". retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ if scope == "client": if client_data is not None: f = filer.Filer(client_data, self.logger) _, res_json = f.file_list(svpath, recursive, fwpaths, listregs) return res_json else: self.logger.warning(f"client_data is empty.") return dict(warn=f"client_data is empty.") elif scope == "current": f = filer.Filer(Path.cwd(), self.logger) _, res_json = f.file_list(svpath, recursive, fwpaths, listregs) return res_json elif scope == "server": payload = dict(svpath=svpath, recursive=recursive, fwpaths=fwpaths, listregs=listregs) payload_b64 = convert.str2b64str(json.dumps(payload, default=common.default_json_enc)) res_json = self.redis_cli.send_cmd('file_list', [payload_b64], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json else: self.logger.warning(f"scope is invalid. {scope}") return dict(warn=f"scope is invalid. {scope}")
[docs] def file_mkdir(self, svpath:str, scope:str="client", client_data:Path=None, fwpaths:List[str]=None, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバー上にディレクトリを作成する Args: svpath (Path): サーバー上のディレクトリパス scope (str, optional): 参照先のスコープ. Defaults to "client". client_data (Path, optional): ローカルを参照させる場合のデータフォルダ. Defaults to None. fwpaths (List[str], optional): 範囲内かどうかを示すパスのリスト. Defaults to None. retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ if scope == "client": if client_data is not None: f = filer.Filer(client_data, self.logger) _, res_json = f.file_mkdir(svpath, fwpaths) return res_json else: self.logger.warning(f"client_data is empty.") return dict(warn=f"client_data is empty.") elif scope == "current": f = filer.Filer(Path.cwd(), self.logger) _, res_json = f.file_mkdir(svpath, fwpaths) return res_json elif scope == "server": payload = dict(svpath=svpath, fwpaths=fwpaths) payload_b64 = convert.str2b64str(json.dumps(payload, default=common.default_json_enc)) res_json = self.redis_cli.send_cmd('file_mkdir', [payload_b64], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json else: self.logger.warning(f"scope is invalid. {scope}") return dict(warn=f"scope is invalid. {scope}")
[docs] def file_rmdir(self, svpath:str, scope:str="client", client_data:Path=None, fwpaths:List[str]=None, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバー上のディレクトリを削除する Args: svpath (Path): サーバー上のディレクトリパス scope (str, optional): 参照先のスコープ. Defaults to "client". client_data (Path, optional): ローカルを参照させる場合のデータフォルダ. Defaults to None. fwpaths (List[str], optional): 範囲内かどうかを示すパスのリスト. Defaults to None. retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ if scope == "client": if client_data is not None: f = filer.Filer(client_data, self.logger) _, res_json = f.file_rmdir(svpath, fwpaths) return res_json else: self.logger.warning(f"client_data is empty.") return dict(warn=f"client_data is empty.") elif scope == "current": f = filer.Filer(Path.cwd(), self.logger) _, res_json = f.file_rmdir(svpath, fwpaths) return res_json elif scope == "server": payload = dict(svpath=svpath, fwpaths=fwpaths) payload_b64 = convert.str2b64str(json.dumps(payload, default=common.default_json_enc)) res_json = self.redis_cli.send_cmd('file_rmdir', [payload_b64], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json else: self.logger.warning(f"scope is invalid. {scope}") return dict(warn=f"scope is invalid. {scope}")
[docs] def file_download(self, svpath:str, download_file:Path, scope:str="client", client_data:Path=None, fwpaths:List[str]=None, rpath:str="", img_thumbnail:float=0.0, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバー上のファイルをダウンロードする Args: svpath (Path): サーバー上のファイルパス download_file (Path): ローカルのファイルパス scope (str, optional): 参照先のスコープ. Defaults to "client". client_data (Path, optional): ローカルを参照させる場合のデータフォルダ. Defaults to None. fwpaths (List[str], optional): 範囲内かどうかを示すパスのリスト. Defaults to None. rpath (str, optional): リクエストパス. Defaults to "". img_thumbnail (float, optional): サムネイル画像のサイズ. Defaults to 0.0. retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: bytes: ダウンロードファイルの内容 """ if scope == "client": if client_data is not None: f = filer.Filer(client_data, self.logger) _, res_json = f.file_download(svpath, img_thumbnail, fwpaths) else: self.logger.warning(f"client_data is empty.") return dict(warn=f"client_data is empty.") elif scope == "current": f = filer.Filer(Path.cwd(), self.logger) _, res_json = f.file_download(svpath, img_thumbnail, fwpaths) elif scope == "server": payload = dict(svpath=svpath, img_thumbnail=img_thumbnail, fwpaths=fwpaths) payload_b64 = convert.str2b64str(json.dumps(payload, default=common.default_json_enc)) res_json = self.redis_cli.send_cmd('file_download', [payload_b64], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) else: self.logger.warning(f"scope is invalid. {scope}") return dict(warn=f"scope is invalid. {scope}") if "success" in res_json: res_json["success"]["rpath"] = rpath res_json["success"]["svpath"] = svpath if download_file is not None: if download_file.is_dir(): download_file = download_file / res_json["success"]["name"] if download_file.exists(): self.logger.warning(f"download_file {download_file} already exists.") return dict(warn=f"download_file {download_file} already exists.") def _wd(f): f.write(base64.b64decode(res_json["success"]["data"])) del res_json["success"]["data"] res_json["success"]["download_file"] = str(download_file.absolute()) common.save_file(download_file, _wd, mode='wb') return res_json
[docs] def file_upload(self, svpath:str, upload_file:Path, scope:str="client", client_data:Path=None, fwpaths:List[str]=None, mkdir:bool=False, orverwrite:bool=False, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバー上にファイルをアップロードする Args: svpath (Path): サーバー上のファイルパス upload_file (Path): ローカルのファイルパス scope (str, optional): 参照先のスコープ. Defaults to "client". mkdir (bool, optional): ディレクトリを作成するかどうか. Defaults to False. orverwrite (bool, optional): 上書きするかどうか. Defaults to False. client_data (Path, optional): ローカルを参照させる場合のデータフォルダ. Defaults to None. fwpaths (List[str], optional): 範囲内かどうかを示すパスのリスト. Defaults to None. retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ if upload_file is None: self.logger.warning(f"upload_file is empty.") return dict(warn=f"upload_file is empty.") if not upload_file.exists(): self.logger.warning(f"input_file {upload_file} does not exist.") return dict(warn=f"input_file {upload_file} does not exist.") if upload_file.is_dir(): self.logger.warning(f"input_file {upload_file} is directory.") return dict(warn=f"input_file {upload_file} is directory.") with open(upload_file, "rb") as f: if scope == "client": if client_data is not None: fi = filer.Filer(client_data, self.logger) _, res_json = fi.file_upload(svpath, upload_file.name, f.read(), mkdir, orverwrite, fwpaths) return res_json else: self.logger.warning(f"client_data is empty.") return dict(warn=f"client_data is empty.") elif scope == "current": fi = filer.Filer(Path.cwd(), self.logger) _, res_json = fi.file_upload(svpath, upload_file.name, f.read(), mkdir, orverwrite, fwpaths) return res_json elif scope == "server": payload = dict(svpath=svpath, file_name=upload_file.name, file_data=convert.bytes2b64str(f.read()), mkdir=mkdir, orverwrite=orverwrite, fwpaths=fwpaths) payload_b64 = convert.str2b64str(json.dumps(payload, default=common.default_json_enc)) res_json = self.redis_cli.send_cmd('file_upload', [payload_b64,], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json else: self.logger.warning(f"scope is invalid. {scope}") return dict(warn=f"scope is invalid. {scope}")
[docs] def file_remove(self, svpath:str, scope:str="client", client_data:Path = None, fwpaths:List[str]=None, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバー上のファイルを削除する Args: svpath (Path): サーバー上のファイルパス scope (str, optional): 参照先のスコープ. Defaults to "client". client_data (Path, optional): ローカルを参照させる場合のデータフォルダ. Defaults to None. fwpaths (List[str], optional): 範囲内かどうかを示すパスのリスト. Defaults to None. retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ if scope == "client": if client_data is not None: f = filer.Filer(client_data, self.logger) _, res_json = f.file_remove(svpath, fwpaths) return res_json else: self.logger.warning(f"client_data is empty.") return dict(warn=f"client_data is empty.") elif scope == "current": f = filer.Filer(Path.cwd(), self.logger) _, res_json = f.file_remove(svpath, fwpaths) return res_json elif scope == "server": payload = dict(svpath=svpath, fwpaths=fwpaths) payload_b64 = convert.str2b64str(json.dumps(payload, default=common.default_json_enc)) res_json = self.redis_cli.send_cmd('file_remove', [payload_b64], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json else: self.logger.warning(f"scope is invalid. {scope}") return dict(warn=f"scope is invalid. {scope}")
[docs] def file_copy(self, from_path:str, to_path:str, orverwrite:bool=False, from_fwpaths:List[str]=None, to_fwpaths:List[str]=None, scope:str="client", client_data:Path = None, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバー上のファイルをコピーする Args: from_path (Path): コピー元のファイルパス to_path (Path): コピー先のファイルパス orverwrite (bool, optional): 上書きするかどうか. Defaults to False. from_fwpaths (List[str], optional): 範囲内かどうかを示すパスのリスト. Defaults to None. to_fwpaths (List[str], optional): 範囲内かどうかを示すパスのリスト. Defaults to None. scope (str, optional): 参照先のスコープ. Defaults to "client". client_data (Path, optional): ローカルを参照させる場合のデータフォルダ. Defaults to None. retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ if scope == "client": if client_data is not None: f = filer.Filer(client_data, self.logger) _, res_json = f.file_copy(from_path, to_path, orverwrite, from_fwpaths, to_fwpaths) return res_json else: self.logger.warning(f"client_data is empty.") return dict(warn=f"client_data is empty.") elif scope == "current": f = filer.Filer(Path.cwd(), self.logger) _, res_json = f.file_copy(from_path, to_path, orverwrite, from_fwpaths, to_fwpaths) return res_json elif scope == "server": payload = dict(from_path=from_path, to_path=to_path, orverwrite=orverwrite, from_fwpaths=from_fwpaths, to_fwpaths=to_fwpaths) payload_b64 = convert.str2b64str(json.dumps(payload, default=common.default_json_enc)) res_json = self.redis_cli.send_cmd('file_copy', [payload_b64], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json else: self.logger.warning(f"scope is invalid. {scope}") return dict(warn=f"scope is invalid. {scope}")
[docs] def file_move(self, from_path:str, to_path:str, from_fwpaths:List[str]=None, to_fwpaths:List[str]=None, scope:str="client", client_data:Path=None, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバー上のファイルを移動する Args: from_path (Path): 移動元のファイルパス to_path (Path): 移動先のファイルパス from_fwpaths (List[str], optional): 移動元の範囲内かどうかを示すパスのリスト. Defaults to None. to_fwpaths (List[str], optional): 移動先の範囲内かどうかを示すパスのリスト. Defaults to None. scope (str, optional): 参照先のスコープ. Defaults to "client". client_data (Path, optional): ローカルを参照させる場合のデータフォルダ. Defaults to None. retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ if scope == "client": if client_data is not None: f = filer.Filer(client_data, self.logger) _, res_json = f.file_move(from_path, to_path, from_fwpaths, to_fwpaths) return res_json else: self.logger.warning(f"client_data is empty.") return dict(warn=f"client_data is empty.") elif scope == "current": f = filer.Filer(Path.cwd(), self.logger) _, res_json = f.file_move(from_path, to_path, from_fwpaths, to_fwpaths) return res_json elif scope == "server": payload = dict(from_path=from_path, to_path=to_path, from_fwpaths=from_fwpaths, to_fwpaths=to_fwpaths) payload_b64 = convert.str2b64str(json.dumps(payload, default=common.default_json_enc)) res_json = self.redis_cli.send_cmd('file_move', [payload_b64], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json else: self.logger.warning(f"scope is invalid. {scope}") return dict(warn=f"scope is invalid. {scope}")
[docs] def server_info(self, retry_count:int=3, retry_interval:int=5, timeout:int=60): """ サーバーの情報を取得する Args: retry_count (int, optional): リトライ回数. Defaults to 3. retry_interval (int, optional): リトライ間隔. Defaults to 5. timeout (int, optional): タイムアウト時間. Defaults to 60. Returns: dict: Redisサーバーからの応答 """ res_json = self.redis_cli.send_cmd('server_info', [], retry_count=retry_count, retry_interval=retry_interval, timeout=timeout) return res_json