contentmonster/classes/connection.py
2021-11-22 11:14:38 +01:00

106 lines
3.4 KiB
Python

import paramiko as pikuniku # :P
from paramiko.client import SSHClient
from io import BytesIO
import errno
import stat
class Connection:
def __init__(self, vessel):
self._vessel = vessel
self._client = SSHClient()
self._client.load_system_host_keys()
self._client.connect(vessel.address)
self._transport = self._client.get_transport()
self._transport.set_keepalive(10)
self._sftp = self._client.open_sftp()
def _exists(self, path):
try:
self._sftp.stat(str(path))
return True
except FileNotFoundError:
return False
def _isdir(self, path):
return stat.S_ISDIR(self._sftp.lstat(str(path)).st_mode)
def _mkdir(self, path):
return self._sftp.mkdir(str(path))
def _listdir(self, path=None):
return self._sftp.listdir(str(path) if path else None)
def _remove(self, path):
return self._sftp.remove(str(path))
def assertDirectories(self, directory):
for d in [directory, self._vessel.tempdir]:
if not self._exists(d):
self._mkdir(d)
elif not self._isdir(d):
raise ValueError(f"{d} exists but is not a directory on Vessel {self._vessel.name}!")
def assertChunkComplete(self, chunk, path=None):
path = path or self._vessel.tempdir / chunk.getTempName()
if self._exists(path):
_,o,_ = self._client.exec_command("sha256sum -b " + str(path))
o.channel.recv_exit_status()
if not o.readline().split()[0] == chunk.getHash():
self._remove(path)
else:
return True
return False
def pushChunk(self, chunk):
path = self._vessel.tempdir / chunk.getTempName()
flo = BytesIO(chunk.data)
self._sftp.putfo(flo, path, len(chunk.data))
def compileComplete(self, remotefile):
numchunks = remotefile.getStatus() + 1
files = " ".join([str(self._vessel.tempdir / f"{remotefile.file.uuid}_{i}.part") for i in range(numchunks)])
completefile = remotefile.file.getChunk(-1)
outname = completefile.getTempName()
outpath = self._vessel.tempdir / outname
_,o,_ = self._client.exec_command(f"cat {files} > {outpath}")
o.channel.recv_exit_status()
def assertComplete(self, remotefile, allow_retry=False):
completefile = remotefile.file.getChunk(-1)
outname = completefile.getTempName()
outpath = self._vessel.tempdir / outname
if not self._exists(outpath):
return False
if not self.assertChunkComplete(completefile):
if allow_retry:
self._remove(outpath)
else:
self.clearTempDir()
return False
return True
def moveComplete(self, remotefile):
completefile = remotefile.file.getChunk(-1)
destination = remotefile.getFullPath()
self._sftp.rename(str(self._vessel.tempdir / completefile.getTempName()), str(destination))
self._sftp.stat(str(destination))
return True
def getCurrentUploadUUID(self):
for f in self._listdir(self._vessel.tempdir):
if f.endswith(".part"):
return f.split("_")[0]
def clearTempDir(self):
for f in self._listdir(self._vessel.tempdir):
self._remove(self._vessel.tempdir / f)
def __del__(self):
self._client.close()