diff --git a/Service/FileTransferService.php b/Service/FileTransferService.php index 301c773..d5169c2 100644 --- a/Service/FileTransferService.php +++ b/Service/FileTransferService.php @@ -1,127 +1,204 @@ setName('transfer:file') - ->setDescription('Transfer a file') - ->addArgument( - 'targetserverid', - InputArgument::REQUIRED, - 'target server identifier') - ->addArgument( - 'sourcefile', - InputArgument::REQUIRED, - 'source file') - ->addArgument( - 'targetfile', - InputArgument::REQUIRED, - 'target file') - ->addOption('method', - 'm', - InputOption::VALUE_OPTIONAL, - "Determen if the service retreive files or push it to the server. Options: put,get", - FileTransferService::MODE_PUT) - ->addOption('ignore', - 'i', - InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, - '', - []) - ; + $this->config = $parameters; + $this->logger = $logger; + $this->logger->setComponent('FileTransfer'); + $this->mode = self::MODE_PUT; } - protected function execute(InputInterface $input, OutputInterface $output) + /** + * Set the mode where the service should be operating + * + * @param string $mode + */ + public function setMode(string $mode = self::MODE_PUT):void { + $this->mode = $mode; + } - $sourcefile = $input->getArgument('sourcefile'); - $targetfile = $input->getArgument('targetfile'); - $targetserverid = $input->getArgument('targetserverid'); + /** + * Returns the mode + * + * @return string + */ + public function getMode() + { + return $this->mode; + } - /** @var FileTransferService $service */ - $service = $this->getContainer()->get('FileTransferBundle\Service\FileTransferService'); - $service->setMode($input->getOption('method')); + public function getRemoteFiles($serverId, $source, $ignore = []): ?array + { + if ($this->mode === self::MODE_PUT) { + return null; + } - if ($service->getMode() === FileTransferService::MODE_GET) { - $files = $service->getRemoteFiles($targetserverid, '/PROD', $this->input->getOption('ignore', [])); + $selectedFiles = []; - if (is_array($files)) { - foreach ($files as $file) { - $service->transferFile( - $targetserverid, - $sourcefile . $file, - $targetfile . $file); - } - } + $sftp = $this->loginInSftp($serverId); + $files = $sftp->nlist($source); + + if (!$files) { + $e = "Directory can not be pulled from :" . $source; + $this->logger->error($e); } else { - if ($this->useDirectoryMode($sourcefile)) { - $this->transferDirectory($service, $targetserverid, $sourcefile, $targetfile); - } else { - $service->transferFile($targetserverid, $sourcefile, $targetfile); + foreach ($files as $file) { + + if (in_array($file, $ignore)) { + continue; + } + + $selectedFiles[] = DIRECTORY_SEPARATOR . $file; } } + + return $selectedFiles; + } + + public function transferFile($serverid, $sourcefile, $targetfile) + { + $sftp = $this->loginInSftp($serverid); + + $sftpFolderName = dirname($targetfile); + + $this->logger->debug("Sftp folder name is $sftpFolderName"); + + $this->checkIfDirectoryExists($sftp, $sftpFolderName); + + $this->changeToDirectory($sftp, $sftpFolderName); + + switch ($this->mode) { + case FileTransferService::MODE_PUT: + $this->putToServer($sftp, $targetfile, $sourcefile); + break; + case FileTransferService::MODE_GET: + $this->getFromServer($sftp, $targetfile, $sourcefile); + break; + default: + throw new \RuntimeException("There is no mode selected please use -m or --method"); + break; + } } /** - * Checks if the transfer is in directory mode + * Login in SFTP and give back the connection * - * @param string $source - * @param string $target - * @return bool + * @return SFTP */ - private function useDirectoryMode(string $source): bool + private function loginInSftp(string $serverid) { - if (is_dir($source)) { - return true; + list ($address, $username, $password) = $this->getCredentials($serverid); + + $sftp = new SFTP($address); + if (!$sftp->login($username, $password)) { + $e = "Sftp login failed for user " . $username; + $this->logger->error($e); + throw new \RuntimeException($e); } - return false; + return $sftp; } /** - * Transfers the a complete directory to a remote server + * @return array + */ + private function getCredentials(string $serverid) + { + if (isset($this->config['servers'][$serverid])) { + $configure = $this->config['servers'][$serverid]; + + return [ + $configure['address'], + $configure['username'], + $configure['password'] + ]; + } else { + $e = "Config not found for server id " . $serverid; + $this->logger->error($e); + throw new \RuntimeException($e); + } + } + /** + * Checks if a directory remotely exists * - * @param FileTransferService $service - * @param string $serverId - * @param string $source - * @param string $target + * @param SFTP $sftp + * @param string $sftpFolderName */ - private function transferDirectory(FileTransferService $service, string $serverId, string $source, string $target): void + private function checkIfDirectoryExists(SFTP $sftp, string $sftpFolderName): void { - $finder = new Finder(); - $finder->files()->in($source); - - /** @var ApplicationLogger $logger */ - $logger = $this->getContainer()->get('monolog.logger.admin'); - if (!$finder->hasResults()) { - $logger->notice('no files found', [ - 'component' => 'FileTransfer' - ]); - return; + if (!$sftp->file_exists($sftpFolderName)) { + if (!$sftp->mkdir($sftpFolderName, 0777)) { + $e = "Can't create $sftpFolderName directory. " . $sftp->getLastSFTPError(); + $this->logger->error($e); + throw new \RuntimeException($e); + } + } else { + $this->logger->debug("Directory exists $sftpFolderName"); } + } - foreach ($finder as $file) { - $destination = $target . $file->getFilename(); + /** + * Change to the correct directory on the server + * + * @param SFTP $sftp + * @param string $targetFile + * @param string $sourceFile + */ + private function changeToDirectory(SFTP $sftp, string $sftpFolderName): void + { + if (!$sftp->chdir($sftpFolderName)) { + $e = "Can't chdir to $sftpFolderName directory. " . $sftp->getLastSFTPError(); + $this->logger->error($e); + throw new \RuntimeException($e); + } + } - $service->transferFile( - $serverId, - $file, - $destination); + /** + * Upload the file to the server + * + * @param SFTP $sftp + * @param string $targetFile + * @param string $sourceFile + */ + private function putToServer(SFTP $sftp, string $targetFile, string $sourceFile): void + { + if (!$sftp->put($targetFile, $sourceFile, SFTP::SOURCE_LOCAL_FILE)) { + $e = "Couldn't send file to sftp. " . $sftp->getLastSFTPError(); + $this->logger->error($e); + throw new \RuntimeException($e); } } + /** + * Download the file from the remote server + * + * @param SFTP $sftp + * @param string $targetFile + * @param string $sourceFile + */ + private function getFromServer(SFTP $sftp, string $targetFile, string $sourceFile): void + { + if (!$sftp->get($sourceFile, $targetFile)) { + $e = "Couldn't get file from sftp. " . $sftp->getLastSFTPError(); + $this->logger->error($e); + throw new \RuntimeException($e); + } + } }