#!/usr/bin/env python3 # -*- coding: utf-8 -*- from typing import Callable, Self, Optional, Any from paramiko import SFTPFile, SSHClient, SFTPClient, AutoAddPolicy from os import stat_result as StatResult from stat import S_ISDIR as is_directory, S_ISREG as is_file from Interfaces.Application.CXCVInterface import CXCVInterface from Interfaces.FilesInterface import FilesInterface from Managers.EventsManager import EventsManager from Models.HashModel import HashModel from Utils.Utils import Utils class SFTPFileDriver(FilesInterface): def __init__(self:Self, cxcv:Any, path:str, inputs:Optional[dict[str, Any|None]|list[Any|None]|tuple[Any|None, ...]] = None ) -> None: self.cxcv:CXCVInterface = cxcv self.__client:SSHClient = SSHClient() self.path:str = path self.chunk_size:int = self.cxcv.settings.get(("chunk_size", "default_chunk_size"), inputs, 4096) self.__file:SFTPFile|None = None self.mode:str = self.cxcv.settings.get("file_mode", inputs, "rb") self.__closed:bool = False self.on_load_chunk:EventsManager = EventsManager() callback:Callable[[bytes], bool]|None = Utils.get_value("on_load_chunk", inputs) self.__autoclose:bool = self.cxcv.settings.get("auto_close", inputs, True) self.reusable:bool = self.cxcv.settings.get("reusable", inputs, True) self.exists:bool = False self.is_file:bool = False self.is_directory:bool = False self.size:int = 0 self.hash:HashModel = None self.__sftp:SFTPClient stat:StatResult self.__client.set_missing_host_key_policy(AutoAddPolicy()) self.__client.connect( hostname = Utils.get_value(("host", "default_host", "default_sftp_host"), inputs, "localhost"), port = Utils.get_value(("port", "default_port", "default_sftp_port"), inputs, 22), username = Utils.get_value(("user", "default_user", "default_sftp_user"), inputs), password = Utils.get_value(("password", "default_password", "default_sftp_password"), inputs) ) self.__sftp = self.__client.open_sftp() try: stat = self.__sftp.stat(self.path) self.exists = True self.is_file = is_file(stat.st_mode) self.is_directory = is_directory(stat.st_mode) self.size = stat.st_size except Exception as exception: pass callback and self.on_load_chunk.add(callback) self.cxcv.settings.get("auto_open", inputs, True) and self.open() def open(self:Self, new_path:Optional[str] = None) -> Self: if new_path or self.reusable: if new_path: self.path = new_path if self.__file and not self.__closed: self.__file.close() self.__closed = False elif self.__file is not None: return self self.__file = self.__sftp.file(self.path, mode = self.mode) return self def close(self:Self) -> Self: if not self.__closed: self.__closed = True self.hash = None self.is_directory = False self.is_file = False self.exists = False self.size = 0 self.__file and self.__file.close() self.__sftp.close() self.__client.close() return self def load(self:Self, all:bool = False) -> bytes: data:bytes = self.__file.read(self.size if all else self.chunk_size) if data: self.on_load_chunk.execute(data) elif self.__autoclose: self.close() def save(self:Self, chunk:Optional[bytes|bool] = None) -> None: if chunk: self.__file.write(chunk) elif self.__autoclose: self.close() def list(self:Self) -> list[str]: return self.__sftp.listdir(self.path) if self.is_directory else [] def remove(self:Self) -> None: self.__sftp.remove(self.path) def reset(self:Self) -> Self: self.close() self.open() return self