Showing preview only (481K chars total). Download the full file or copy to clipboard to get everything.
Repository: linuxserver/davos
Branch: master
Commit: fd3a46bffa8d
Files: 184
Total size: 424.6 KB
Directory structure:
gitextract_1q48vioe/
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── conf/
│ ├── local/
│ │ ├── application.properties
│ │ └── log4j2.xml
│ └── release/
│ ├── application.properties
│ └── log4j2.xml
├── docs/
│ ├── Makefile
│ ├── make.bat
│ └── source/
│ ├── conf.py
│ ├── developers/
│ │ └── index.rst
│ ├── faq/
│ │ └── index.rst
│ ├── guides/
│ │ ├── appsettings.rst
│ │ ├── gettingstarted/
│ │ │ ├── hosts.rst
│ │ │ ├── index.rst
│ │ │ └── schedules.rst
│ │ ├── index.rst
│ │ └── installation.rst
│ ├── index.rst
│ ├── reference/
│ │ ├── api.rst
│ │ └── index.rst
│ └── requirements.txt
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── src/
│ ├── cucumber/
│ │ ├── java/
│ │ │ └── io/
│ │ │ └── linuxserver/
│ │ │ └── davos/
│ │ │ └── bdd/
│ │ │ ├── ClientStepDefs.java
│ │ │ ├── ScheduleStepDefs.java
│ │ │ ├── ServerStepDefs.java
│ │ │ └── helpers/
│ │ │ ├── FakeFTPServerFactory.java
│ │ │ ├── FakeSFTPServerFactory.java
│ │ │ └── Logging.java
│ │ └── resources/
│ │ ├── Client.feature
│ │ └── Schedule.feature
│ ├── main/
│ │ ├── java/
│ │ │ └── io/
│ │ │ └── linuxserver/
│ │ │ └── davos/
│ │ │ ├── DavosApplication.java
│ │ │ ├── Version.java
│ │ │ ├── converters/
│ │ │ │ ├── Converter.java
│ │ │ │ ├── HostConverter.java
│ │ │ │ └── ScheduleConverter.java
│ │ │ ├── delegation/
│ │ │ │ └── services/
│ │ │ │ ├── HostService.java
│ │ │ │ ├── HostServiceImpl.java
│ │ │ │ ├── ScheduleService.java
│ │ │ │ ├── ScheduleServiceImpl.java
│ │ │ │ ├── SettingsService.java
│ │ │ │ └── SettingsServiceImpl.java
│ │ │ ├── dto/
│ │ │ │ ├── ActionDTO.java
│ │ │ │ ├── FTPFileDTO.java
│ │ │ │ ├── FilterDTO.java
│ │ │ │ ├── HostDTO.java
│ │ │ │ ├── ScheduleDTO.java
│ │ │ │ └── ScheduleProcessResponse.java
│ │ │ ├── exception/
│ │ │ │ ├── HostInUseException.java
│ │ │ │ ├── ScheduleAlreadyRunningException.java
│ │ │ │ └── ScheduleNotRunningException.java
│ │ │ ├── logging/
│ │ │ │ └── LoggingManager.java
│ │ │ ├── persistence/
│ │ │ │ ├── dao/
│ │ │ │ │ ├── DefaultHostDAO.java
│ │ │ │ │ ├── DefaultScheduleDAO.java
│ │ │ │ │ ├── HostDAO.java
│ │ │ │ │ └── ScheduleDAO.java
│ │ │ │ ├── model/
│ │ │ │ │ ├── ActionModel.java
│ │ │ │ │ ├── FilterModel.java
│ │ │ │ │ ├── HostModel.java
│ │ │ │ │ ├── ScannedFileModel.java
│ │ │ │ │ └── ScheduleModel.java
│ │ │ │ └── repository/
│ │ │ │ ├── HostRepository.java
│ │ │ │ └── ScheduleRepository.java
│ │ │ ├── schedule/
│ │ │ │ ├── RunnableSchedule.java
│ │ │ │ ├── RunningSchedule.java
│ │ │ │ ├── ScheduleConfiguration.java
│ │ │ │ ├── ScheduleConfigurationFactory.java
│ │ │ │ ├── ScheduleExecutor.java
│ │ │ │ └── workflow/
│ │ │ │ ├── ConnectWorkflowStep.java
│ │ │ │ ├── DisconnectWorkflowStep.java
│ │ │ │ ├── DownloadFilesWorkflowStep.java
│ │ │ │ ├── FilterFilesWorkflowStep.java
│ │ │ │ ├── ScheduleWorkflow.java
│ │ │ │ ├── WorkflowStep.java
│ │ │ │ ├── actions/
│ │ │ │ │ ├── HttpAPICallAction.java
│ │ │ │ │ ├── MoveFileAction.java
│ │ │ │ │ ├── PostDownloadAction.java
│ │ │ │ │ ├── PostDownloadExecution.java
│ │ │ │ │ ├── PushbulletNotifyAction.java
│ │ │ │ │ └── SNSNotifyAction.java
│ │ │ │ ├── filter/
│ │ │ │ │ ├── FileFilter.java
│ │ │ │ │ ├── ReferentialFileFilter.java
│ │ │ │ │ └── TemporalFileFilter.java
│ │ │ │ └── transfer/
│ │ │ │ ├── FTPTransfer.java
│ │ │ │ ├── FilesAndFoldersTranferStrategy.java
│ │ │ │ ├── FilesOnlyTransferStrategy.java
│ │ │ │ ├── TransferStrategy.java
│ │ │ │ └── TransferStrategyFactory.java
│ │ │ ├── transfer/
│ │ │ │ └── ftp/
│ │ │ │ ├── FTPFile.java
│ │ │ │ ├── FileTransferType.java
│ │ │ │ ├── TransferProtocol.java
│ │ │ │ ├── client/
│ │ │ │ │ ├── Client.java
│ │ │ │ │ ├── ClientFactory.java
│ │ │ │ │ ├── FTPClient.java
│ │ │ │ │ ├── FTPSClient.java
│ │ │ │ │ ├── SFTPClient.java
│ │ │ │ │ └── UserCredentials.java
│ │ │ │ ├── connection/
│ │ │ │ │ ├── Connection.java
│ │ │ │ │ ├── ConnectionFactory.java
│ │ │ │ │ ├── FTPConnection.java
│ │ │ │ │ ├── SFTPConnection.java
│ │ │ │ │ └── progress/
│ │ │ │ │ ├── ListenerFactory.java
│ │ │ │ │ ├── ProgressListener.java
│ │ │ │ │ └── SFTPProgressListener.java
│ │ │ │ └── exception/
│ │ │ │ ├── ClientConnectionException.java
│ │ │ │ ├── ClientDisconnectException.java
│ │ │ │ ├── DeleteFileException.java
│ │ │ │ ├── DownloadFailedException.java
│ │ │ │ ├── FTPException.java
│ │ │ │ └── FileListingException.java
│ │ │ ├── util/
│ │ │ │ ├── FileStreamFactory.java
│ │ │ │ ├── FileUtils.java
│ │ │ │ └── PatternBuilder.java
│ │ │ └── web/
│ │ │ ├── API.java
│ │ │ ├── Filter.java
│ │ │ ├── Host.java
│ │ │ ├── Notifications.java
│ │ │ ├── Pushbullet.java
│ │ │ ├── SNS.java
│ │ │ ├── Schedule.java
│ │ │ ├── ScheduleCommand.java
│ │ │ ├── Settings.java
│ │ │ ├── Transfer.java
│ │ │ ├── VersionChecker.java
│ │ │ ├── controller/
│ │ │ │ ├── APIController.java
│ │ │ │ ├── FragmentController.java
│ │ │ │ ├── ViewController.java
│ │ │ │ └── response/
│ │ │ │ ├── APIResponse.java
│ │ │ │ └── APIResponseBuilder.java
│ │ │ └── selectors/
│ │ │ ├── IntervalSelector.java
│ │ │ ├── LogLevelSelector.java
│ │ │ ├── MethodSelector.java
│ │ │ ├── ProtocolSelector.java
│ │ │ └── TransferSelector.java
│ │ └── resources/
│ │ ├── static/
│ │ │ ├── browserconfig.xml
│ │ │ ├── css/
│ │ │ │ └── davos.css
│ │ │ ├── js/
│ │ │ │ └── davos.js
│ │ │ └── manifest.json
│ │ └── templates/
│ │ ├── fragments/
│ │ │ ├── api.html
│ │ │ ├── filter.html
│ │ │ ├── header.html
│ │ │ ├── pushbullet.html
│ │ │ ├── sns.html
│ │ │ └── transfers.html
│ │ └── v2/
│ │ ├── edit-host.html
│ │ ├── edit-schedule.html
│ │ ├── hosts.html
│ │ ├── schedules.html
│ │ └── settings.html
│ └── test/
│ └── java/
│ └── io/
│ └── linuxserver/
│ └── davos/
│ ├── VersionTest.java
│ ├── delegation/
│ │ └── services/
│ │ ├── ScheduleServiceImplTest.java
│ │ └── SettingsServiceImplTest.java
│ ├── persistence/
│ │ └── dao/
│ │ └── DefaultScheduleDAOTest.java
│ ├── schedule/
│ │ ├── ScheduleConfigurationFactoryTest.java
│ │ ├── ScheduleExecutorTest.java
│ │ └── workflow/
│ │ ├── ConnectWorkflowStepTest.java
│ │ ├── DisconnectWorkflowStepTest.java
│ │ ├── DownloadFilesWorkflowStepTest.java
│ │ ├── FilterFilesWorkflowStepTest.java
│ │ ├── actions/
│ │ │ ├── HttpAPICallActionTest.java
│ │ │ ├── MoveFileActionTest.java
│ │ │ └── PushbulletNotifyActionTest.java
│ │ ├── filter/
│ │ │ └── ReferentialFileFilterTest.java
│ │ └── transfer/
│ │ ├── FilesAndFoldersTranferStrategyTest.java
│ │ ├── FilesOnlyTransferStrategyTest.java
│ │ ├── TransferStrategyFactoryTest.java
│ │ └── TransferStrategyTest.java
│ ├── transfer/
│ │ └── ftp/
│ │ ├── client/
│ │ │ ├── ClientFactoryTest.java
│ │ │ ├── FTPClientTest.java
│ │ │ ├── FTPSClientTest.java
│ │ │ └── SFTPClientTest.java
│ │ └── connection/
│ │ ├── FTPConnectionTest.java
│ │ ├── SFTPConnectionTest.java
│ │ └── progress/
│ │ ├── ListenerFactoryTest.java
│ │ ├── ProgressListenerTest.java
│ │ └── SFTPProgressListenerTest.java
│ ├── util/
│ │ └── PatternBuilderTest.java
│ └── web/
│ └── controller/
│ ├── APIControllerTest.java
│ └── ViewControllerTest.java
└── version.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.gradle
*.sw?
.#*
*#
*~
/build
/code
.classpath
.project
.settings
.metadata
.factorypath
.recommenders
bin
build
lib/
target
.factorypath
.springBeans
interpolated*.xml
dependency-reduced-pom.xml
build.log
_site/
.*.md.html
manifest.yml
MANIFEST.MF
settings.xml
activemq-data
overridedb.*
*.iml
*.ipr
*.iws
.idea
.DS_Store
.factorypath
davos.log
src/main/resources/application.properties
src/main/resources/log4j2.xml
.vscode/
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015 LinuxServer.io
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# davos
[](http://ci.linuxserver.io/job/Software/job/Davos/job/davos_10_Unit_Tests/) [](http://davos.readthedocs.io/en/latest)
davos is an FTP download automation tool that allows you to scan various FTP servers for files you are interested in. This can be used to configure file feeds as part of a wider workflow.
# Why use davos?
A fair number of services still rely on "file-drops" to transport data from place to place. A common practice is to configure a cron job to periodically trigger FTP/SFTP programs to download those files. _davos_ is relatively similar, only it also adds a web UI to the whole process, making the management of these schedules easier.
# How it works
## Hosts
All periodic scans (Schedules) require a host to connect to. These can be added individually:

## Schedules
Each schedule contains all of the required information pertaining to the files it is interested in. This includes the host it needs to connect to, where to look for the files, where to download them, and how often:

It is also possible to limit what the schedule downloads by applying filters to each scan. _davos_ will only download files that match its list of given filters. If no filters are applied to a schedule, all files will be downloaded. Each schedule also keeps an internal record of what it scanned in the previous run, so it won't download the same file twice.

Once each file has been downloaded, _davos_ can also notify you via Pushbullet, as well as sending downstream requests to other services. This is particularly useful if another service makes use of the file _davos_ has just downloaded.

## Running
Finally, schedules can be started or stopped at any point, using the schedules listing UI:

# Changelog
- **2.2.2**
- Updated log4j dependency to 2.16.0, accounting for CVE-2021-44228
- **2.2.1**
- Fixed bug where lastRunTime got reset whenever a change was made to a schedule.
- General refactoring of code, plus added unit tests.
- Allow $filename resolution in URLs of API calls.
- **2.2.0**
- The filter pattern matcher now resolves '*' to zero or more characters, rather than one or more.
- The scanned items list can now be cleared.
- Added a Last Run field to the scanned items modal.
- Included [readthedocs](https://davos.readthedocs.io) documentation!
- Added SNS capability to notifications area
- Updated FTPS connections to run over Explicit TLS, rather than Implicit SSL
- This may or may not break existing schedules that use FTPS prior to 2.2.0.
- Improved some areas of DEBUG logging
- Schedules page now automatically updates when files are downloading
- Added identity file authentication for SFTP connections
- Included a version checker to help prompt users when a new version is available
- **Full disclosure**: This makes a GET request to GitHub to ascertain the latest release version.
- **2.1.2**
- Fixed NaN bug caused by empty files (Div/0)
- Fixed recursive delete issue for directories in FTP and SFTP connections.
- **2.1.1**
- Fixed primitive issue on Schedule model for new fields
- **2.1.0**
- Mandatory filtering allows schedules to only download files when at least one filter has been set.
- Form validation on Hosts and Schedule pages
- New theme
- Inverse filtering allows schedules to download files that DO NOT match provided filters.
- "Test Connection" button added to Hosts page
- Schedules can now delete the remote copy of each file once the download has completed. This is separate to the Post-download actions.
- New intervals: "Every minute" and "Every 5 minutes"
================================================
FILE: build.gradle
================================================
import java.util.regex.Matcher;
buildscript {
ext {
springBootVersion = '1.4.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath('io.spring.gradle:dependency-management-plugin:0.6.1.RELEASE')
}
}
plugins {
id "com.github.samueltbrown.cucumber" version "0.9"
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
jar {
baseName = 'davos'
version = file('version.txt').text.trim()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
configurations {
all*.exclude module : 'spring-boot-starter-logging'
bddTestCompile
testCompile.extendsFrom bddTestCompile
}
sourceSets {
bbdTest {
java { srcDir 'src/cucumber/java' }
resources { srcDir 'src/cucumber/resources' }
compileClasspath += test.output
}
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-thymeleaf'
compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'org.springframework.boot:spring-boot-starter-jdbc'
compile 'org.apache.logging.log4j:log4j-api:2.16.0'
compile 'org.apache.logging.log4j:log4j-core:2.16.0'
compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.16.0'
compile 'com.jcraft:jsch:0.1.50'
compile 'joda-time:joda-time:2.3'
compile 'commons-net:commons-net:3.3'
compile 'commons-io:commons-io:2.4'
compile 'org.apache.commons:commons-lang3:3.4'
compile 'com.amazonaws:aws-java-sdk-sns:1.11.167'
runtime 'com.h2database:h2'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'org.assertj:assertj-core:3.2.0'
testCompile 'org.mockito:mockito-all:1.9.5'
testCompile 'junit:junit:4.11'
bddTestCompile 'org.mockftpserver:MockFtpServer:2.6'
bddTestCompile 'org.apache.sshd:sshd-core:1.4.0'
bddTestCompile 'info.cukes:cucumber-java:1.2.4'
cucumberCompile 'info.cukes:cucumber-java:1.2.4'
}
eclipse {
classpath {
containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.14'
}
task updateBuildVersion << {
Matcher matcher = file('version.txt').text.trim() =~ /(.+)\.(.+)\.(.+)$/
if (matcher.find()) {
String major = matcher.group(1)
String minor = matcher.group(2)
String patch = matcher.group(3).trim()
int nextBuild = Integer.valueOf(patch) + 1
String updatedVersion = "${major}.${minor}.${nextBuild}"
file('version.txt').text = "${updatedVersion}\n"
}
}
task copyConfig(type: Copy) {
def location = project.hasProperty('env') ? "$env" : 'local'
from "conf/${location}"
into "src/main/resources/"
}
cucumber {
jvmOptions {
maxHeapSize = '512m'
environment 'ENV', 'staging'
}
}
build.dependsOn copyConfig
build.mustRunAfter copyConfig
================================================
FILE: conf/local/application.properties
================================================
davos.version=2.2.2
================================================
FILE: conf/local/log4j2.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} - %5p - [%c{1}] - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="io.linuxserver" level="debug" additivity="false">
<AppenderRef ref="Console" />
</Logger>
<Logger name="org.thymeleaf" level="warn" additivity="false">
<AppenderRef ref="Console" />
</Logger>
<Logger name="org.springframework" level="info" additivity="false">
<AppenderRef ref="Console" />
</Logger>
<Root level="info">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
================================================
FILE: conf/release/application.properties
================================================
spring.datasource.url=jdbc:h2:file:/config/db/davos2
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
davos.version=2.2.2
================================================
FILE: conf/release/log4j2.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<RollingFile name="File" fileName="/config/logs/davos.log" filePattern="/config/logs/${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} - %5p - [%c{1}] - %msg%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="io.linuxserver" level="info" additivity="false">
<AppenderRef ref="File" />
</Logger>
<Logger name="org.thymeleaf" level="warn" additivity="false">
<AppenderRef ref="File" />
</Logger>
<Logger name="org.springframework" level="error" additivity="false">
<AppenderRef ref="File" />
</Logger>
<Root level="warn">
<AppenderRef ref="File" />
</Root>
</Loggers>
</Configuration>
================================================
FILE: docs/Makefile
================================================
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = python -msphinx
SPHINXPROJ = davos
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
================================================
FILE: docs/make.bat
================================================
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=python -msphinx
)
set SOURCEDIR=source
set BUILDDIR=build
set SPHINXPROJ=davos
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The Sphinx module was not found. Make sure you have Sphinx installed,
echo.then set the SPHINXBUILD environment variable to point to the full
echo.path of the 'sphinx-build' executable. Alternatively you may add the
echo.Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
================================================
FILE: docs/source/conf.py
================================================
# -*- coding: utf-8 -*-
#
# davos documentation build configuration file, created by
# sphinx-quickstart on Sat Jul 29 08:01:32 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'davos'
copyright = u'2017, Josh Stark'
author = u'Josh Stark'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'2.2'
# The full version, including alpha/beta/rc tags.
release = u'2.2.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
#html_theme = 'alabaster'
import sphinx_rtd_theme
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
'donate.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'davosdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'davos.tex', u'davos Documentation',
u'Josh Stark', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'davos', u'davos Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'davos', u'davos Documentation',
author, 'davos', 'One line description of project.',
'Miscellaneous'),
]
================================================
FILE: docs/source/developers/index.rst
================================================
##########
Developers
##########
If you wish to contribute to davos (and help me tidy up some of its rather messy code!), you
will need to be able to build and run it locally. davos is written almost completely in
Java using the Spring Framework, utilising the Thymeleaf rendering engine. The project is
unit and integration tested using jUnit and Cucumber JVM, respectively.
*****
Setup
*****
Download and install the `Java 8 JDK <http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html>`_.
I'd also recommend using `Spring Tool Suite (STS) <https://spring.io/tools/sts/all>`_ as it is a prebuilt version of Eclipse IDE with all of the necessary
plugins installed for working with a Spring application.
********
Building
********
.. note:: You do not need to pre-install Gradle for this application as it comes with Gradle Wrapper, which does all the work for you.
To build the application, use Gradle:
.. code-block:: text
./gradlew clean build -Penv={release|local}
This will download all necessary dependencies, run tests, then package up the application.
The resulting .jar file will be in ``build/libs``. If you pass through a ``-Penv=release`` when
running this command, the packaged application will use the config under ``conf/release``, which
tells davos to use a file-based database. By default (i.e. if you do not pass this switch
through), it will use the ``conf/local`` configuration, which makes use of an in-memory database.
***************
Running the app
***************
It is recommended to build the app first before running, so you know your latest
changes are built:
.. code-block:: text
./gradlew clean build && java -jar build/libs/davos-2.2.0.jar
***********
Development
***********
Classpath
---------
When using Eclipse (or STS), a separate Gradle command is required in order to update
the project's classpath files so Eclipse is aware of the downloaded dependencies:
.. code-block:: text
./gradlew cleanEcipse eclipse
Code Structure
--------------
The code of davos is split in to four main sections:
``src/main/java``
The core functional code. This contains all logic for the workflow, API,
connectivity, and object persistence (database).
``src/main/resources``
The front-end code, including all JavaScript, CSS, images, and Thymeleaf
templates.
``src/test/java``
All unit tests for the core code
``src/cucumber/java``
Integration test code. This is separate to the main project code and
does not get packaged in to the released application.
Running Tests
-------------
To run all unit tests, use Gradle:
.. code-block:: text
./gradlew test
To run all integration tests:
.. code-block:: text
./gradlew cucumber
Managing the version
--------------------
The version of the application is referenced in three files:
* ``version.txt`` in the project root directory
* ``conf/local/application.properties`` as a property called ``davos.version``
* ``conf/release/application.properties`` as a property called ``davos.version``
All three of these need to be updated if you are changing the version number.
================================================
FILE: docs/source/faq/index.rst
================================================
###
FAQ
###
**********************************
Can davos be used to upload files?
**********************************
No, davos only downloads files. There are currently no plans on implementing the ability
to upload files as this will require a rework of the schedule workflow engine.
******************************
How many schedules can I have?
******************************
There is no theoretical limit to the number of schedules you can have. davos creates
an initial thread pool of 10 worker threads, but this gets extended if more than 10
schedules are created.
**************************
How many hosts can I have?
**************************
Unlimited.
********************************************
Are host credentials hashed in the database?
********************************************
No, all host usernames and passwords are stored in plain text in the H2 database. This
is because the application needs to query the hosts table every time a schedule runs,
and would have no way to compare a hash with a valid password.
***************************************************
How do I use an identity file for SFTP connections?
***************************************************
On the Host configuration page for your Host, make sure **Use Identity File** is checked. Then
enter the absolute path of the identity file. If you're running davos in a Docker container (recommended),
the value of this should be some thing like "/config/id_rsa", assuming you are using an SSH private key called
"id_rsa" and have placed it in your mapped host directory on your machine.
Any form of private identity is applicable, for example if your host server uses .pem files
for authentication, use "/config/my_identity.pem".
.. note:: Remember, davos can't see files outside of its ``/download`` and ``/config`` directories when running in a Docker container. So remember to place your identity file(s) in the mapped directory on the host (e.g. ``/home/user/davos``).
***************************************************************
I've just updated davos. The application is behaving strangely.
***************************************************************
Some version updates include changes to the JavaScript sources for the website side
of the application. Modern browsers like Chrome tend to cache these types of sources for
the sake of performance. It is likely your browser has not re-cached the latest version of
the JavaScript code.
To remedy this, hard-refresh the app: ``CTRL`` + ``F5``.
****************************************
How can I use SNS to notify me by email?
****************************************
To use SNS, you'll need an Amazon AWS Account. Once set up, you should go to **Services -> Simple Notification Service**,
then **Create topic**. For Topic name, enter something like "davos-notifications", and click **Create topic**. The first
thing you'll notice is that it has generated a **Topic ARN**. You'll need this for the notification configuration later.
Now create a subscription to your topic by clicking on **Create subscription**, chosing "Email" as the Protocol, and your
preferred email address as the Endpoint. Click **Create subscription**. You'll receive an email asking you to confirm
the subscription request.
Once your topic has been configured, you should create an IAM User that can publish messages to it. It is this user's
credentials that davos needs to perform the publish.
Go to **Services -> IAM**, then **Users**. Click **Add user**. For User name, enter something sensible, then select "Programmatic access"
as the Access Type. Click **Next: Permissions**. This user should only have permission to publish to this topic,
nothing more. So, under "Add user to group", click **Create group**, and then **Create policy**.
.. note:: A user can be in many groups. Groups can have many policies. A policy is a set of permissions for access to various things in AWS.
You should be directed to the policy creation tool. Select the Policy Generator and set the following:
Effect
Allow
AWS Service
Amazon SNS
Actions
Publish
Amazon Resource Name (ARN)
{YOUR_TOPIC_ARN}
Then click **Add Statement**. You should see it added underneath. Click **Next Step**. The generated policy will be shown
to you on screen (it's formatted as JSON, and contains a ``Statement`` array). Update the Policy Name to something
sensible (e.g. "DavosTopicPublishAccess") then click **Create Policy**. You'll be redirected back to the IAM
console, but you can close this.
Go back to the previous tab and under the Filter, type in the name of the policy you just created. Select it. Now, for the
Group name, give it a sensible name (e.g. DavosNotifications), and click **Create group**. The group should now be selected under
the IAM user console. Click **Next: Review**, make sure you're happy, and then click **Create user**.
You should see a table showing the user's Access key ID and Secret access key. You'll need these for the SNS configuration
in davos, so keep them safe somewhere (you can download a .csv with the credentials in).
.. warning:: The Secret access key will only be shown once in the console, so make sure you store it somewhere safe.
================================================
FILE: docs/source/guides/appsettings.rst
================================================
############
App Settings
############
Under **Settings -> App Settings**, you can configure the log level that davos
will output to its log file.
*******
Logging
*******
All logs are written to ``davos.log``, located in the ``/config/logs`` directory.
When mapping the ``/config`` directory in the container to a host directory, logs
will be made available in that host directory.
The log level can be changed at any time while the application is running. The available
levels are:
* DEBUG
* INFO
* WARN
* ERROR
The higher the level (``DEBUG`` is lowest, ``ERROR`` is highest), the fewer logs will be
written. By default, davos logs at ``INFO`` level. If you are experiencing issues
with davos and wish to understand the area of failure, change the level to ``DEBUG``.
Under this setting, the most logs will be written.
.. warning:: When setting the log level to ``DEBUG``, any secure credentials used in connections to the FTP host, or notification systems **will** be logged.
================================================
FILE: docs/source/guides/gettingstarted/hosts.rst
================================================
#####
Hosts
#####
A Host configuration provides one or more Schedules with information pertaining
to the FTP server to connect to when scanning for files. They are separate to the
Schedule configuration to allow multiple Schedules to use the same Host configuration
without the need for having to input the same data multiple times.
Under **Settings -> New Host**, you will be prompted to enter all of the relevant
information.
Name *[REQUIRED]*
The friendly name for this Host. This is what will be visible when creating a
schedule, so make it indicative of the Host you're making.
Protocol
Which type of connection to be made. This has no bearing on how you configure
the host, but will direct davos to build the specific client when connecting.
Host Address *[REQUIRED]*
The IP address (or hostname) of the server.
Port
FTP and FTPS are usually on ``21``, while SFTP is usually on ``22``. If your
server has been configured to run on a separate port, this is where you
reference it.
Username *[REQUIRED]*
Name of the user to connect as.
Password
Password of the user to connect as.
Use Identity File
Only available when ``SFTP`` is selected. Choose this if the SFTP server
requires an identity file to authenticate the user.
Identity File
Displayed when ``Use Identity File`` is checked, replacing the ``Password`` field. Enter
the location of the file.
.. note:: The location of the identity file will be relative to the container's filesystem, so should ideally be under ``/config`` as this is the directory exposed by the Docker volume mapping.
It is also possible to create, manage, and delete a Host via the HTTP API. See :doc:`../../reference/api` for more details.
================================================
FILE: docs/source/guides/gettingstarted/index.rst
================================================
###############
Getting Started
###############
This section aims to help you understand how davos is pieced together, and shows
you how it can be configured to meet your needs. It is recommended that you follow
the below guides.
.. toctree::
:maxdepth: 1
hosts
schedules
************
How it works
************
The Schedules in davos are powered by a basic workflow engine that runs a series
of steps to ensure each run processes files properly. The order of this
workflow is as follows:
1. Connect to the host.
2. List all files in the provided remote directory.
3. Filter all files in the remote directory so only the relevant ones remain.
4. Remove any files that have been previously scanned.
5. For each matched file, download it. Once downloaded, run any actions required by the schedule.
6. Store the list of scanned files against the Schedule.
7. Disconnect.
There is no theoretical limit to the number of schedules you can have running at
the same time, however it is advised you keep it below 10, as memory usage can
become quite high.
================================================
FILE: docs/source/guides/gettingstarted/schedules.rst
================================================
#########
Schedules
#########
A Schedule is the configuration that tells davos when to run, where to connect, what
to look for, and what to do once it has finished downloading. Schedules are the heart
of davos and are powered by its workflow engine.
To create a new Schedule, go to **Settings -> New Schedule**. Schedules are split into
multiple sections, each with their own part to play in the process.
*******
General
*******
This defines the metadata and connection information of the Schedule. The **General** section
allows you to name the Schedule, as well as define how often it should run, and where files
should be managed.
Name *[REQUIRED]*
The name of the Schedule. This should be relevant to the task this schedule
is performing. E.g. "Nightly Feed"
Interval
How often the schedule should run. The rate at which the schedule runs begins
when the schedule is started for the first time. So, if it is started at 14:05,
with an interval of "Every 30 minutes", it will run again at 14:35, then 15:05, and
so on.
.. note:: If you change the interval for an already running Schedule, you'll need to restart it before the change takes effect.
..
Host
The Host configuration to use for this Schedule. It will default to the first
Host in the list. You cannot create a Schedule if no Hosts have been created.
Host Directory *[REQUIRED]*
This is the directory on the host (relative to the connection entry point) that
the Schedule should use for file scanning. Absolute paths are also compliant.
Local Directory *[REQUIRED]*
The directory where this schedule should place file downloads.
.. note :: The local directory must be relative to the container's filesystem, so should be under ``/download``.
..
Transfer Type
This setting will inform the Schedule whether or not it should only download
matching files (``FILE``), or if it should also scan matching directories (``RECURSIVE``). This can be useful
if the server contains sub-directories that may match in a scan, but should not be
downloaded.
Start Automatically
If checked, the Schedule will automatically start when davos is started. Useful if
you have a restart policy enabled in Docker and your machine requires a restart.
*********
Filtering
*********
This is a process that allows you to narrow down file scanning so only relevant
files are processed. Filters can be exceptionally useful for host directories that
are used by multiple processes or contain large numbers of files.
Mandatory
If checked, the Schedule will only consider scanning files if at least one filter has been
defined. If checked and no filters are defined, nothing will be scanned, so nothing
will be downloaded.
Invert
The default behaviour is to match all files on the host with the defined filters. Checking
this option will invert that behaviour, so all files *not* matching the defined filters
will be downloaded.
Filters
A list of strings that will be used to scan the host directory. Each file on the host is compared to
this list - if it matches at least one filter, it will be downloaded. Filters can also be wildcarded
using ``?`` (single character) and ``*`` (multiple characters).
For example, for a file called "my_file_name.txt":
.. code-block:: text
my?file?name.txt = MATCH
my*name.txt = MATCH
my_file.name.txt = NO MATCH
*file_name* = MATCH
*file_name = NO MATCH
***************
File Management
***************
davos also provides a way to tidy processed files upon completion. You can choose to
either delete the file remotely once downloaded (effectively making it a *move* operation),
and you can also move the file locally.
Delete from Host
If checked, all matched and downloaded files will be deleted from the Host. This
logic will run after each individual download has completed.
.. warning :: If the FTP user does not have permission to delete files on the Host, this step will fail and the Schedule will cancel the current run. A future run of the Schedule will skip all files previously scanned.
..
Move Downloaded File
The location to move each successfully downloaded file. This will occur after each individual
download has completed. A common use-case for this feature is to separate in-progress files with
completed files (i.e. ``/download/doing`` and ``/download/done``).
.. note :: The "move to" directory must be relative to the container's filesystem, so should be under ``/download``. Advanced users may create additional volume mappings if need be.
.. note :: If davos is unable to move the file, it will remain in its originating directory, and will continue on to the Schedule's next step without failure.
******************
Downstream Actions
******************
One of the unique aspects of davos in respect to FTP management is its ability to create hooks in to other
applications that may be interested in the downloaded files. This may be useful when
the download action is part of a wider workflow that must be continued outside of the scope
of davos.
Actions defined against a Schedule will run for each individually downloaded file *after*
the File Management step previously mentioned has run.
There are two types of Downstream Action: *Notifications* and *API Calls*.
Notifications
=============
Notifications are useful if you'd like to know whenever davos has successfully downloaded
a file. Generally speaking, no further action is taken after a notification is sent,
but SNS may be configured to include a subscriber to a topic that performs a further action.
.. note:: There is no limit to the number of notifications you can have.
Pushbullet
----------
You will need an account with `Pushbullet <https://www.pushbullet.com/>`_ in order to use this feature.
In your Pushbullet account, create an Access Token.
Access Token
Your Pushbullet account's access token. This will be used to authenticate
notification push requests to the Pushbullet API.
Amazon SNS
-------------------------
You will need an `Amazon AWS <https://aws.amazon.com/>`_ account to use this feature.
Topic Arn
The Amazon Resource Name for an SNS Topic created under your AWS account. This
will be the topic that notifications are sent to.
Region
The region that the topic was created under. While regions are not mandatory for
Topic Arns, this will be used to authenticate your account and create an SNS
client in the correct region.
Access Key
The access key for an IAM User under your AWS account.
Secret Access Key
The second half of authentication with AWS. This is the secret key for the same
IAM User.
.. warning:: Be careful with IAM User permissions! You should create a new IAM User with permissions only to publish messages to your notification topic, nothing more! See :doc:`../../faq/index` for more details on best practice regarding IAM Users.
API Calls
=========
API Calls are a great way to create hooks in to other applications via their own HTTP API.
URL
The URL of the API you wish to call
Method
Available options are *GET*, *POST*, *PUT* and *DELETE*
Content-Type
Informs the target API what type of body you're sending (if any), e.g. "application/json"
Message Body
The request payload being sent to the target API
.. note:: If you need to reference the downloaded file in an HTTP request, use **$filename**. This will resolve to the file or folder that was matched and subsequently downloaded.
================================================
FILE: docs/source/guides/index.rst
================================================
######
Guides
######
This section will run you through the aspects of the application itself, including installation,
first time use, and the concept of schedules (what they consist of), hosts, and how they tie together.
.. toctree::
:maxdepth: 1
installation
gettingstarted/index
appsettings
================================================
FILE: docs/source/guides/installation.rst
================================================
############
Installation
############
.. note :: davos has been written with `Docker <https://www.docker.com/>`_ at the forefront regarding installation and deployment. This means that you should consider using the pre-built Docker image that `LinuxServer have provided <https://github.com/linuxserver/docker-davos>`_ for this application.
***********
With Docker
***********
This is the recommended method of installation and deployment.
Install Docker
--------------
Firstly, you'll need to install `Docker <https://www.docker.com/>`_, a container engine that is used to
fire up user-space virtual containers. I recommend using `Docker's official guide <https://docs.docker.com/engine/installation/>`_ on installing the latest version of Docker CE on your machine,
as the steps differ depending on your platform.
Build the container
===================
Create a new container from LinuxServer's image.
.. code-block:: text
docker create \
--name=davos \
-v <path to config>:/config \
-v <path to downloads folder>:/download
-e PGID=<gid> -e PUID=<uid> \
-p 8080:8080 \
linuxserver/davos
Params
------
* ``<path to config>``
The folder on your machine where davos will place its configuration and log files.
Typically this will be somewhere like ``/home/me/davos``, but it can be anywhere.
* ``<path to downloads folder>``
The folder on your machine that davos can download files to. This is the volume mount
point that davos is aware of for all file downloads.
* ``<uid>``
The id of the user you'd like davos to run as. All files downloaded by davos will be owned by this user.
* ``<gid>``
The id of the group you'd like to attribute to the user davos runs as. All files downloaded by davos will be owned by this group.
.. warning:: Docker will run all containers as ``root`` by default. Omitting ``PUID`` and ``PGID`` is not recommended.
Run the container
=================
Once the container has been created, you can run it.
.. code-block:: text
docker start davos
After about 30 seconds, the application will be running and will be accessible on ``http://localhost:8080``. If you are running
davos on a remote server, substitute ``localhost`` with the server's IP address.
**************
Without Docker
**************
This is not the recommended method of installation and deployment, but has the potential for being the most configurable and flexible.
Davos does not have any prebuilt binaries, so you'll need to get the source and build it yourself (another reason to use Docker instead).
Get the source
--------------
.. code-block:: text
wget https://github.com/linuxserver/davos/archive/LatestRelease.zip
unzip LatestRelease.zip -d davos
Configure the application
-------------------------
By default, davos is configured to place all of its configuration in ``/config``, which may
not be preferable if you're running the application on bare metal. Firstly, reconfigure davos
to use your own defined directory for its database.
In ``conf/release/application.properties``, change ``spring.datasource.url``, e.g.:
.. code-block:: text
spring.datasource.url=jdbc:h2:file:/home/me/davos
You'll also need to do the same in ``conf/release/log4j2.xml``, this time for the appender:
.. code-block:: xml
<RollingFile name="File" fileName="/home/me/davos/logs/davos.log" filePattern="/config/logs/${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log">
Build davos
-----------
.. note:: davos requires the `Java 8 SDK <http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html>`_ to build.
Once you've updated the configuration locations, you can build the binary.
.. code-block:: text
./gradlew build -Penv=release
This will create "davos-|release|.jar" in ``build/libs``. You should move this somewhere more fitting for an executable (``/var/lib``, for example).
It may also be worth renaming the .jar to "davos.jar", although this is not necessary.
Run davos
---------
.. note:: davos requires the `Java 8 JRE <http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html>`_ to build. This is not required if you already have the SDK installed.
To run the application, run the following command:
.. code-block:: text
java -jar davos.jar
================================================
FILE: docs/source/index.rst
================================================
##############################
davos: FTP Download Automation
##############################
This is the documentation for `davos <https://github.com/linuxserver/davos>`_, a web-based tool for
automating and managing file downloads over FTP, FTPS and SFTP. Davos was born from the idea that
even today, FTP still has relevance in many different markets, but there weren't many web-based
solutions that provided an easy way to manage the movement of files (outside of a command line cron job)
from one place to another.
For those new to davos, look through the :doc:`guides/installation` and :doc:`guides/gettingstarted/index` guides.
They will run you though how to get and set up davos for the first time.
davos also provides a basic HTTP API that can be used to hook in to the application to manage things like
schedules, hosts, filters, and even to stop or start individual schedules.
.. toctree::
:maxdepth: 2
:caption: Contents
guides/index
reference/index
faq/index
developers/index
================================================
FILE: docs/source/reference/api.rst
================================================
###
API
###
davos provides an HTTP API that exposes Schedules and Hosts so they can be managed
outside the scope of the web application. This API is also used by the web application's
AJAX calls.
.. warning:: This API is completely unauthenticated, so anyone on your network can use this
*********
/schedule
*********
POST
----
Creates a single Schedule.
.. code-block:: text
POST /api/v2/schedule HTTP 1.0
Host: localhost:8080
Content-Type: application/json
Accept: application/json
{
"name": String,
"interval": Integer,
"host": Integer,
"hostDirectory": String,
"localDirectory": String,
"transferType": String [ FILE | RECURSIVE ],
"automatic": Boolean,
"moveFileTo": String,
"filtersMandatory": Boolean,
"invertFilters": Boolean,
"deleteHostFile": Boolean,
"filters": [
{
"value": String
}
],
"notifications": {
"pushbullet": [
{
"apiKey": String
}
],
"sns": [
{
"topicArn": String,
"region": String,
"accessKey": String,
"secretAccessKey": String
}
]
},
"apis": [
{
"url": String,
"method": String [ POST | GET | PUT | DELETE ],
"contentType": String,
"body": String
}
]
}
For more information regarding what each field represents, see the :doc:`../guides/gettingstarted/schedules` documentation
in :doc:`../guides/gettingstarted/index`.
Response
========
See: :ref:`Schedule Response Syntax <schedule-response>`.
**************
/schedule/{id}
**************
GET
---
Retrieves a single Schedule based on the supplied ``{id}``.
.. code-block:: text
GET /api/v2/schedule/{id} HTTP 1.0
Host: localhost:8080
Accept: application/json
Response
========
See: :ref:`Schedule Response Syntax <schedule-response>`.
PUT
---
Updates a single Schedule based on the given ``{id}``. All fields must be supplied, even if only a subset is
being updated. Use a GET to first obtain the most up-to-date payload before performing
a PUT.
.. code-block:: text
PUT /api/v2/schedule/{id} HTTP 1.0
Host: localhost:8080
Content-Type: application/json
Accept: application/json
{
"name": String,
"interval": Integer,
"host": Integer,
"hostDirectory": String,
"localDirectory": String,
"transferType": String [ FILE | RECURSIVE ],
"automatic": Boolean,
"moveFileTo": String,
"filtersMandatory": Boolean,
"invertFilters": Boolean,
"deleteHostFile": Boolean,
"filters": [
{
"id": Integer,
"value": String
}
],
"notifications": {
"pushbullet": [
{
"id": Integer,
"apiKey": String
}
],
"sns": [
{
"id": Integer,
"topicArn": String,
"region": String,
"accessKey": String,
"secretAccessKey": String
}
]
},
"apis": [
{
"url": String,
"method": String [ POST | GET | PUT | DELETE ],
"contentType": String,
"body": String
}
]
}
.. note:: If you are updating a listed object, you must provide the object's ``id``. If you do not, the API will remove the old reference and create a new one. To add a new item to the list, provide the new item (without an ``id``) alongside the existing one.
Response
========
See: :ref:`Schedule Response Syntax <schedule-response>`.
DELETE
------
Deletes a single Schedule with the given ``{id}``.
.. code-block:: text
DELETE /api/v2/schedule/{id} HTTP 1.0
Host: localhost:8080
Accept: application/json
Response
========
.. code-block:: javascript
{
"status": String [ OK | Failed ],
"body": String
}
***************************
/schedule/{id}/scannedFiles
***************************
DELETE
------
Clears all items in the given Schedule's ``lastScannedFiles``.
.. code-block:: text
DELETE /api/v2/schedule/{id}/scannedFiles HTTP 1.0
Host: localhost:8080
Accept: application/json
Response
========
.. code-block:: javascript
{
"status": String [ OK | Failed ],
"body": String
}
**********************
/schedule/{id}/execute
**********************
POST
----
Starts/Stops an existing Schedule.
.. code-block:: text
POST /api/v2/schedule/{id}/execute
Host: localhost:8080
Content-Type: application/json
Accept: application/json
{
"command": String [ START | STOP ]
}
Response
========
.. code-block:: javascript
{
"status": String [ OK | Failed ],
"body": String
}
*****
/host
*****
POST
----
Creates a new Host.
.. code-block:: text
POST /api/v2/host
Host: localhost:8080
Content-Type: application/json
Accept: application/json
{
"name": String,
"address": String,
"port": Integer,
"protocol": String [ FTP | FTPS | SFTP ],
"username": String,
"password": String,
"identityFile": String,
"identityFileEnabled": Boolean
}
.. note:: If ``identityFileEnabled`` is set to TRUE, you must also provide ``identityFile``, otherwise provide ``password``.
**********
/host/{id}
**********
GET
---
Retrieves a single Host based on the given ``{id}``.
.. code-block:: text
GET /api/v2/host/{id}
Host: localhost:8080
Accept: application/json
Response
========
See: :ref:`Host Response Syntax <host-response>`.
PUT
---
Updates a Host with the given ``{id}``.
.. code-block:: text
POST /api/v2/host/{id}
Host: localhost:8080
Content-Type: application/json
Accept: application/json
{
"name": String,
"address": String,
"port": Integer,
"protocol": String [ FTP | FTPS | SFTP ],
"username": String,
"password": String,
"identityFile": String,
"identityFileEnabled": Boolean
}
.. note:: If ``identityFileEnabled`` is set to TRUE, you must also provide ``identityFile``, otherwise provide ``password``.
Response
========
See: :ref:`Host Response Syntax <host-response>`.
DELETE
------
Deletes a single Host with the given ``{id}``.
.. code-block:: text
DELETE /api/v2/host/{id} HTTP 1.0
Host: localhost:8080
Accept: application/json
Response
========
.. code-block:: javascript
{
"status": String [ OK | Failure ],
"body": String
}
.. warning:: If the Host you are attempting to delete is being used by an active Schedule, the DELETE call will fail.
***************
/testConnection
***************
POST
----
Allows you to assert whether or not the provided payload contains valid Host information.
.. code-block:: text
POST /api/v2/testConnection
Host: localhost:8080
Content-Type: application/json
{
"id": Integer,
"name": String,
"address": String,
"port": Integer,
"protocol": String [ FTP | FTPS | SFTP ],
"username": String,
"password": String,
"identityFile": String,
"identityFileEnabled": Boolean
}
Response
========
.. code-block:: javascript
{
"status": String [ OK | Failed ],
"body": String
}
*************
/settings/log
*************
POST
----
Changes the logging level of the application's core code. Unlike other POST calls,
there is no payload body. The level is passed in as a request parameter.
level
The level to change the logging to. Available options are DEBUG, INFO, WARN, ERROR, FATAL
.. code-block:: text
POST /api/v2/settings/log?level={LEVEL}
Host: localhost:8080
Accept: application/json
Response
========
.. code-block:: javascript
{
"status": String [ OK | Failed ],
"body": String
}
*********
Responses
*********
.. _schedule-response:
Schedule Response Syntax
------------------------
.. code-block:: javascript
{
"status": String [ OK ],
"body": {
"id": Integer,
"name": String,
"interval": Integer,
"host": Integer,
"hostDirectory": String,
"localDirectory": String,
"transferType": String [ FILE | RECURSIVE ],
"automatic": Boolean,
"moveFileTo": String,
"running": Boolean,
"filtersMandatory": Boolean,
"invertFilters": Boolean,
"lastRunTime": String,
"deleteHostFile": Boolean,
"lastScannedFiles": [
String
],
"filters": [
{
"id": Integer,
"value": String
}
],
"notifications": {
"pushbullet": [
{
"id": Integer,
"apiKey": String
}
],
"sns": [
{
"id": Integer,
"topicArn": String,
"region": String,
"accessKey": String,
"secretAccessKey": String
}
]
},
"transfers": [
{
"fileName": String,
"fileSize": Integer,
"directory": Boolean,
"progress": {
"percentageComplete": Double,
"transferSpeed": Double
},
"status": String [ DOWNLOADING | SKIPPED | PENDING | FINISHED ]
}
],
"apis": [
{
"id": Integer,
"url": String,
"method": String [ POST | GET | PUT | DELETE ],
"contentType": String,
"body": String
}
]
}
}
.. note:: ``running``, ``lastScannedFiles``, ``lastRunTime`` and ``transfers`` are immutable metadata fields and can't be used in PUT or POST requests. If supplied, they will be ignored.
..
host
References the ``id`` of the linked host.
running
Descibes whether or not the Schedule is running.
lastRunTime
The time recorded when the Schedule last *finished* running.
lastScannedFiles
A list of Strings that represent the files/folders found in the last run of the
schedule.
transfers
A list of transfer objects that describe all files being actioned. This list
will only be populated when the Schedule is running and is actively downloading.
.. _host-response:
Host Response Syntax
--------------------
Success
=======
.. code-block:: javascript
{
"status": String [ OK ],
"body": {
"id": Integer,
"name": String,
"address": String,
"port": Integer,
"protocol": String [ FTP | FTPS | SFTP ],
"username": String,
"password": String,
"identityFile": String,
"identityFileEnabled": Boolean
}
}
Failure
=======
.. code-block:: javascript
{
"status": String [ Failed ],
"body": String
}
================================================
FILE: docs/source/reference/index.rst
================================================
#########
Reference
#########
.. toctree::
:maxdepth: 1
api
================================================
FILE: docs/source/requirements.txt
================================================
sphinx_rtd_theme
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Nov 11 19:22:20 GMT 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: src/cucumber/java/io/linuxserver/davos/bdd/ClientStepDefs.java
================================================
package io.linuxserver.davos.bdd;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.util.List;
import org.apache.commons.io.FileUtils;
import cucumber.api.java.After;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.linuxserver.davos.bdd.helpers.FakeFTPServerFactory;
import io.linuxserver.davos.bdd.helpers.FakeSFTPServerFactory;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.client.Client;
import io.linuxserver.davos.transfer.ftp.client.FTPClient;
import io.linuxserver.davos.transfer.ftp.client.SFTPClient;
import io.linuxserver.davos.transfer.ftp.client.UserCredentials;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
import io.linuxserver.davos.transfer.ftp.connection.progress.ProgressListener;
public class ClientStepDefs {
private static final String TMP = FileUtils.getTempDirectoryPath();
private Connection connection;
private Client client;
private ProgressListener progressListener;
@After("@Client")
public void after() {
client.disconnect();
}
@When("^davos connects to the server$")
public void davos_connects_to_the_server() throws Throwable {
client = new FTPClient();
client.setCredentials(new UserCredentials("user", "password"));
client.setHost("localhost");
client.setPort(FakeFTPServerFactory.getPort());
connection = client.connect();
}
@When("^davos connects to the SFTP server$")
public void davos_connects_to_the_SFTP_server() throws Throwable {
client = new SFTPClient();
client.setCredentials(new UserCredentials("user", "password"));
client.setHost("localhost");
client.setPort(FakeSFTPServerFactory.getPort());
connection = client.connect();
}
@When("^deletes an SFTP directory$")
public void deletes_an_SFTP_directory() throws Throwable {
connection.deleteRemoteFile(new FTPFile("toDelete", 0, "/", 0, true));
}
@Then("^the SFTP directory is deleted on the server$")
public void the_SFTP_directory_is_deleted_on_the_server() throws Throwable {
assertThat(new File(TMP + "/toDelete").exists()).isFalse();
}
@Then("^listing the files will show the correct files$")
public void listing_the_files_will_show_the_correct_files() throws Throwable {
List<FTPFile> files = connection.listFiles("/tmp");
assertThat(files).hasSize(3);
assertThat(files.get(0).getName()).isEqualTo("file3.txt");
assertThat(files.get(1).getName()).isEqualTo("file2.txt");
assertThat(files.get(2).getName()).isEqualTo("file1.txt");
}
@When("^downloads a file$")
public void downloads_a_file() throws Throwable {
connection.download(new FTPFile("file2.txt", "hello world".getBytes().length, "/tmp/", 0, false), TMP);
}
@Then("^the file is located in the specified local directory$")
public void the_file_is_located_in_the_specified_local_directory() throws Throwable {
File file = new File(TMP + "/file2.txt");
assertThat(file.exists()).isTrue();
file.delete();
}
@When("^initialises a Progress Listener for that connection$")
public void initialises_a_Progress_Listener_for_that_connection() throws Throwable {
progressListener = new CountingFTPProgressListener();
connection.setProgressListener(progressListener);
}
@Then("^the Progress Listener will have its values updated$")
public void the_Progress_Listener_will_have_its_values_updated() throws Throwable {
assertThat(progressListener.getProgress()).isEqualTo(100);
assertThat(((CountingFTPProgressListener) progressListener).getTimesCalled()).isEqualTo(11);
}
@When("^deletes a directory$")
public void deletes_a_directory() throws Throwable {
connection.deleteRemoteFile(new FTPFile("toDelete", 0, "/tmp", 0, true));
}
@Then("^the directory is deleted on the server$")
public void the_directory_is_deleted_on_the_server() throws Throwable {
assertThat(FakeFTPServerFactory.checkFileExists("/tmp/toDelete")).isFalse();
}
class CountingFTPProgressListener extends ProgressListener {
int timesCalled;
@Override
public void setBytesWritten(long byteCount) {
super.setBytesWritten(byteCount);
timesCalled++;
}
public int getTimesCalled() {
return timesCalled;
}
}
}
================================================
FILE: src/cucumber/java/io/linuxserver/davos/bdd/ScheduleStepDefs.java
================================================
package io.linuxserver.davos.bdd;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.util.List;
import org.apache.commons.io.FileUtils;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.linuxserver.davos.bdd.helpers.FakeFTPServerFactory;
import io.linuxserver.davos.persistence.dao.ScheduleDAO;
import io.linuxserver.davos.persistence.model.FilterModel;
import io.linuxserver.davos.persistence.model.HostModel;
import io.linuxserver.davos.persistence.model.ScheduleModel;
import io.linuxserver.davos.schedule.RunnableSchedule;
import io.linuxserver.davos.transfer.ftp.TransferProtocol;
public class ScheduleStepDefs {
private static final String TMP = FileUtils.getTempDirectoryPath();
private ScheduleModel scheduleModel;
@Given("^a schedule exists for that server, with filters$")
public void a_schedule_exists_for_that_server_with_filters() throws Throwable {
createBasicSchedule();
FilterModel filter1 = new FilterModel();
filter1.value = "file2*";
scheduleModel.filters.add(filter1);
FilterModel filter2 = new FilterModel();
filter2.value = "file3*";
scheduleModel.filters.add(filter2);
}
@Given("^the schedule is set to delete host files$")
public void the_schedule_is_set_to_delete_host_files() throws Throwable {
scheduleModel.setDeleteHostFile(true);
}
@Given("^the schedule is set to invert filters$")
public void the_schedule_is_set_to_invert_filters() throws Throwable {
scheduleModel.setInvertFilters(true);
}
@Given("^the schedule is set to have mandatory filters$")
public void the_schedule_is_set_to_have_mandatory_filters() throws Throwable {
scheduleModel.setFiltersMandatory(true);
}
@Given("^a schedule exists for that server, without filters$")
public void a_schedule_exists_for_that_server() throws Throwable {
createBasicSchedule();
}
@When("^that schedule is run$")
public void that_schedule_is_run() throws Throwable {
new RunnableSchedule(1L, new CucumberScheduleConfigurationDAO()).run();
}
@Then("^no files are downloaded$")
public void no_files_are_downloaded() throws Throwable {
File file1 = new File(TMP + "/file1.txt");
File file2 = new File(TMP + "/file2.txt");
File file3 = new File(TMP + "/file3.txt");
assertThat(file1.exists()).isFalse();
assertThat(file2.exists()).isFalse();
assertThat(file3.exists()).isFalse();
}
@Then("^all files not matching the filters are downloaded$")
public void all_files_not_matching_the_filters_are_downloaded() throws Throwable {
File file1 = new File(TMP + "/file1.txt");
File file2 = new File(TMP + "/file2.txt");
File file3 = new File(TMP + "/file3.txt");
assertThat(file1.exists()).isTrue();
assertThat(file2.exists()).isFalse();
assertThat(file3.exists()).isFalse();
file1.delete();
}
@Then("^those files are deleted on the host$")
public void those_files_are_deleted_on_the_host() throws Throwable {
assertThat(FakeFTPServerFactory.checkFileExists("/tmp/file1.txt")).isTrue();
assertThat(FakeFTPServerFactory.checkFileExists("/tmp/file2.txt")).isFalse();
assertThat(FakeFTPServerFactory.checkFileExists("/tmp/file3.txt")).isFalse();
}
@Then("^only the filtered files are downloaded$")
public void only_the_filtered_files_are_downloaded() throws Throwable {
File file1 = new File(TMP + "/file1.txt");
File file2 = new File(TMP + "/file2.txt");
File file3 = new File(TMP + "/file3.txt");
assertThat(file1.exists()).isFalse();
assertThat(file2.exists()).isTrue();
assertThat(file3.exists()).isTrue();
file2.delete();
file3.delete();
}
private void createBasicSchedule() {
scheduleModel = new ScheduleModel();
scheduleModel.host = new HostModel();
scheduleModel.host.address = "localhost";
scheduleModel.host.port = FakeFTPServerFactory.getPort();
scheduleModel.host.username = "user";
scheduleModel.host.password = "password";
scheduleModel.host.protocol = TransferProtocol.FTP;
scheduleModel.remoteFilePath = "/tmp";
scheduleModel.localFilePath = TMP;
}
class CucumberScheduleConfigurationDAO implements ScheduleDAO {
@Override
public List<ScheduleModel> getAll() {
return null;
}
@Override
public ScheduleModel fetchSchedule(Long id) {
return scheduleModel;
}
@Override
public ScheduleModel updateConfig(ScheduleModel model) {
return null;
}
@Override
public List<ScheduleModel> fetchSchedulesUsingHost(Long hostId) {
// TODO Auto-generated method stub
return null;
}
@Override
public void updateScannedFilesOnSchedule(Long id, List<String> newlyScannedFiles) {
// TODO Auto-generated method stub
}
@Override
public void deleteSchedule(Long id) {
// TODO Auto-generated method stub
}
}
}
================================================
FILE: src/cucumber/java/io/linuxserver/davos/bdd/ServerStepDefs.java
================================================
package io.linuxserver.davos.bdd;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import cucumber.api.java.After;
import cucumber.api.java.en.Given;
import io.linuxserver.davos.bdd.helpers.FakeFTPServerFactory;
import io.linuxserver.davos.bdd.helpers.FakeSFTPServerFactory;
public class ServerStepDefs {
private static final String TMP = FileUtils.getTempDirectoryPath();
@Given("^there is an FTP server running$")
public void there_is_an_FTP_server_running() throws Throwable {
FakeFTPServerFactory.setup();
}
@Given("^the FTP server has a directory with contents$")
public void the_FTP_server_has_a_directory_with_contents() throws Throwable {
FakeFTPServerFactory.addDirectoryWithNameAndNumberOfFiles("toDelete", 3);
}
@Given("^the FTP server has a directory without contents$")
public void the_FTP_server_has_a_directory_without_contents() throws Throwable {
FakeFTPServerFactory.addDirectoryWithNameAndNumberOfFiles("toDelete", 0);
}
@Given("^there is an SFTP server running$")
public void there_is_an_SFTP_server_running() throws Throwable {
FakeSFTPServerFactory.setup();
}
@Given("^the SFTP server has a directory with contents$")
public void the_SFTP_server_has_a_directory_with_contents() throws Throwable {
FakeSFTPServerFactory.addDirectoryWithNameAndNumberOfFiles("toDelete", 3);
assertThat(new File(TMP + "/toDelete").exists()).isTrue();
assertThat(new File(TMP + "/toDelete/file0").exists()).isTrue();
assertThat(new File(TMP + "/toDelete/file1").exists()).isTrue();
assertThat(new File(TMP + "/toDelete/file2").exists()).isTrue();
}
@Given("^the SFTP server has a directory without contents$")
public void the_SFTP_server_has_a_directory_without_contents() throws Throwable {
FakeSFTPServerFactory.addDirectoryWithNameAndNumberOfFiles("toDelete", 0);
}
@After("@Server")
public void after() {
FakeFTPServerFactory.stop();
}
@After("@SFTPServer")
public void afterSFTP() throws IOException {
FakeSFTPServerFactory.stop();
}
}
================================================
FILE: src/cucumber/java/io/linuxserver/davos/bdd/helpers/FakeFTPServerFactory.java
================================================
package io.linuxserver.davos.bdd.helpers;
import org.mockftpserver.fake.FakeFtpServer;
import org.mockftpserver.fake.UserAccount;
import org.mockftpserver.fake.filesystem.DirectoryEntry;
import org.mockftpserver.fake.filesystem.FileEntry;
import org.mockftpserver.fake.filesystem.FileSystem;
import org.mockftpserver.fake.filesystem.UnixFakeFileSystem;
public class FakeFTPServerFactory {
private static FakeFtpServer server;
public static int getPort() {
return server.getServerControlPort();
}
public static FakeFtpServer setup() {
server = new FakeFtpServer();
server.addUserAccount(new UserAccount("user", "password", "/tmp"));
server.setServerControlPort(0);
FileSystem fileSystem = new UnixFakeFileSystem();
fileSystem.add(new DirectoryEntry("/tmp"));
fileSystem.add(new FileEntry("/tmp/file1.txt", "hello world"));
fileSystem.add(new FileEntry("/tmp/file2.txt", "hello world"));
fileSystem.add(new FileEntry("/tmp/file3.txt", "hello world"));
server.setFileSystem(fileSystem);
server.start();
return server;
}
public static boolean checkFileExists(String filePath) {
return server.getFileSystem().exists(filePath);
}
public static void addDirectoryWithNameAndNumberOfFiles(String name, int numberOfFiles) {
server.getFileSystem().add(new DirectoryEntry("/tmp/" + name));
int i;
for (i = 0; i < numberOfFiles; i++)
server.getFileSystem().add(new FileEntry("/tmp/" + name + "/file" + i));
}
public static void stop() {
server.stop();
}
}
================================================
FILE: src/cucumber/java/io/linuxserver/davos/bdd/helpers/FakeSFTPServerFactory.java
================================================
package io.linuxserver.davos.bdd.helpers;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import org.apache.commons.io.FileUtils;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.scp.ScpCommandFactory;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.shell.ProcessShellFactory;
import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
public class FakeSFTPServerFactory {
private static final String TMP = FileUtils.getTempDirectoryPath();
private static final String USERNAME = "user";
private static final String PASSWORD = "password";
private static SshServer sshd;
public static void setup() throws IOException {
SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder().build();
sshd = SshServer.setUpDefaultServer();
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", "-l" }));
sshd.setCommandFactory(new ScpCommandFactory());
sshd.setSubsystemFactories(Collections.<NamedFactory<Command>> singletonList(factory));
sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
@Override
public boolean authenticate(String username, String password, ServerSession session)
throws PasswordChangeRequiredException {
return USERNAME.equals(username) && PASSWORD.equals(password);
}
});
sshd.setFileSystemFactory(new VirtualFileSystemFactory() {
@Override
protected Path computeRootDir(Session session) throws IOException {
return Paths.get(TMP);
}
});
sshd.start();
}
public static void stop() throws IOException {
sshd.stop();
}
public static void addDirectoryWithNameAndNumberOfFiles(String name, int numberOfFiles) throws IOException {
File directory = new File(TMP + "/" + name);
directory.mkdirs();
int i;
for (i = 0; i < numberOfFiles; i++)
new File(TMP + "/" + name + "/file" + i).createNewFile();
}
public static int getPort() {
return sshd.getPort();
}
}
================================================
FILE: src/cucumber/java/io/linuxserver/davos/bdd/helpers/Logging.java
================================================
package io.linuxserver.davos.bdd.helpers;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import cucumber.api.java.Before;
public class Logging {
@Before
public void before() {
Configurator.setRootLevel(Level.ERROR);
Configurator.setLevel("io.linuxserver", Level.ERROR);
}
}
================================================
FILE: src/cucumber/resources/Client.feature
================================================
@Client
Feature: General client tests
@Server
Scenario: Connecting to the FTP server
Given there is an FTP server running
When davos connects to the server
Then listing the files will show the correct files
@Server
Scenario: Downloading a file from the server
Given there is an FTP server running
When davos connects to the server
And downloads a file
Then the file is located in the specified local directory
@Listener @Server
Scenario: Download with FTP Progress Listener
Given there is an FTP server running
When davos connects to the server
And initialises a Progress Listener for that connection
And downloads a file
Then the Progress Listener will have its values updated
@Server
Scenario: Deleting directories on the remote FTP server
Given there is an FTP server running
And the FTP server has a directory with contents
When davos connects to the server
And deletes a directory
Then the directory is deleted on the server
@Server
Scenario: Deleting directories on the remote FTP server (empty)
Given there is an FTP server running
And the FTP server has a directory without contents
When davos connects to the server
And deletes a directory
Then the directory is deleted on the server
@SFTPServer
Scenario: Deleting directories on the remote SFTP server
Given there is an SFTP server running
And the SFTP server has a directory with contents
When davos connects to the SFTP server
And deletes an SFTP directory
Then the SFTP directory is deleted on the server
@SFTPServer
Scenario: Deleting directories on the remote SFTP server (empty)
Given there is an SFTP server running
And the SFTP server has a directory without contents
When davos connects to the SFTP server
And deletes an SFTP directory
Then the SFTP directory is deleted on the server
================================================
FILE: src/cucumber/resources/Schedule.feature
================================================
@Schedule @Server
Feature: Scheduling
Scenario: Finding files that match filters
Given there is an FTP server running
And a schedule exists for that server, with filters
When that schedule is run
Then only the filtered files are downloaded
Scenario: Should delete files once matched and downloaded
Given there is an FTP server running
And a schedule exists for that server, with filters
And the schedule is set to delete host files
When that schedule is run
Then only the filtered files are downloaded
And those files are deleted on the host
Scenario: Should download all files not matching filters if inverted
Given there is an FTP server running
And a schedule exists for that server, with filters
And the schedule is set to invert filters
When that schedule is run
Then all files not matching the filters are downloaded
Scenario: Should not download any files if filters are mandatory but not set
Given there is an FTP server running
And a schedule exists for that server, without filters
And the schedule is set to have mandatory filters
When that schedule is run
Then no files are downloaded
================================================
FILE: src/main/java/io/linuxserver/davos/DavosApplication.java
================================================
package io.linuxserver.davos;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DavosApplication {
public static void main(String[] args) {
SpringApplication.run(DavosApplication.class, args);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/Version.java
================================================
package io.linuxserver.davos;
public class Version {
private int major;
private int minor;
private int patch;
public Version(int major, int minor, int patch) {
this.major = major;
this.minor = minor;
this.patch = patch;
}
public Version(String version) {
String[] bits = version.split("\\.");
this.major = Integer.parseInt(bits[0]);
this.minor = Integer.parseInt(bits[1]);
this.patch = Integer.parseInt(bits[2]);
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getPatch() {
return patch;
}
public boolean isNewerThan(Version version) {
if (this.major > version.major)
return true;
if (this.minor > version.minor)
return true;
else if (this.minor < version.minor)
return false;
if (this.patch > version.patch)
return true;
return false;
}
@Override
public String toString() {
return new StringBuilder().append(major).append(".").append(minor).append(".").append(patch).toString();
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/converters/Converter.java
================================================
package io.linuxserver.davos.converters;
public interface Converter<S, T> {
T convertTo(S source);
S convertFrom(T source);
}
================================================
FILE: src/main/java/io/linuxserver/davos/converters/HostConverter.java
================================================
package io.linuxserver.davos.converters;
import org.springframework.stereotype.Component;
import io.linuxserver.davos.persistence.model.HostModel;
import io.linuxserver.davos.transfer.ftp.TransferProtocol;
import io.linuxserver.davos.web.Host;
import io.linuxserver.davos.web.selectors.ProtocolSelector;
@Component
public class HostConverter implements Converter<HostModel, Host> {
@Override
public Host convertTo(HostModel source) {
Host host = new Host();
host.setId(source.id);
host.setName(source.name);
host.setAddress(source.address);
host.setPort(source.port);
host.setUsername(source.username);
host.setPassword(source.password);
host.setProtocol(ProtocolSelector.valueOf(source.protocol.toString()));
host.setIdentityFileEnabled(source.isIdentityFileEnabled());
host.setIdentityFile(source.identityFile);
return host;
}
@Override
public HostModel convertFrom(Host source) {
HostModel model = new HostModel();
model.id = source.getId();
model.name = source.getName();
model.address = source.getAddress();
model.port = source.getPort();
model.username = source.getUsername();
model.password = source.getPassword();
model.protocol = TransferProtocol.valueOf(source.getProtocol().toString());
model.setIdentityFileEnabled(source.isIdentityFileEnabled());
model.identityFile = source.getIdentityFile();
return model;
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/converters/ScheduleConverter.java
================================================
package io.linuxserver.davos.converters;
import static java.util.stream.Collectors.toList;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.linuxserver.davos.persistence.model.ActionModel;
import io.linuxserver.davos.persistence.model.FilterModel;
import io.linuxserver.davos.persistence.model.ScheduleModel;
import io.linuxserver.davos.transfer.ftp.FileTransferType;
import io.linuxserver.davos.web.API;
import io.linuxserver.davos.web.Filter;
import io.linuxserver.davos.web.Pushbullet;
import io.linuxserver.davos.web.SNS;
import io.linuxserver.davos.web.Schedule;
import io.linuxserver.davos.web.selectors.MethodSelector;
import io.linuxserver.davos.web.selectors.TransferSelector;
@Component
public class ScheduleConverter implements Converter<ScheduleModel, Schedule> {
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleConverter.class);
@Override
public Schedule convertTo(ScheduleModel source) {
Schedule schedule = new Schedule();
schedule.setId(source.id);
schedule.setInterval(source.interval);
schedule.setLocalDirectory(source.localFilePath);
schedule.setName(source.name);
schedule.setHostDirectory(source.remoteFilePath);
schedule.setAutomatic(source.getStartAutomatically());
schedule.setHost(source.host.id);
schedule.setTransferType(TransferSelector.valueOf(source.transferType.toString()));
schedule.setMoveFileTo(source.moveFileTo);
schedule.getLastScannedFiles().addAll(source.scannedFiles.stream().map(f -> f.file).collect(toList()));
schedule.setFiltersMandatory(source.getFiltersMandatory());
schedule.setDeleteHostFile(source.getDeleteHostFile());
schedule.setInvertFilters(source.getInvertFilters());
if (source.getLastRunTime() > 0)
schedule.setLastRunTime(new DateTime(source.getLastRunTime()).toString("yyyy-MM-dd HH:mm:ss"));
for (ActionModel action : source.actions) {
if ("api".equals(action.actionType)) {
API api = new API();
api.setId(action.id);
api.setUrl(action.f1);
api.setMethod(MethodSelector.valueOf(action.f2));
api.setContentType(action.f3);
api.setBody(action.f4);
schedule.getApis().add(api);
} else if ("pushbullet".equals(action.actionType)) {
Pushbullet notification = new Pushbullet();
notification.setId(action.id);
notification.setApiKey(action.f1);
schedule.getNotifications().getPushbullet().add(notification);
} else if ("sns".equals(action.actionType)) {
SNS sns = new SNS();
sns.setId(action.id);
sns.setTopicArn(action.f1);
sns.setRegion(action.f2);
sns.setAccessKey(action.f3);
sns.setSecretAccessKey(action.f4);
schedule.getNotifications().getSns().add(sns);
}
}
for (FilterModel filter : source.filters) {
Filter filterDto = new Filter();
filterDto.setId(filter.id);
filterDto.setValue(filter.value);
schedule.getFilters().add(filterDto);
}
return schedule;
}
@Override
public ScheduleModel convertFrom(Schedule source) {
ScheduleModel model = new ScheduleModel();
model.id = source.getId();
model.name = source.getName();
model.interval = source.getInterval();
model.localFilePath = source.getLocalDirectory();
model.remoteFilePath = source.getHostDirectory();
model.setStartAutomatically(source.isAutomatic());
model.transferType = FileTransferType.valueOf(source.getTransferType().toString());
model.moveFileTo = source.getMoveFileTo();
model.setFiltersMandatory(source.isFiltersMandatory());
model.setInvertFilters(source.isInvertFilters());
model.setDeleteHostFile(source.isDeleteHostFile());
if (StringUtils.isNotBlank(source.getMoveFileTo())) {
LOGGER.debug("Converting MoveTo to internal action: {}", source.getMoveFileTo());
ActionModel moveTo = new ActionModel();
moveTo.actionType = "move";
moveTo.f1 = source.getMoveFileTo();
moveTo.schedule = model;
model.actions.add(moveTo);
}
for (Pushbullet action : source.getNotifications().getPushbullet()) {
LOGGER.debug("Converting Pushbullet to internal action: {}", action.getApiKey());
ActionModel actionModel = new ActionModel();
actionModel.id = action.getId();
actionModel.actionType = "pushbullet";
actionModel.f1 = action.getApiKey();
actionModel.schedule = model;
model.actions.add(actionModel);
}
for (SNS action : source.getNotifications().getSns()) {
LOGGER.debug("Converting SNS to internal action: {}", action.getTopicArn());
ActionModel actionModel = new ActionModel();
actionModel.id = action.getId();
actionModel.actionType = "sns";
actionModel.f1 = action.getTopicArn();
actionModel.f2 = action.getRegion();
actionModel.f3 = action.getAccessKey();
actionModel.f4 = action.getSecretAccessKey();
actionModel.schedule = model;
model.actions.add(actionModel);
}
for (API action : source.getApis()) {
LOGGER.debug("Converting API to internal action: {}", action.getUrl());
ActionModel actionModel = new ActionModel();
actionModel.id = action.getId();
actionModel.actionType = "api";
actionModel.f1 = action.getUrl();
actionModel.f2 = action.getMethod().toString();
actionModel.f3 = action.getContentType();
actionModel.f4 = action.getBody();
actionModel.schedule = model;
model.actions.add(actionModel);
}
for (Filter filter : source.getFilters()) {
FilterModel filterModel = new FilterModel();
filterModel.id = filter.getId();
filterModel.value = filter.getValue();
filterModel.schedule = model;
model.filters.add(filterModel);
}
return model;
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/delegation/services/HostService.java
================================================
package io.linuxserver.davos.delegation.services;
import java.util.List;
import io.linuxserver.davos.web.Host;
public interface HostService {
List<Host> fetchAllHosts();
Host fetchHost(Long id);
Host saveHost(Host host);
void deleteHost(Long id);
List<Long> fetchSchedulesUsingHost(Long id);
void testConnection(Host host);
}
================================================
FILE: src/main/java/io/linuxserver/davos/delegation/services/HostServiceImpl.java
================================================
package io.linuxserver.davos.delegation.services;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.linuxserver.davos.converters.HostConverter;
import io.linuxserver.davos.exception.HostInUseException;
import io.linuxserver.davos.persistence.dao.HostDAO;
import io.linuxserver.davos.persistence.dao.ScheduleDAO;
import io.linuxserver.davos.persistence.model.HostModel;
import io.linuxserver.davos.transfer.ftp.client.Client;
import io.linuxserver.davos.transfer.ftp.client.ClientFactory;
import io.linuxserver.davos.transfer.ftp.client.UserCredentials;
import io.linuxserver.davos.transfer.ftp.client.UserCredentials.Identity;
import io.linuxserver.davos.web.Host;
@Component
public class HostServiceImpl implements HostService {
private static final Logger LOGGER = LoggerFactory.getLogger(HostServiceImpl.class);
@Resource
private HostDAO hostDAO;
@Resource
private ScheduleDAO scheduleDAO;
@Resource
private HostConverter hostConverter;
@Override
public Host fetchHost(Long id) {
return toHost(hostDAO.fetchHost(id));
}
@Override
public Host saveHost(Host host) {
HostModel model = hostConverter.convertFrom(host);
return hostConverter.convertTo(hostDAO.saveHost(model));
}
@Override
public void deleteHost(Long id) {
List<Long> schedulesUsingHost = fetchSchedulesUsingHost(id);
if (schedulesUsingHost.isEmpty()) {
hostDAO.deleteHost(id);
} else {
throw new HostInUseException("Host is being used by Schedules: " + schedulesUsingHost);
}
}
@Override
public List<Host> fetchAllHosts() {
return hostDAO.fetchAllHosts().stream().map(this::toHost).collect(Collectors.toList());
}
private Host toHost(HostModel model) {
return hostConverter.convertTo(model);
}
@Override
public List<Long> fetchSchedulesUsingHost(Long id) {
return scheduleDAO.fetchSchedulesUsingHost(id).stream().map(s -> s.id).collect(Collectors.toList());
}
@Override
public void testConnection(Host host) {
HostModel model = hostConverter.convertFrom(host);
LOGGER.info("Attempting to test connection to host", model.address);
Client client = new ClientFactory().getClient(model.protocol);
LOGGER.debug("Credentials: {} : {}", model.username, model.password);
UserCredentials userCredentials;
if (model.isIdentityFileEnabled())
userCredentials = new UserCredentials(model.username, new Identity(model.identityFile));
else
userCredentials = new UserCredentials(model.username, model.password);
client.setCredentials(userCredentials);
client.setHost(model.address);
client.setPort(model.port);
LOGGER.debug("Making connection on port {}", model.port);
client.connect();
LOGGER.info("Connection successful.");
client.disconnect();
LOGGER.debug("Disconnected");
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/delegation/services/ScheduleService.java
================================================
package io.linuxserver.davos.delegation.services;
import java.util.List;
import io.linuxserver.davos.web.Schedule;
public interface ScheduleService {
void startSchedule(Long id);
void stopSchedule(Long id);
void deleteSchedule(Long id);
List<Schedule> fetchAllSchedules();
Schedule fetchSchedule(Long id);
Schedule createSchedule(Schedule schedule);
Schedule updateSchedule(Schedule schedule);
void clearScannedFilesFromSchedule(Long id);
}
================================================
FILE: src/main/java/io/linuxserver/davos/delegation/services/ScheduleServiceImpl.java
================================================
package io.linuxserver.davos.delegation.services;
import static java.util.stream.Collectors.toList;
import java.util.List;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.linuxserver.davos.converters.HostConverter;
import io.linuxserver.davos.converters.ScheduleConverter;
import io.linuxserver.davos.persistence.dao.HostDAO;
import io.linuxserver.davos.persistence.dao.ScheduleDAO;
import io.linuxserver.davos.persistence.model.HostModel;
import io.linuxserver.davos.persistence.model.ScheduleModel;
import io.linuxserver.davos.schedule.ScheduleExecutor;
import io.linuxserver.davos.schedule.workflow.transfer.FTPTransfer;
import io.linuxserver.davos.web.Schedule;
import io.linuxserver.davos.web.Transfer;
import io.linuxserver.davos.web.Transfer.Progress;
@Component
public class ScheduleServiceImpl implements ScheduleService {
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleServiceImpl.class);
@Resource
private ScheduleConverter scheduleConverter;
@Resource
private ScheduleExecutor scheduleExecutor;
@Resource
private HostConverter hostConverter;
@Resource
private ScheduleDAO scheduleDAO;
@Resource
private HostDAO hostDAO;
@Override
public void startSchedule(Long id) {
LOGGER.info("Starting schedule");
scheduleExecutor.startSchedule(id);
LOGGER.info("Schedule started");
}
@Override
public void stopSchedule(Long id) {
LOGGER.info("Stopping schedule");
scheduleExecutor.stopSchedule(id);
LOGGER.info("Schedule stopped");
}
@Override
public void deleteSchedule(Long id) {
if (scheduleExecutor.isScheduleRunning(id)) {
LOGGER.debug("Schedule is running, so will stop it before deleting");
stopSchedule(id);
}
scheduleDAO.deleteSchedule(id);
}
@Override
public List<Schedule> fetchAllSchedules() {
return scheduleDAO.getAll().stream().map(this::toSchedule).collect(toList());
}
@Override
public Schedule fetchSchedule(Long id) {
return toSchedule(scheduleDAO.fetchSchedule(id));
}
@Override
public Schedule createSchedule(Schedule schedule) {
ScheduleModel model = scheduleConverter.convertFrom(schedule);
model.host = getHostForSchedule(schedule.getHost());
return scheduleConverter.convertTo(scheduleDAO.updateConfig(model));
}
@Override
public Schedule updateSchedule(Schedule schedule) {
if (null == schedule.getId())
throw new IllegalArgumentException("Schdule has no ID");
ScheduleModel existingModel = scheduleDAO.fetchSchedule(schedule.getId());
ScheduleModel model = scheduleConverter.convertFrom(schedule);
model.host = getHostForSchedule(schedule.getHost());
model.setLastRunTime(existingModel.getLastRunTime());
return scheduleConverter.convertTo(scheduleDAO.updateConfig(model));
}
@Override
public void clearScannedFilesFromSchedule(Long id) {
ScheduleModel model = scheduleDAO.fetchSchedule(id);
model.scannedFiles.clear();
scheduleDAO.updateConfig(model);
}
private HostModel getHostForSchedule(Long id) {
HostModel hostModel = hostDAO.fetchHost(id);
if (null == hostModel) {
LOGGER.info("Schedule is referencing a host that does not exist");
throw new IllegalArgumentException("Host with id " + id + " does not exist.");
}
return hostModel;
}
private Schedule toSchedule(ScheduleModel model) {
Schedule convertTo = scheduleConverter.convertTo(model);
if (scheduleExecutor.isScheduleRunning(convertTo.getId())) {
convertTo.setRunning(true);
List<FTPTransfer> transfers = scheduleExecutor.getRunningSchedule(convertTo.getId()).getSchedule().getTransfers();
convertTo.getTransfers().addAll(transfers.stream().map(this::toTransfer).collect(toList()));
}
return convertTo;
}
private Transfer toTransfer(FTPTransfer ftpTransfer) {
Transfer transfer = new Transfer();
transfer.setFileName(ftpTransfer.getFile().getName());
transfer.setFileSize(ftpTransfer.getFile().getSize());
transfer.setDirectory(ftpTransfer.getFile().isDirectory());
transfer.setStatus(ftpTransfer.getState().toString());
if (null != ftpTransfer.getListener()) {
Progress progress = new Progress();
progress.setPercentageComplete(ftpTransfer.getListener().getProgress());
progress.setTransferSpeed(ftpTransfer.getListener().getTransferSpeed());
transfer.setProgress(progress);
}
return transfer;
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/delegation/services/SettingsService.java
================================================
package io.linuxserver.davos.delegation.services;
import io.linuxserver.davos.Version;
import io.linuxserver.davos.web.selectors.LogLevelSelector;
public interface SettingsService {
void setLoggingLevel(LogLevelSelector level);
LogLevelSelector getCurrentLoggingLevel();
Version retrieveRemoteVersion();
}
================================================
FILE: src/main/java/io/linuxserver/davos/delegation/services/SettingsServiceImpl.java
================================================
package io.linuxserver.davos.delegation.services;
import org.apache.logging.log4j.Level;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import io.linuxserver.davos.Version;
import io.linuxserver.davos.logging.LoggingManager;
import io.linuxserver.davos.web.selectors.LogLevelSelector;
@Component
public class SettingsServiceImpl implements SettingsService {
private static final Logger LOGGER = LoggerFactory.getLogger(SettingsServiceImpl.class);
private LogLevelSelector currentLevel = LogLevelSelector.INFO;
private RestTemplate restTemplate = new RestTemplate();
@Override
public void setLoggingLevel(LogLevelSelector level) {
currentLevel = level;
LoggingManager.setLogLevel(Level.valueOf(level.toString()));
}
@Override
public LogLevelSelector getCurrentLoggingLevel() {
return currentLevel;
}
@Override
public Version retrieveRemoteVersion() {
try {
String gitHubURL = "https://raw.githubusercontent.com/linuxserver/davos/LatestRelease/version.txt";
LOGGER.debug("Calling out to GitHub to check for new version ({})", gitHubURL);
ResponseEntity<String> response = restTemplate.exchange(gitHubURL, HttpMethod.GET,
new HttpEntity<String>(new HttpHeaders()), String.class);
String body = response.getBody();
LOGGER.debug("GitHub responded with a {}, and body of {}", response.getStatusCode(), body);
return new Version(body);
} catch (RestClientException | HttpMessageConversionException e) {
LOGGER.error("Unable to get version from GitHub: {}", e.getMessage(), e);
LOGGER.debug("Defaulting remote version to zero");
return new Version(0, 0, 0);
}
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/dto/ActionDTO.java
================================================
package io.linuxserver.davos.dto;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class ActionDTO {
public Long id;
public String actionType;
public String f1;
public String f2;
public String f3;
public String f4;
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/dto/FTPFileDTO.java
================================================
package io.linuxserver.davos.dto;
public class FTPFileDTO {
public String name;
public String extension;
public String modified;
public String path;
public long size;
public boolean directory;
}
================================================
FILE: src/main/java/io/linuxserver/davos/dto/FilterDTO.java
================================================
package io.linuxserver.davos.dto;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class FilterDTO {
public Long id;
public String value;
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/dto/HostDTO.java
================================================
package io.linuxserver.davos.dto;
import io.linuxserver.davos.transfer.ftp.TransferProtocol;
public class HostDTO {
public String name;
public String address;
public int port;
public String username;
public String password;
public TransferProtocol protocol = TransferProtocol.FTP;
}
================================================
FILE: src/main/java/io/linuxserver/davos/dto/ScheduleDTO.java
================================================
package io.linuxserver.davos.dto;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import io.linuxserver.davos.transfer.ftp.FileTransferType;
import io.linuxserver.davos.transfer.ftp.TransferProtocol;
public class ScheduleDTO {
public Long id;
public String name;
public boolean startAutomatically;
public int interval;
public TransferProtocol connectionType;
public String hostName;
public int port;
public String username;
public String password;
public String remoteFilePath;
public String localFilePath;
public long lastRun;
public boolean running;
public FileTransferType transferType;
public List<FilterDTO> filters = new ArrayList<FilterDTO>();
public List<ActionDTO> actions = new ArrayList<ActionDTO>();
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/dto/ScheduleProcessResponse.java
================================================
package io.linuxserver.davos.dto;
public class ScheduleProcessResponse {
public String message = "OK";
public Long id;
}
================================================
FILE: src/main/java/io/linuxserver/davos/exception/HostInUseException.java
================================================
package io.linuxserver.davos.exception;
public class HostInUseException extends RuntimeException {
private static final long serialVersionUID = 618892455818185964L;
public HostInUseException(String message) {
super(message);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/exception/ScheduleAlreadyRunningException.java
================================================
package io.linuxserver.davos.exception;
public class ScheduleAlreadyRunningException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ScheduleAlreadyRunningException() {
super("The schedule is already running");
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/exception/ScheduleNotRunningException.java
================================================
package io.linuxserver.davos.exception;
public class ScheduleNotRunningException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ScheduleNotRunningException() {
super("The schedule was not running");
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/logging/LoggingManager.java
================================================
package io.linuxserver.davos.logging;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggingManager {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggingManager.class);
public static void enableDebug() {
Configurator.setLevel("io.linuxserver", Level.DEBUG);
LOGGER.debug("DEBUG has been enabled");
}
public static void disableDebug() {
Configurator.setLevel("io.linuxserver", Level.INFO);
LOGGER.info("DEBUG has been disabled. Back at INFO.");
}
public static void setLogLevel(Level level) {
LOGGER.info("Logging level now set at {}", level);
Configurator.setLevel("io.linuxserver", level);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/dao/DefaultHostDAO.java
================================================
package io.linuxserver.davos.persistence.dao;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import io.linuxserver.davos.persistence.model.HostModel;
import io.linuxserver.davos.persistence.repository.HostRepository;
@Component
public class DefaultHostDAO implements HostDAO {
@Resource
private HostRepository hostRepository;
@Override
public HostModel saveHost(HostModel host) {
return hostRepository.save(host);
}
@Override
public HostModel fetchHost(Long id) {
return hostRepository.findOne(id);
}
@Override
public List<HostModel> fetchAllHosts() {
return hostRepository.findAll();
}
@Override
public void deleteHost(Long id) {
hostRepository.delete(id);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/dao/DefaultScheduleDAO.java
================================================
package io.linuxserver.davos.persistence.dao;
import static java.util.stream.Collectors.toList;
import java.util.List;
import javax.annotation.Resource;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.linuxserver.davos.persistence.model.ScannedFileModel;
import io.linuxserver.davos.persistence.model.ScheduleModel;
import io.linuxserver.davos.persistence.repository.ScheduleRepository;
@Component
public class DefaultScheduleDAO implements ScheduleDAO {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultScheduleDAO.class);
@Resource
private ScheduleRepository configRepository;
@Override
public List<ScheduleModel> getAll() {
return configRepository.findAll();
}
@Override
public ScheduleModel fetchSchedule(Long id) {
return configRepository.findOne(id);
}
@Override
public ScheduleModel updateConfig(ScheduleModel model) {
if (null != model.id) {
LOGGER.debug("Getting original view of schedule to overlay scannedFiles. "
+ "These should only be updated by 'updateScannedFilesOnSchedule'");
ScheduleModel current = fetchSchedule(model.id);
model.scannedFiles = current.scannedFiles;
}
LOGGER.debug("Saving model: {}, filters {}", model, model.filters);
ScheduleModel savedModel = configRepository.save(model);
LOGGER.debug("Schedule model has been saved. Returned values from DB are: {}", model);
return savedModel;
}
@Override
public List<ScheduleModel> fetchSchedulesUsingHost(Long hostId) {
List<ScheduleModel> models = configRepository.findByHost_Id(hostId);
LOGGER.debug("Found {} schedules using host {}", models.size(), hostId);
return models;
}
@Override
public void updateScannedFilesOnSchedule(Long id, List<String> newlyScannedFiles) {
ScheduleModel model = configRepository.findOne(id);
model.scannedFiles.clear();
model.scannedFiles.addAll(newlyScannedFiles.stream().map(f -> toScannedFileModel(f, model)).collect(toList()));
model.setLastRunTime(DateTime.now().getMillis());
configRepository.save(model);
}
private ScannedFileModel toScannedFileModel(String fileName, ScheduleModel model) {
ScannedFileModel scannedFileModel = new ScannedFileModel();
scannedFileModel.file = fileName;
scannedFileModel.schedule = model;
return scannedFileModel;
}
@Override
public void deleteSchedule(Long id) {
configRepository.delete(id);
LOGGER.info("Schedule has been deleted");
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/dao/HostDAO.java
================================================
package io.linuxserver.davos.persistence.dao;
import java.util.List;
import io.linuxserver.davos.persistence.model.HostModel;
public interface HostDAO {
HostModel saveHost(HostModel host);
HostModel fetchHost(Long id);
List<HostModel> fetchAllHosts();
void deleteHost(Long id);
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/dao/ScheduleDAO.java
================================================
package io.linuxserver.davos.persistence.dao;
import java.util.List;
import io.linuxserver.davos.persistence.model.ScheduleModel;
public interface ScheduleDAO {
List<ScheduleModel> getAll();
List<ScheduleModel> fetchSchedulesUsingHost(Long hostId);
ScheduleModel fetchSchedule(Long id);
ScheduleModel updateConfig(ScheduleModel model);
void updateScannedFilesOnSchedule(Long id, List<String> newlyScannedFiles);
void deleteSchedule(Long id);
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/model/ActionModel.java
================================================
package io.linuxserver.davos.persistence.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class ActionModel {
@Id
@GeneratedValue
public Long id;
@Column
public String actionType;
@Column
public String f1;
@Column
public String f2;
@Column
public String f3;
@Column
public String f4;
@ManyToOne
@JoinColumn(name = "action_schedule_id")
public ScheduleModel schedule;
@Override
public String toString() {
return "ActionModel [id=" + id + ", actionType=" + actionType + ", f1=" + f1 + ", f2=" + f2 + ", f3=" + f3 + ", f4=" + f4
+ "]";
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/model/FilterModel.java
================================================
package io.linuxserver.davos.persistence.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class FilterModel {
@Id
@GeneratedValue
public Long id;
@Column
public String value;
@ManyToOne
@JoinColumn(name = "filter_schedule_id")
public ScheduleModel schedule;
@Override
public String toString() {
return "FilterModel [id=" + id + ", value=" + value + "]";
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/model/HostModel.java
================================================
package io.linuxserver.davos.persistence.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import io.linuxserver.davos.transfer.ftp.TransferProtocol;
@Entity
public class HostModel {
@Id
@GeneratedValue
public Long id;
@Column
public String name;
@Column
public String address;
@Column
public int port;
@Column
public TransferProtocol protocol = TransferProtocol.FTP;
@Column
public String username;
@Column
public String password;
@Column
public String identityFile;
@Column
private Boolean identityFileEnabled;
public boolean isIdentityFileEnabled() {
if (null == identityFileEnabled)
return false;
return identityFileEnabled;
}
public void setIdentityFileEnabled(boolean identityFileEnabled) {
this.identityFileEnabled = identityFileEnabled;
}
@OneToMany(mappedBy = "host", orphanRemoval = false)
@LazyCollection(LazyCollectionOption.TRUE)
public List<ScheduleModel> schedules = new ArrayList<ScheduleModel>();
@Override
public String toString() {
return "HostModel [id=" + id + ", name=" + name + ", address=" + address + ", port=" + port + ", protocol="
+ protocol + ", username=" + username + ", password=" + password + ", identityFile=" + identityFile
+ ", identityFileEnabled=" + identityFileEnabled + ", schedules=" + schedules + "]";
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/model/ScannedFileModel.java
================================================
package io.linuxserver.davos.persistence.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class ScannedFileModel {
@Id
@GeneratedValue
public Long id;
@Column
public String file;
@ManyToOne
@JoinColumn(name = "scanned_file_schedule_id")
public ScheduleModel schedule;
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/model/ScheduleModel.java
================================================
package io.linuxserver.davos.persistence.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import io.linuxserver.davos.transfer.ftp.FileTransferType;
@Entity
public class ScheduleModel {
@Id
@GeneratedValue
public Long id;
@Column
public String name;
@Column
private Boolean startAutomatically;
@Column
public int interval;
@Column
public String remoteFilePath;
@Column
public String localFilePath;
@Column
public String moveFileTo;
@Column
private Boolean filtersMandatory;
@Column
private Boolean deleteHostFile;
@Column
private Boolean invertFilters;
@Column
private Long lastRunTime;
public long getLastRunTime() {
if (null != lastRunTime)
return lastRunTime;
return 0;
}
public Boolean getFiltersMandatory() {
if (null != filtersMandatory)
return filtersMandatory;
return false;
}
public void setLastRunTime(long millis) {
lastRunTime = millis;
}
public void setFiltersMandatory(boolean filtersMandatory) {
this.filtersMandatory = filtersMandatory;
}
public Boolean getDeleteHostFile() {
if (null != deleteHostFile)
return deleteHostFile;
return false;
}
public void setDeleteHostFile(boolean deleteHostFile) {
this.deleteHostFile = deleteHostFile;
}
public Boolean getStartAutomatically() {
if (null != startAutomatically)
return startAutomatically;
return false;
}
public void setStartAutomatically(boolean startAutomatically) {
this.startAutomatically = startAutomatically;
}
public Boolean getInvertFilters() {
if (null != invertFilters)
return invertFilters;
return false;
}
public void setInvertFilters(boolean invertFilters) {
this.invertFilters = invertFilters;
}
@Column
public FileTransferType transferType = FileTransferType.FILE;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "schedule_host_id")
public HostModel host;
@OneToMany(orphanRemoval = true, mappedBy = "schedule", cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
public List<FilterModel> filters = new ArrayList<FilterModel>();
@OneToMany(orphanRemoval = true, mappedBy = "schedule", cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
public List<ActionModel> actions = new ArrayList<ActionModel>();
@OneToMany(orphanRemoval = true, mappedBy = "schedule", cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
public List<ScannedFileModel> scannedFiles = new ArrayList<ScannedFileModel>();
@Override
public String toString() {
return "ScheduleModel [id=" + id + ", name=" + name + ", startAutomatically=" + startAutomatically + ", interval="
+ interval + ", remoteFilePath=" + remoteFilePath + ", localFilePath=" + localFilePath + ", transferType="
+ transferType + ", filters=" + filters + ", actions=" + actions + "]";
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/repository/HostRepository.java
================================================
package io.linuxserver.davos.persistence.repository;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import io.linuxserver.davos.persistence.model.HostModel;
public interface HostRepository extends CrudRepository<HostModel, Long> {
List<HostModel> findAll();
}
================================================
FILE: src/main/java/io/linuxserver/davos/persistence/repository/ScheduleRepository.java
================================================
package io.linuxserver.davos.persistence.repository;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import io.linuxserver.davos.persistence.model.ScheduleModel;
public interface ScheduleRepository extends CrudRepository<ScheduleModel, Long> {
List<ScheduleModel> findAll();
List<ScheduleModel> findByHost_Id(Long hostId);
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/RunnableSchedule.java
================================================
package io.linuxserver.davos.schedule;
import static java.util.stream.Collectors.toList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.persistence.dao.ScheduleDAO;
import io.linuxserver.davos.persistence.model.ScheduleModel;
import io.linuxserver.davos.schedule.workflow.ScheduleWorkflow;
import io.linuxserver.davos.schedule.workflow.transfer.FTPTransfer;
public class RunnableSchedule implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(RunnableSchedule.class);
private ScheduleDAO configurationDAO;
private Long scheduleId;
private ScheduleWorkflow scheduleWorkflow;
public RunnableSchedule(Long scheduleId, ScheduleDAO configurationDAO) {
this.scheduleId = scheduleId;
this.configurationDAO = configurationDAO;
}
@Override
public void run() {
LOGGER.info("Starting schedule {}", scheduleId);
ScheduleModel model = configurationDAO.fetchSchedule(scheduleId);
ScheduleConfiguration config = ScheduleConfigurationFactory.createConfig(model);
scheduleWorkflow = new ScheduleWorkflow(config);
LOGGER.debug("Setting last scanned files on workflow before starting.");
scheduleWorkflow.getFilesFromLastScan().addAll(model.scannedFiles.stream().map(sf -> sf.file).collect(toList()));
LOGGER.debug("Starting workflow");
scheduleWorkflow.start();
LOGGER.debug("Workflow finished");
LOGGER.debug("Saving newly scanned files against schedule");
configurationDAO.updateScannedFilesOnSchedule(scheduleId, scheduleWorkflow.getFilesFromLastScan());
}
public List<FTPTransfer> getTransfers() {
return scheduleWorkflow.getFilesToDownload();
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/RunningSchedule.java
================================================
package io.linuxserver.davos.schedule;
import java.util.concurrent.ScheduledFuture;
public class RunningSchedule {
private final ScheduledFuture<?> future;
private final RunnableSchedule schedule;
public RunningSchedule(ScheduledFuture<?> future, RunnableSchedule schedule) {
this.future = future;
this.schedule = schedule;
}
public ScheduledFuture<?> getFuture() {
return future;
}
public RunnableSchedule getSchedule() {
return schedule;
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/ScheduleConfiguration.java
================================================
package io.linuxserver.davos.schedule;
import java.util.ArrayList;
import java.util.List;
import io.linuxserver.davos.schedule.workflow.actions.PostDownloadAction;
import io.linuxserver.davos.transfer.ftp.FileTransferType;
import io.linuxserver.davos.transfer.ftp.TransferProtocol;
import io.linuxserver.davos.transfer.ftp.client.UserCredentials;
public class ScheduleConfiguration {
private TransferProtocol connectionType;
private String hostname;
private int port;
private UserCredentials credentials;
private String remoteFilePath;
private String localFilePath;
private String scheduleName;
private List<String> filters = new ArrayList<String>();
private List<PostDownloadAction> actions = new ArrayList<PostDownloadAction>();
private FileTransferType transferType;
private boolean filtersMandatory;
private boolean invertFilters;
private boolean deleteHostFile;
public ScheduleConfiguration(final String scheduleName, final TransferProtocol protocol, final String hostname,
final int port, final UserCredentials credentials, final String remoteFilePath, final String localFilePath,
FileTransferType transferType, boolean filtersMandatory, boolean invertFilters, boolean deleteHostFile) {
this.scheduleName = scheduleName;
this.connectionType = protocol;
this.hostname = hostname;
this.port = port;
this.credentials = credentials;
this.localFilePath = localFilePath;
this.remoteFilePath = remoteFilePath;
this.transferType = transferType;
this.filtersMandatory = filtersMandatory;
this.invertFilters = invertFilters;
this.deleteHostFile = deleteHostFile;
}
public TransferProtocol getConnectionType() {
return connectionType;
}
public String getHostName() {
return hostname;
}
public int getPort() {
return port;
}
public UserCredentials getCredentials() {
return credentials;
}
public String getRemoteFilePath() {
return remoteFilePath;
}
public String getLocalFilePath() {
return localFilePath;
}
public List<String> getFilters() {
return filters;
}
public void setFilters(List<String> filters) {
this.filters = filters;
}
public String getScheduleName() {
return scheduleName;
}
public List<PostDownloadAction> getActions() {
return actions;
}
public void setActions(List<PostDownloadAction> actions) {
this.actions = actions;
}
public FileTransferType getTransferType() {
return transferType;
}
public boolean isFiltersMandatory() {
return filtersMandatory;
}
public boolean isInvertFilters() {
return invertFilters;
}
public boolean isDeleteHostFile() {
return deleteHostFile;
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactory.java
================================================
package io.linuxserver.davos.schedule;
import org.apache.commons.lang3.StringUtils;
import io.linuxserver.davos.persistence.model.ActionModel;
import io.linuxserver.davos.persistence.model.FilterModel;
import io.linuxserver.davos.persistence.model.HostModel;
import io.linuxserver.davos.persistence.model.ScheduleModel;
import io.linuxserver.davos.schedule.workflow.actions.HttpAPICallAction;
import io.linuxserver.davos.schedule.workflow.actions.MoveFileAction;
import io.linuxserver.davos.schedule.workflow.actions.PushbulletNotifyAction;
import io.linuxserver.davos.schedule.workflow.actions.SNSNotifyAction;
import io.linuxserver.davos.transfer.ftp.client.UserCredentials;
import io.linuxserver.davos.transfer.ftp.client.UserCredentials.Identity;
public class ScheduleConfigurationFactory {
public static ScheduleConfiguration createConfig(ScheduleModel model) {
ScheduleConfiguration config = new ScheduleConfiguration(model.name, model.host.protocol, model.host.address,
model.host.port, buildCredentials(model.host), model.remoteFilePath, model.localFilePath, model.transferType,
model.getFiltersMandatory(), model.getInvertFilters(), model.getDeleteHostFile());
if (StringUtils.isNotBlank(model.moveFileTo))
config.getActions().add(new MoveFileAction(config.getLocalFilePath(), model.moveFileTo));
if (null != model.filters)
addFilters(model, config);
if (null != model.actions)
addActions(model, config);
return config;
}
private static UserCredentials buildCredentials(HostModel host) {
if (host.isIdentityFileEnabled())
return new UserCredentials(host.username, new Identity(host.identityFile));
return new UserCredentials(host.username, host.password);
}
private static void addActions(ScheduleModel model, ScheduleConfiguration config) {
for (ActionModel action : model.actions) {
if ("pushbullet".equals(action.actionType))
config.getActions().add(new PushbulletNotifyAction(action.f1));
if ("sns".equals(action.actionType))
config.getActions().add(new SNSNotifyAction(action.f2, action.f1, action.f3, action.f4));
if ("api".equals(action.actionType))
config.getActions().add(new HttpAPICallAction(action.f1, action.f2, action.f3, action.f4));
}
}
private static void addFilters(ScheduleModel model, ScheduleConfiguration config) {
for (FilterModel filter : model.filters)
config.getFilters().add(filter.value);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/ScheduleExecutor.java
================================================
package io.linuxserver.davos.schedule;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.linuxserver.davos.exception.ScheduleAlreadyRunningException;
import io.linuxserver.davos.exception.ScheduleNotRunningException;
import io.linuxserver.davos.persistence.dao.ScheduleDAO;
import io.linuxserver.davos.persistence.model.ScheduleModel;
@Component
public class ScheduleExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleExecutor.class);
private Map<Long, RunningSchedule> runningSchedules = new HashMap<>();
@Resource
private ScheduleDAO scheduleConfigurationDAO;
private ScheduledExecutorService scheduledExecutorService;
public ScheduleExecutor() {
this.scheduledExecutorService = Executors.newScheduledThreadPool(10);
}
public boolean isScheduleRunning(Long id) {
return runningSchedules.containsKey(id);
}
public RunningSchedule getRunningSchedule(Long id) {
return runningSchedules.get(id);
}
@PostConstruct
public void runAutomaticStartupSchedules() {
LOGGER.info("Initialising automatic startup schedules");
for (ScheduleModel model : scheduleConfigurationDAO.getAll()) {
if (model.getStartAutomatically()) {
RunnableSchedule runnable = new RunnableSchedule(model.id, scheduleConfigurationDAO);
ScheduledFuture<?> runningSchedule = scheduledExecutorService.scheduleAtFixedRate(runnable, 0, model.interval,
TimeUnit.MINUTES);
runningSchedules.put(model.id, new RunningSchedule(runningSchedule, runnable));
}
}
LOGGER.info("Automatic startup schedules should now be running");
}
public void startSchedule(Long id) throws ScheduleAlreadyRunningException {
if (!runningSchedules.containsKey(id)) {
ScheduleModel model = scheduleConfigurationDAO.fetchSchedule(id);
RunnableSchedule runnable = new RunnableSchedule(model.id, scheduleConfigurationDAO);
LOGGER.info("Starting schedule {}", id);
ScheduledFuture<?> runningSchedule = scheduledExecutorService.scheduleAtFixedRate(runnable, 0, model.interval,
TimeUnit.MINUTES);
runningSchedules.put(model.id, new RunningSchedule(runningSchedule, runnable));
} else {
throw new ScheduleAlreadyRunningException();
}
}
public void stopSchedule(Long id) throws ScheduleNotRunningException {
if (runningSchedules.containsKey(id)) {
LOGGER.info("Stopping schedule {}", id);
ScheduledFuture<?> future = runningSchedules.get(id).getFuture();
if (!future.isCancelled()) {
future.cancel(true);
runningSchedules.remove(id);
LOGGER.info("Schedule should now be stopped");
}
} else {
throw new ScheduleNotRunningException();
}
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/ConnectWorkflowStep.java
================================================
package io.linuxserver.davos.schedule.workflow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.transfer.ftp.client.Client;
import io.linuxserver.davos.transfer.ftp.client.ClientFactory;
import io.linuxserver.davos.transfer.ftp.exception.FTPException;
public class ConnectWorkflowStep extends WorkflowStep {
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectWorkflowStep.class);
private ClientFactory clientFactory = new ClientFactory();
public ConnectWorkflowStep() {
this.nextStep = new FilterFilesWorkflowStep();
}
@Override
public void runStep(ScheduleWorkflow schedule) {
Client client = clientFactory.getClient(schedule.getConfig().getConnectionType());
client.setCredentials(schedule.getConfig().getCredentials());
client.setHost(schedule.getConfig().getHostName());
client.setPort(schedule.getConfig().getPort());
try {
LOGGER.info("Connecting to host {} on port {}", schedule.getConfig().getHostName(), schedule.getConfig().getPort());
schedule.setConnection(client.connect());
schedule.setClient(client);
LOGGER.info("Connection success. Moving onto next step");
nextStep.runStep(schedule);
} catch (FTPException e) {
LOGGER.error("Unable to create connection to {} on port {}. Falling back. Will try again next time.",
schedule.getConfig().getHostName(), schedule.getConfig().getPort());
LOGGER.error("Error was: {}", e.getMessage());
LOGGER.debug("Stacktrace", e);
}
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/DisconnectWorkflowStep.java
================================================
package io.linuxserver.davos.schedule.workflow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.transfer.ftp.exception.FTPException;
public class DisconnectWorkflowStep extends WorkflowStep {
private static final Logger LOGGER = LoggerFactory.getLogger(DisconnectWorkflowStep.class);
@Override
public void runStep(ScheduleWorkflow schedule) {
try {
schedule.getClient().disconnect();
} catch (FTPException e) {
LOGGER.error("Unable to disconnect from host. Error was: {}", e.getMessage());
LOGGER.debug("Stacktrace", e);
}
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/DownloadFilesWorkflowStep.java
================================================
package io.linuxserver.davos.schedule.workflow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.schedule.ScheduleConfiguration;
import io.linuxserver.davos.schedule.workflow.transfer.FTPTransfer;
import io.linuxserver.davos.schedule.workflow.transfer.TransferStrategy;
import io.linuxserver.davos.schedule.workflow.transfer.TransferStrategyFactory;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.connection.progress.ListenerFactory;
import io.linuxserver.davos.transfer.ftp.connection.progress.ProgressListener;
import io.linuxserver.davos.transfer.ftp.exception.FTPException;
public class DownloadFilesWorkflowStep extends WorkflowStep {
private static final Logger LOGGER = LoggerFactory.getLogger(DownloadFilesWorkflowStep.class);
private TransferStrategyFactory transferStrategyFactory = new TransferStrategyFactory();
public DownloadFilesWorkflowStep() {
this.nextStep = new DisconnectWorkflowStep();
}
@Override
public void runStep(ScheduleWorkflow schedule) {
ScheduleConfiguration config = schedule.getConfig();
TransferStrategy strategyToUse = transferStrategyFactory.getStrategy(config.getTransferType(), schedule.getConnection());
LOGGER.debug("Strategy chosen for downloads is {}, selected {}", config.getTransferType(), strategyToUse);
strategyToUse.setPostDownloadActions(schedule.getConfig().getActions());
LOGGER.debug("PostDownloadActions: {} have been set against chosen strategy", schedule.getConfig().getActions());
try {
if (schedule.getFilesToDownload().isEmpty())
LOGGER.info("There are no files to download in this run");
for (FTPTransfer transfer : schedule.getFilesToDownload()) {
LOGGER.debug("Generating listener for transfer");
FTPFile file = transfer.getFile();
ProgressListener listener = new ListenerFactory().createListener(config.getConnectionType());
schedule.getConnection().setProgressListener(listener);
transfer.setListener(listener);
strategyToUse.transferFile(transfer, config.getLocalFilePath());
if (config.isDeleteHostFile())
schedule.getConnection().deleteRemoteFile(file);
}
LOGGER.info("Download step complete. Moving onto next step");
schedule.getFilesToDownload().clear();
} catch (FTPException e) {
LOGGER.error("Unable to complete download. Error was: {}", e.getMessage());
LOGGER.debug("Stacktrace", e);
LOGGER.info("Clearing current queue and will still continue to next step");
schedule.getFilesToDownload().clear();
}
nextStep.runStep(schedule);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/FilterFilesWorkflowStep.java
================================================
package io.linuxserver.davos.schedule.workflow;
import static java.util.stream.Collectors.toList;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.schedule.workflow.filter.ReferentialFileFilter;
import io.linuxserver.davos.schedule.workflow.transfer.FTPTransfer;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.exception.FTPException;
import io.linuxserver.davos.util.PatternBuilder;
public class FilterFilesWorkflowStep extends WorkflowStep {
private static final Logger LOGGER = LoggerFactory.getLogger(FilterFilesWorkflowStep.class);
public FilterFilesWorkflowStep() {
this.nextStep = new DownloadFilesWorkflowStep();
this.backoutStep = new DisconnectWorkflowStep();
}
@Override
public void runStep(ScheduleWorkflow schedule) {
try {
List<String> filters = schedule.getConfig().getFilters();
List<FTPFile> allFiles = schedule.getConnection().listFiles(schedule.getConfig().getRemoteFilePath()).stream()
.filter(removeCurrentAndParentDirs()).collect(toList());
List<FTPFile> filesToFilter = new ReferentialFileFilter(schedule.getFilesFromLastScan()).filter(allFiles);
List<FTPFile> filteredFiles = new ArrayList<FTPFile>();
LOGGER.debug("Clearing pending download list");
schedule.getFilesToDownload().clear();
if (noFilteringRequired(schedule, filters)) {
LOGGER.info("Filter list was empty. Adding all found files to list");
LOGGER.debug("All files: {}", filesToFilter.stream().map(f -> f.getName()).collect(Collectors.toList()));
schedule.getFilesToDownload().addAll(filesToFilter.stream().map(f -> new FTPTransfer(f)).collect(toList()));
} else {
LOGGER.debug("Filters used {}", filters);
LOGGER.debug("Files to filter against {}", filesToFilter.stream().map(f -> f.getName()).collect(toList()));
boolean invertFilters = schedule.getConfig().isInvertFilters();
for (FTPFile file : filesToFilter)
filterFilesByName(invertFilters, filters, filteredFiles, file);
schedule.getFilesToDownload().addAll(filteredFiles.stream().map(f -> new FTPTransfer(f)).collect(toList()));
}
LOGGER.debug("Resetting files from scan to files in this scan");
schedule.getFilesFromLastScan().clear();
schedule.getFilesFromLastScan().addAll(allFiles.stream().map(f -> f.getName()).collect(toList()));
LOGGER.debug("Files from last scan set to {}", schedule.getFilesFromLastScan());
LOGGER.info("Filtered files. Moving onto next step");
nextStep.runStep(schedule);
} catch (FTPException e) {
LOGGER.error("Unable to filter files. Error message was: {}", e.getMessage());
LOGGER.debug("Stacktrace", e);
LOGGER.info("Backing out of this run.");
backoutStep.runStep(schedule);
}
}
private boolean noFilteringRequired(ScheduleWorkflow schedule, List<String> filters) {
return filters.isEmpty() && !schedule.getConfig().isFiltersMandatory();
}
private void filterFilesByName(boolean invertFilters, List<String> filters, List<FTPFile> filteredFiles, FTPFile file) {
if (invertFilters) {
boolean filterForFileFound = false;
for (String filter : filters) {
String expression = PatternBuilder.buildFromFilterString(filter);
if (file.getName().toLowerCase().matches(expression.toLowerCase()))
filterForFileFound = true;
}
if (!filterForFileFound) {
LOGGER.debug("Inverting enabled - no matching filter found for file {}, so adding to download list.", file.getName());
filteredFiles.add(file);
}
} else {
for (String filter : filters) {
String expression = PatternBuilder.buildFromFilterString(filter);
if (file.getName().toLowerCase().matches(expression.toLowerCase())) {
LOGGER.debug("Matched {} to {}. Adding to final filter list.", file.getName().toLowerCase(),
expression.toLowerCase());
filteredFiles.add(file);
return;
}
}
}
}
private Predicate<? super FTPFile> removeCurrentAndParentDirs() {
return file -> !file.getName().equals(".") && !file.getName().equals("..");
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/ScheduleWorkflow.java
================================================
package io.linuxserver.davos.schedule.workflow;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.schedule.ScheduleConfiguration;
import io.linuxserver.davos.schedule.workflow.transfer.FTPTransfer;
import io.linuxserver.davos.transfer.ftp.client.Client;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
public class ScheduleWorkflow {
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleWorkflow.class);
private ScheduleConfiguration config;
private Client client;
private Connection connection;
private List<String> filesFromLastScan = new ArrayList<>();
private List<FTPTransfer> filesToDownload = new ArrayList<>();
public ScheduleWorkflow(ScheduleConfiguration config) {
this.config = config;
}
protected Client getClient() {
return client;
}
protected ScheduleConfiguration getConfig() {
return config;
}
protected Connection getConnection() {
return connection;
}
public void start() {
LOGGER.info("Running schedule: {}", config.getScheduleName());
new ConnectWorkflowStep().runStep(this);
LOGGER.info("Finished schedule run: {}", config.getScheduleName());
}
protected void setConnection(Connection connection) {
this.connection = connection;
}
protected void setClient(Client client) {
this.client = client;
}
public List<String> getFilesFromLastScan() {
return filesFromLastScan;
}
public List<FTPTransfer> getFilesToDownload() {
return filesToDownload;
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/WorkflowStep.java
================================================
package io.linuxserver.davos.schedule.workflow;
public abstract class WorkflowStep {
protected WorkflowStep nextStep;
protected WorkflowStep backoutStep;
abstract public void runStep(ScheduleWorkflow schedule);
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/HttpAPICallAction.java
================================================
package io.linuxserver.davos.schedule.workflow.actions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
public class HttpAPICallAction implements PostDownloadAction {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpAPICallAction.class);
private RestTemplate restTemplate = new RestTemplate();
private String url;
private HttpMethod method;
private String contentType;
private String body;
public HttpAPICallAction(String url, String method, String contentType, String body) {
this.url = url;
this.method = HttpMethod.valueOf(method);
this.contentType = contentType;
this.body = body;
}
@Override
public void execute(PostDownloadExecution execution) {
try {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", contentType);
LOGGER.info("Sending message to generic API for {}", execution.fileName);
HttpEntity<String> httpEntity = new HttpEntity<String>(resolveFilename(body, execution.fileName), headers);
LOGGER.debug("Sending {} message {} to generic API: {}", method, httpEntity, url);
restTemplate.exchange(resolveFilename(url, execution.fileName), method, httpEntity, Object.class);
} catch (RestClientException | HttpMessageConversionException e) {
LOGGER.debug("Full stacktrace", e);
LOGGER.error("Unable to complete message to generic API. Given error: {}", e.getMessage());
}
}
@Override
public String toString() {
return getClass().getSimpleName();
}
private String resolveFilename(String value, String filename) {
return value.replace("$filename", filename);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/MoveFileAction.java
================================================
package io.linuxserver.davos.schedule.workflow.actions;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.util.FileUtils;
public class MoveFileAction implements PostDownloadAction {
private static final Logger LOGGER = LoggerFactory.getLogger(MoveFileAction.class);
private String currentFilePath;
private String newFilePath;
private FileUtils fileUtils = new FileUtils();
public MoveFileAction(String currentFilePath, String newFilePath) {
this.currentFilePath = FileUtils.ensureTrailingSlash(currentFilePath);
this.newFilePath = FileUtils.ensureTrailingSlash(newFilePath);
}
@Override
public void execute(PostDownloadExecution execution) {
try {
LOGGER.info("Executing move action: Moving {} to {}", execution.fileName, newFilePath);
fileUtils.moveFileToDirectory(currentFilePath + execution.fileName, newFilePath);
LOGGER.info("File successfully moved!");
} catch (IOException e) {
LOGGER.error("Unable to move {} to {}. Reason given: {}", execution.fileName, newFilePath, e.getMessage());
LOGGER.debug("Full stack trace on error", e);
}
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/PostDownloadAction.java
================================================
package io.linuxserver.davos.schedule.workflow.actions;
public interface PostDownloadAction {
void execute(PostDownloadExecution execution);
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/PostDownloadExecution.java
================================================
package io.linuxserver.davos.schedule.workflow.actions;
public class PostDownloadExecution {
public String fileName;
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/PushbulletNotifyAction.java
================================================
package io.linuxserver.davos.schedule.workflow.actions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
public class PushbulletNotifyAction implements PostDownloadAction {
private static final Logger LOGGER = LoggerFactory.getLogger(PushbulletNotifyAction.class);
private RestTemplate restTemplate = new RestTemplate();
private String apiKey;
public PushbulletNotifyAction(String apiKey) {
this.apiKey = apiKey;
}
@Override
public void execute(PostDownloadExecution execution) {
PushbulletRequest body = new PushbulletRequest();
body.body = execution.fileName;
body.title = "A new file has been downloaded";
body.type = "note";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Bearer " + apiKey);
try {
LOGGER.info("Sending notification to Pushbullet for {}", execution.fileName);
LOGGER.debug("API Key: {}", apiKey);
HttpEntity<PushbulletRequest> httpEntity = new HttpEntity<PushbulletRequest>(body, headers);
LOGGER.debug("Sending message to Pushbullet: {}", httpEntity);
restTemplate.exchange("https://api.pushbullet.com/v2/pushes", HttpMethod.POST, httpEntity, Object.class);
} catch (RestClientException | HttpMessageConversionException e ) {
LOGGER.debug("Full stacktrace", e);
LOGGER.error("Unable to complete notification to Pushbullet. Given error: {}", e.getMessage());
}
}
@Override
public String toString() {
return getClass().getSimpleName();
}
class PushbulletRequest {
public String type;
public String title;
public String body;
@Override
public String toString() {
return "PushbulletRequest [type=" + type + ", title=" + title + ", body=" + body + "]";
}
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/SNSNotifyAction.java
================================================
package io.linuxserver.davos.schedule.workflow.actions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
import com.amazonaws.services.sns.model.PublishRequest;
import com.amazonaws.services.sns.model.PublishResult;
public class SNSNotifyAction implements PostDownloadAction {
private static final Logger LOGGER = LoggerFactory.getLogger(SNSNotifyAction.class);
private AmazonSNSClientBuilder snsClientBuilder = AmazonSNSClient.builder();
private String region;
private String arn;
private String accessKey;
private String secretAccessKey;
public SNSNotifyAction(String region, String arn, String accessKey, String secretAccessKey) {
this.region = region;
this.arn = arn;
this.accessKey = accessKey;
this.secretAccessKey = secretAccessKey;
}
@Override
public void execute(PostDownloadExecution execution) {
AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretAccessKey);
AmazonSNS sns = snsClientBuilder.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(credentials)).build();
LOGGER.debug("SNS: Topic Arn : {}", arn);
LOGGER.debug("SNS: Topic Region : {}", region);
LOGGER.debug("SNS: Topic Access Key : {}", accessKey);
LOGGER.debug("SNS: Topic Secret Access Key : {}", secretAccessKey);
PublishRequest request = new PublishRequest();
request.setTopicArn(arn);
request.setMessageStructure("json");
request.setMessage(formatJsonMessage(execution.fileName));
request.setSubject("A new file has been downloaded");
LOGGER.info("Publishing message to SNS");
PublishResult result = sns.publish(request);
LOGGER.info("Publish successful!");
LOGGER.debug("{}", result.getMessageId());
}
private String formatJsonMessage(String message) {
return String.format("{\"default\": \"%s\"}", message);
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/filter/FileFilter.java
================================================
package io.linuxserver.davos.schedule.workflow.filter;
import java.util.List;
import io.linuxserver.davos.transfer.ftp.FTPFile;
public interface FileFilter {
List<FTPFile> filter(List<FTPFile> allFiles);
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/filter/ReferentialFileFilter.java
================================================
package io.linuxserver.davos.schedule.workflow.filter;
import static java.util.stream.Collectors.toList;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.transfer.ftp.FTPFile;
public class ReferentialFileFilter implements FileFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(ReferentialFileFilter.class);
private List<String> filesToCompareWith = new ArrayList<>();
public ReferentialFileFilter(List<String> files) {
filesToCompareWith = files;
}
@Override
public List<FTPFile> filter(List<FTPFile> allFiles) {
if (filesToCompareWith.isEmpty()) {
LOGGER.debug("No files in last scan. Using all files in this scan for filtering");
return allFiles;
}
LOGGER.debug("Files in last scan {}", filesToCompareWith);
LOGGER.debug("Files in this scan {}", allFiles.stream().map(f -> f.getName()).collect(toList()));
LOGGER.debug("Checking this scan for new files - comparing with files from last scan");
List<FTPFile> collectedFiles = allFiles.stream().filter(f -> !filesToCompareWith.contains(f.getName())).collect(toList());
LOGGER.debug("New files {}", collectedFiles.stream().map(f -> f.getName()).collect(toList()));
return collectedFiles;
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/filter/TemporalFileFilter.java
================================================
package io.linuxserver.davos.schedule.workflow.filter;
import static java.util.stream.Collectors.toList;
import java.util.List;
import java.util.function.Predicate;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.transfer.ftp.FTPFile;
public class TemporalFileFilter implements FileFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(TemporalFileFilter.class);
private DateTime lastRun;
public TemporalFileFilter(DateTime lastRun) {
this.lastRun = lastRun;
}
@Override
public List<FTPFile> filter(List<FTPFile> allFiles) {
return allFiles.stream().filter(after(lastRun)).collect(toList());
}
private Predicate<? super FTPFile> after(DateTime lastRun) {
LOGGER.debug("Filtering initial set of files by lastRun. Last run was {}", lastRun);
return f -> f.getLastModified().isAfter(lastRun);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FTPTransfer.java
================================================
package io.linuxserver.davos.schedule.workflow.transfer;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.connection.progress.ProgressListener;
public class FTPTransfer {
private State state = State.PENDING;
private final FTPFile file;
private ProgressListener listener;
public FTPTransfer(FTPFile file) {
this.file = file;
}
public FTPFile getFile() {
return file;
}
public ProgressListener getListener() {
return listener;
}
public void setListener(ProgressListener listener) {
this.listener = listener;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public enum State {
PENDING, DOWNLOADING, SKIPPED, FINISHED
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FilesAndFoldersTranferStrategy.java
================================================
package io.linuxserver.davos.schedule.workflow.transfer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
import io.linuxserver.davos.util.FileUtils;
public class FilesAndFoldersTranferStrategy extends TransferStrategy {
private static final Logger LOGGER = LoggerFactory.getLogger(FilesAndFoldersTranferStrategy.class);
public FilesAndFoldersTranferStrategy(Connection connection) {
super(connection);
}
@Override
public void transferFile(FTPTransfer transfer, String destination) {
FTPFile file = transfer.getFile();
String filename = file.getName();
String cleanFilePath = FileUtils.ensureTrailingSlash(file.getPath());
String cleanDestination = FileUtils.ensureTrailingSlash(destination);
LOGGER.info("Downloading {} to {}", cleanFilePath + filename, cleanDestination);
transfer.setState(FTPTransfer.State.DOWNLOADING);
connection.download(file, cleanDestination);
transfer.setState(FTPTransfer.State.FINISHED);
LOGGER.info("Successfully downloaded file.");
LOGGER.info("Running post download actions on {}", filename);
runPostDownloadAction(file);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FilesOnlyTransferStrategy.java
================================================
package io.linuxserver.davos.schedule.workflow.transfer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
import io.linuxserver.davos.util.FileUtils;
public class FilesOnlyTransferStrategy extends TransferStrategy {
private static final Logger LOGGER = LoggerFactory.getLogger(FilesOnlyTransferStrategy.class);
public FilesOnlyTransferStrategy(Connection connection) {
super(connection);
}
@Override
public void transferFile(FTPTransfer transfer, String destination) {
FTPFile file = transfer.getFile();
String filename = file.getName();
String cleanFilePath = FileUtils.ensureTrailingSlash(file.getPath());
String cleanDestination = FileUtils.ensureTrailingSlash(destination);
if (!file.isDirectory()) {
LOGGER.info("Downloading {} to {}", cleanFilePath + filename, cleanDestination);
transfer.setState(FTPTransfer.State.DOWNLOADING);
connection.download(file, cleanDestination);
transfer.setState(FTPTransfer.State.FINISHED);
LOGGER.info("Successfully downloaded file.");
LOGGER.info("Running post download actions on {}", filename);
runPostDownloadAction(file);
} else {
LOGGER.debug("Nullifying listener as it will never get used");
transfer.setState(FTPTransfer.State.SKIPPED);
transfer.setListener(null);
}
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategy.java
================================================
package io.linuxserver.davos.schedule.workflow.transfer;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.schedule.workflow.actions.PostDownloadAction;
import io.linuxserver.davos.schedule.workflow.actions.PostDownloadExecution;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
public abstract class TransferStrategy {
private static final Logger LOGGER = LoggerFactory.getLogger(TransferStrategy.class);
protected Connection connection;
private List<PostDownloadAction> postDownloadActions = new ArrayList<PostDownloadAction>();
public TransferStrategy(Connection connection) {
this.connection = connection;
}
public void setPostDownloadActions(List<PostDownloadAction> postDownloadActions) {
this.postDownloadActions = postDownloadActions;
}
@Override
public String toString() {
return getClass().getSimpleName();
}
public abstract void transferFile(FTPTransfer fileToTransfer, String destination);
protected void runPostDownloadAction(FTPFile file) {
if (null == postDownloadActions) {
LOGGER.warn("Post download actions have been nulled! This should not happen. Will not attempt run of actions");
return;
}
LOGGER.debug("Running actions...");
for (PostDownloadAction action : postDownloadActions) {
PostDownloadExecution execution = new PostDownloadExecution();
execution.fileName = file.getName();
action.execute(execution);
}
LOGGER.debug("Finished running actions...");
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategyFactory.java
================================================
package io.linuxserver.davos.schedule.workflow.transfer;
import io.linuxserver.davos.transfer.ftp.FileTransferType;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
public class TransferStrategyFactory {
public TransferStrategy getStrategy(FileTransferType type, Connection connection) {
if (FileTransferType.FILE.equals(type))
return new FilesOnlyTransferStrategy(connection);
return new FilesAndFoldersTranferStrategy(connection);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/FTPFile.java
================================================
package io.linuxserver.davos.transfer.ftp;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.joda.time.DateTime;
public class FTPFile {
private String name;
private long size;
private String path;
private DateTime lastModified;
private boolean directory;
public FTPFile(String name, long size, String path, long mTime, boolean directory) {
this.name = name;
this.size = size;
this.path = path;
this.lastModified = new DateTime(mTime);
this.directory = directory;
}
public String getName() {
return name;
}
public long getSize() {
return size;
}
public String getPath() {
return path;
}
public DateTime getLastModified() {
return lastModified;
}
public boolean isDirectory() {
return directory;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/FileTransferType.java
================================================
package io.linuxserver.davos.transfer.ftp;
public enum FileTransferType {
FILE, RECURSIVE;
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/TransferProtocol.java
================================================
package io.linuxserver.davos.transfer.ftp;
public enum TransferProtocol {
FTP, FTPS, SFTP;
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/Client.java
================================================
package io.linuxserver.davos.transfer.ftp.client;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
public abstract class Client {
protected String host;
protected int port;
protected UserCredentials userCredentials = UserCredentials.ANONYMOUS;
public void setCredentials(UserCredentials userCredentials) {
this.userCredentials = userCredentials;
}
public void setHost(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
public abstract Connection connect();
public abstract void disconnect();
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/ClientFactory.java
================================================
package io.linuxserver.davos.transfer.ftp.client;
import io.linuxserver.davos.transfer.ftp.TransferProtocol;
public class ClientFactory {
public Client getClient(TransferProtocol protocol) {
if (protocol.equals(TransferProtocol.SFTP))
return new SFTPClient();
if (protocol.equals(TransferProtocol.FTPS))
return new FTPSClient();
return new FTPClient();
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/FTPClient.java
================================================
package io.linuxserver.davos.transfer.ftp.client;
import java.io.IOException;
import java.net.SocketException;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
import io.linuxserver.davos.transfer.ftp.connection.ConnectionFactory;
import io.linuxserver.davos.transfer.ftp.exception.ClientConnectionException;
import io.linuxserver.davos.transfer.ftp.exception.ClientDisconnectException;
import io.linuxserver.davos.transfer.ftp.exception.FTPException;
public class FTPClient extends Client {
private static final Logger LOGGER = LoggerFactory.getLogger(FTPClient.class);
private ConnectionFactory connectionFactory = new ConnectionFactory();
protected org.apache.commons.net.ftp.FTPClient ftpClient;
public FTPClient() {
LOGGER.debug("Initialising FTP Client");
ftpClient = new org.apache.commons.net.ftp.FTPClient();
}
public Connection connect() {
try {
connectClientAndCheckStatus();
setSpecificModesOnClient();
login();
} catch (IOException e) {
throw new ClientConnectionException(String.format("Unable to connect to host %s on port %d", host, port), e);
}
return connectionFactory.createFTPConnection(ftpClient);
}
public void disconnect() {
try {
if (null == ftpClient)
throw new ClientDisconnectException("The underlying client was null.");
if (ftpClient.isConnected()) {
LOGGER.debug("Disconnecting...");
ftpClient.disconnect();
LOGGER.debug("Disconnected");
}
} catch (IOException e) {
throw new ClientDisconnectException("There was an unexpected error while trying to disconnect.", e);
}
}
private void connectClientAndCheckStatus() throws SocketException, IOException, FTPException {
LOGGER.debug("Connecting to {}:{}", host, port);
ftpClient.connect(host, port);
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
LOGGER.debug("Connection not made.");
LOGGER.debug("Response status: {}", replyCode);
LOGGER.debug("Disconnecting");
ftpClient.disconnect();
LOGGER.debug("Disconnected");
throw new ClientConnectionException(String.format("The host %s on port %d returned a bad status code.", host, port));
}
}
private void login() throws IOException, FTPException {
String username = userCredentials.getUsername();
String password = userCredentials.getPassword();
LOGGER.debug("Username: {}", username);
boolean hasLoggedIn = ftpClient.login(username, password);
if (!hasLoggedIn)
throw new ClientConnectionException(String.format("Unable to login for user %s", username));
ftpClient.setFileType(org.apache.commons.net.ftp.FTPClient.BINARY_FILE_TYPE);
}
private void setSpecificModesOnClient() throws IOException {
ftpClient.enterLocalPassiveMode();
ftpClient.setControlKeepAliveTimeout(300);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/FTPSClient.java
================================================
package io.linuxserver.davos.transfer.ftp.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FTPSClient extends FTPClient {
private static final Logger LOGGER = LoggerFactory.getLogger(FTPSClient.class);
public FTPSClient() {
LOGGER.debug("Initialising FTPS Client");
ftpClient = new org.apache.commons.net.ftp.FTPSClient();
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/SFTPClient.java
================================================
package io.linuxserver.davos.transfer.ftp.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import io.linuxserver.davos.transfer.ftp.client.UserCredentials.Identity;
import io.linuxserver.davos.transfer.ftp.connection.Connection;
import io.linuxserver.davos.transfer.ftp.connection.ConnectionFactory;
import io.linuxserver.davos.transfer.ftp.exception.ClientConnectionException;
import io.linuxserver.davos.transfer.ftp.exception.ClientDisconnectException;
public class SFTPClient extends Client {
private static final Logger LOGGER = LoggerFactory.getLogger(SFTPClient.class);
private JSch jsch;
private ConnectionFactory connectionFactory;
private Session session;
private Channel channel;
public SFTPClient() {
this.jsch = new JSch();
this.connectionFactory = new ConnectionFactory();
}
@Override
public Connection connect() {
session = null;
channel = null;
try {
configureSessionAndConnect();
openChannelFromSession();
} catch (JSchException e) {
throw new ClientConnectionException(String.format("Unable to connect to host %s on port %d", host, port), e);
}
return connectionFactory.createSFTPConnection(channel);
}
@Override
public void disconnect() {
if (null == channel || null == session)
throw new ClientDisconnectException("The underlying connection was never initially made.");
LOGGER.debug("Disconnecting from channel");
channel.disconnect();
LOGGER.debug("Disconnecting from session");
session.disconnect();
}
private void configureSessionAndConnect() throws JSchException {
LOGGER.debug("Configuring connection credentials and options on session");
Identity identity = userCredentials.getIdentity();
if (null != identity) {
String identityFile = identity.getIdentityFile();
LOGGER.debug("SSH identity found ({}). Setting against session", identityFile);
jsch.addIdentity(identityFile);
}
String username = userCredentials.getUsername();
String password = userCredentials.getPassword();
LOGGER.debug("Username: {}", username);
session = jsch.getSession(username, host, port);
session.setConfig("StrictHostKeyChecking", "no");
// I'm going to have to think of a nicer way of doing this...
if (null == userCredentials.getIdentity())
session.setPassword(password);
session.connect();
LOGGER.debug("Connected to session");
}
private void openChannelFromSession() throws JSchException {
LOGGER.debug("Opening SFTP channel from session");
channel = session.openChannel("sftp");
channel.connect();
LOGGER.debug("Connected to channel");
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/UserCredentials.java
================================================
package io.linuxserver.davos.transfer.ftp.client;
public class UserCredentials {
public static final UserCredentials ANONYMOUS = new UserCredentials("anonymous", "stark@linuxserver.io");
private String username;
private String password;
private Identity identity;
public UserCredentials(final String username, final String password) {
this.username = username;
this.password = password;
}
public UserCredentials(final String username, final Identity identity) {
this.username = username;
this.identity = identity;
}
public Identity getIdentity() {
return identity;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public static class Identity {
private final String identityFile;
public Identity(String identityFile) {
this.identityFile = identityFile;
}
public String getIdentityFile() {
return identityFile;
}
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/Connection.java
================================================
package io.linuxserver.davos.transfer.ftp.connection;
import java.util.List;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.connection.progress.ProgressListener;
import io.linuxserver.davos.transfer.ftp.exception.FTPException;
public interface Connection {
String currentDirectory() throws FTPException;
void download(FTPFile remoteFilePath, String localFilePath) throws FTPException;
void deleteRemoteFile(FTPFile file) throws FTPException;
List<FTPFile> listFiles() throws FTPException;
List<FTPFile> listFiles(String remoteDirectory) throws FTPException;
void setProgressListener(ProgressListener progressListener);
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/ConnectionFactory.java
================================================
package io.linuxserver.davos.transfer.ftp.connection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
public class ConnectionFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionFactory.class);
public SFTPConnection createSFTPConnection(Channel channel) {
LOGGER.debug("Creating SFTP connection for channel {}", channel);
return new SFTPConnection((ChannelSftp) channel);
}
public FTPConnection createFTPConnection(org.apache.commons.net.ftp.FTPClient client) {
LOGGER.debug("Creating FTP connection for client {}", client);
return new FTPConnection(client);
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/FTPConnection.java
================================================
package io.linuxserver.davos.transfer.ftp.connection;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.io.output.CountingOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.linuxserver.davos.transfer.ftp.FTPFile;
import io.linuxserver.davos.transfer.ftp.connection.progress.ProgressListener;
import io.linuxserver.davos.transfer.ftp.exception.DeleteFileException;
import io.linuxserver.davos.transfer.ftp.exception.DownloadFailedException;
import io.linuxserver.davos.transfer.ftp.exception.FTPException;
import io.linuxserver.davos.transfer.ftp.exception.FileListingException;
import io.linuxserver.davos.util.FileStreamFactory;
import io.linuxserver.davos.util.FileUtils;
public class FTPConnection implements Connection {
private static final Logger LOGGER = LoggerFactory.getLogger(FTPConnection.class);
private org.apache.commons.net.ftp.FTPClient client;
private FileStreamFactory fileStreamFactory = new FileStreamFactory();
private FileUtils fileUtils = new FileUtils();
private ProgressListener progressListener;
public FTPConnection(org.apache.commons.net.ftp.FTPClient client) {
this.client = client;
}
@Override
public String currentDirectory() {
try {
String workingDirectory = client.printWorkingDirectory();
LOGGER.debug("{}", workingDirectory);
return workingDirectory;
} catch (IOException e) {
throw new FileListingException("Unable to print the working directory", e);
}
}
@Override
public void download(FTPFile file, String localFilePath) {
String cleanRemotePath = FileUtils.ensureTrailingSlash(file.getPath()) + file.getName();
String cleanLocalPath = FileUtils.ensureTrailingSlash(localFilePath);
LOGGER.debug("Remote path: {}", cleanRemotePath);
LOGGER.debug("Local path: {}", cleanLocalPath);
try {
if (file.isDirectory())
downloadDirectoryAndContents(file, cleanLocalPath, cleanRemotePath);
else
doDownload(file, cleanRemotePath, cleanLocalPath);
} catch (FileNotFoundException e) {
throw new DownloadFailedException(
String.format("Unable to write to local directory %s", cleanLocalPath + file.getName()), e);
} catch (IOException e) {
throw new DownloadFailedException(String.format("Unable to download file %s", cleanRemotePath), e);
}
}
@Override
public List<FTPFile> listFiles() {
return listFiles(currentDirectory());
}
@Override
public List<FTPFile> listFiles(String remoteDirectory) {
List<FTPFile> files = new ArrayList<FTPFile>();
try {
String cleanRemoteDirectory = FileUtils.ensureTrailingSlash(remoteDirectory);
LOGGER.debug("Listing all files in {}", cleanRemoteDirectory);
org.apache.commons.net.ftp.FTPFile[] ftpFiles = client.listFiles(cleanRemoteDirectory);
for (org.apache.commons.net.ftp.FTPFile file : ftpFiles)
files.add(toFtpFile(file, cleanRemoteDirectory));
LOGGER.debug("{}", files);
} catch (IOException e) {
throw new FileListingException(String.format("Unable to list files in directory %s", remoteDirectory), e);
}
return files.stream().filter(removeCurrentAndParentDirs()).collect(Collectors.toList());
}
@Override
public void setProgressListener(ProgressListener progressListener) {
this.progressListener = progressListener;
}
private CountingOutputStream listenOn(OutputStream outputStream) {
LOGGER.debug("Creating wrapping output stream for progress listener");
CountingOutputStream countingStream = new CountingOutputStream(outputStream) {
@Override
protected void beforeWrite(int n) {
super.beforeWrite(n);
progressListener.setBytesWritten(getByteCount());
}
};
return countingStream;
}
private void doDownload(FTPFile file, String cleanRemotePath, String cleanLocalPath)
throws FileNotFoundException, IOException {
LOGGER.info("Downloading {} to {}", cleanRemotePath, cleanLocalPath);
LOGGER.debug("Creating output stream for file {}", cleanLocalPath + file.getName());
OutputStream outputStream = fileStreamFactory.createOutputStream(cleanLocalPath + file.getName());
boolean hasDownloaded;
if (null != progressListener) {
LOGGER.debug("ProgressListener has been set. Initialising...");
LOGGER.debug("Total file size is {}", file.getSize());
progressListener.reset();
progressListener.setTotalBytes(file.getSize());
progressListener.start();
hasDownloaded = client.retrieveFile(cleanRemotePath, listenOn(outputStream));
} else
hasDownloaded = client.retrieveFile(cleanRemotePath, outputStream);
outputStream.close();
if (!hasDownloaded)
throw new DownloadFailedException("Server returned failure while downloading.");
}
private void downloadDirectoryAndContents(FTPFile file, String localDownloadFolder, String path) throws IOException {
LOGGER.info("Item {} is a directory. Will now check sub-items", file.getName());
List<FTPFile> subItems = listFiles(path).stream().filter(removeCurrentAndParentDirs()).collect(Collectors.toList());
LOGGER.debug("Counted {} sub items.", subItems.size());
String fullLocalDownloadPath = FileUtils.ensureTrailingSlash(localDownloadFolder + file.getName());
LOGGER.debug("Creating new local directory {}", fullLocalDownloadPath);
fileUtils.createLocalDirectory(fullLocalDownloadPath);
for (FTPFile subItem : subItems) {
String subItemPath = FileUtils.ensureTrailingSlash(subItem.getPath()) + subItem.getName();
LOGGER.debug("Download. Sub item path: {}", subItemPath);
if (subItem.isDirectory()) {
String subLocalFilePath = FileUtils.ensureTrailingSlash(fullLocalDownloadPath);
downloadDirectoryAndContents(subItem, subLocalFilePath, FileUtils.ensureTrailingSlash(subItemPath));
}
else
doDownload(subItem, subItemPath, fullLocalDownloadPath);
}
}
private Predicate<? super FTPFile> removeCurrentAndParentDirs() {
return file -> !file.getName().equals(".") && !file.getName().equals("..");
}
private FTPFile toFtpFile(org.apache.commons.net.ftp.FTPFile ftpFile, String filePath) throws IOException {
String name = ftpFile.getName();
long fileSize = ftpFile.getSize();
long mTime = ftpFile.getTimestamp().getTime().getTime();
boolean isDirectory = ftpFile.isDirectory();
return new FTPFile(name, fileSize, filePath, mTime, isDirectory);
}
@Override
public void deleteRemoteFile(FTPFile file) throws FTPException {
String cleanRemotePath = FileUtils.ensureTrailingSlash(file.getPath()) + file.getName();
LOGGER.debug("Deleting remote file {}", cleanRemotePath);
try {
if (file.isDirectory()) {
deleteDirectoryAndContents(file, cleanRemotePath);
} else
doDelete(cleanRemotePath);
} catch (IOException e) {
LOGGER.debug("client#deleteFile() threw exception. Assuming file not deleted");
throw new DeleteFileException("Unable to delete file on remote server", e);
}
}
private void deleteDirectoryAndContents(FTPFile file, String remoteDirectoryPath) throws IOException {
LOGGER.info("Item {} is a directory. Will now check sub-items", file.getName());
List<FTPFile> subItems = listFiles(remoteDirectoryPath).stream().filter(removeCurrentAndParentDirs())
.collect(Collectors.toList());
for (FTPFile subItem : subItems) {
String subItemPath = FileUtils.ensureTrailingSlash(subItem.getPath()) + subItem.getName();
LOGGER.debug("Delete. Sub item path: {}", subItemPath);
if (subItem.isDirectory())
deleteDirectoryAndContents(subItem, subItemPath);
else
doDelete(subItemPath);
}
LOGGER.debug("Removing empty directory {}", remoteDirectoryPath);
client.removeDirectory(remoteDirectoryPath);
}
private void doDelete(String subItemPath) throws IOException {
LOGGER.debug("Deleting file: {}", subItemPath);
boolean deleted = client.deleteFile(subItemPath);
LOGGER.debug("File deleted");
if (!deleted)
throw new DeleteFileException("Unable to delete file on remote server. Unknown reason");
}
}
================================================
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/SFTPConnection.java
================================================
package io.linuxserver.davos.transfer.ftp.connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jcraft.jsch.ChannelSftp;
import co
gitextract_1q48vioe/ ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── conf/ │ ├── local/ │ │ ├── application.properties │ │ └── log4j2.xml │ └── release/ │ ├── application.properties │ └── log4j2.xml ├── docs/ │ ├── Makefile │ ├── make.bat │ └── source/ │ ├── conf.py │ ├── developers/ │ │ └── index.rst │ ├── faq/ │ │ └── index.rst │ ├── guides/ │ │ ├── appsettings.rst │ │ ├── gettingstarted/ │ │ │ ├── hosts.rst │ │ │ ├── index.rst │ │ │ └── schedules.rst │ │ ├── index.rst │ │ └── installation.rst │ ├── index.rst │ ├── reference/ │ │ ├── api.rst │ │ └── index.rst │ └── requirements.txt ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── src/ │ ├── cucumber/ │ │ ├── java/ │ │ │ └── io/ │ │ │ └── linuxserver/ │ │ │ └── davos/ │ │ │ └── bdd/ │ │ │ ├── ClientStepDefs.java │ │ │ ├── ScheduleStepDefs.java │ │ │ ├── ServerStepDefs.java │ │ │ └── helpers/ │ │ │ ├── FakeFTPServerFactory.java │ │ │ ├── FakeSFTPServerFactory.java │ │ │ └── Logging.java │ │ └── resources/ │ │ ├── Client.feature │ │ └── Schedule.feature │ ├── main/ │ │ ├── java/ │ │ │ └── io/ │ │ │ └── linuxserver/ │ │ │ └── davos/ │ │ │ ├── DavosApplication.java │ │ │ ├── Version.java │ │ │ ├── converters/ │ │ │ │ ├── Converter.java │ │ │ │ ├── HostConverter.java │ │ │ │ └── ScheduleConverter.java │ │ │ ├── delegation/ │ │ │ │ └── services/ │ │ │ │ ├── HostService.java │ │ │ │ ├── HostServiceImpl.java │ │ │ │ ├── ScheduleService.java │ │ │ │ ├── ScheduleServiceImpl.java │ │ │ │ ├── SettingsService.java │ │ │ │ └── SettingsServiceImpl.java │ │ │ ├── dto/ │ │ │ │ ├── ActionDTO.java │ │ │ │ ├── FTPFileDTO.java │ │ │ │ ├── FilterDTO.java │ │ │ │ ├── HostDTO.java │ │ │ │ ├── ScheduleDTO.java │ │ │ │ └── ScheduleProcessResponse.java │ │ │ ├── exception/ │ │ │ │ ├── HostInUseException.java │ │ │ │ ├── ScheduleAlreadyRunningException.java │ │ │ │ └── ScheduleNotRunningException.java │ │ │ ├── logging/ │ │ │ │ └── LoggingManager.java │ │ │ ├── persistence/ │ │ │ │ ├── dao/ │ │ │ │ │ ├── DefaultHostDAO.java │ │ │ │ │ ├── DefaultScheduleDAO.java │ │ │ │ │ ├── HostDAO.java │ │ │ │ │ └── ScheduleDAO.java │ │ │ │ ├── model/ │ │ │ │ │ ├── ActionModel.java │ │ │ │ │ ├── FilterModel.java │ │ │ │ │ ├── HostModel.java │ │ │ │ │ ├── ScannedFileModel.java │ │ │ │ │ └── ScheduleModel.java │ │ │ │ └── repository/ │ │ │ │ ├── HostRepository.java │ │ │ │ └── ScheduleRepository.java │ │ │ ├── schedule/ │ │ │ │ ├── RunnableSchedule.java │ │ │ │ ├── RunningSchedule.java │ │ │ │ ├── ScheduleConfiguration.java │ │ │ │ ├── ScheduleConfigurationFactory.java │ │ │ │ ├── ScheduleExecutor.java │ │ │ │ └── workflow/ │ │ │ │ ├── ConnectWorkflowStep.java │ │ │ │ ├── DisconnectWorkflowStep.java │ │ │ │ ├── DownloadFilesWorkflowStep.java │ │ │ │ ├── FilterFilesWorkflowStep.java │ │ │ │ ├── ScheduleWorkflow.java │ │ │ │ ├── WorkflowStep.java │ │ │ │ ├── actions/ │ │ │ │ │ ├── HttpAPICallAction.java │ │ │ │ │ ├── MoveFileAction.java │ │ │ │ │ ├── PostDownloadAction.java │ │ │ │ │ ├── PostDownloadExecution.java │ │ │ │ │ ├── PushbulletNotifyAction.java │ │ │ │ │ └── SNSNotifyAction.java │ │ │ │ ├── filter/ │ │ │ │ │ ├── FileFilter.java │ │ │ │ │ ├── ReferentialFileFilter.java │ │ │ │ │ └── TemporalFileFilter.java │ │ │ │ └── transfer/ │ │ │ │ ├── FTPTransfer.java │ │ │ │ ├── FilesAndFoldersTranferStrategy.java │ │ │ │ ├── FilesOnlyTransferStrategy.java │ │ │ │ ├── TransferStrategy.java │ │ │ │ └── TransferStrategyFactory.java │ │ │ ├── transfer/ │ │ │ │ └── ftp/ │ │ │ │ ├── FTPFile.java │ │ │ │ ├── FileTransferType.java │ │ │ │ ├── TransferProtocol.java │ │ │ │ ├── client/ │ │ │ │ │ ├── Client.java │ │ │ │ │ ├── ClientFactory.java │ │ │ │ │ ├── FTPClient.java │ │ │ │ │ ├── FTPSClient.java │ │ │ │ │ ├── SFTPClient.java │ │ │ │ │ └── UserCredentials.java │ │ │ │ ├── connection/ │ │ │ │ │ ├── Connection.java │ │ │ │ │ ├── ConnectionFactory.java │ │ │ │ │ ├── FTPConnection.java │ │ │ │ │ ├── SFTPConnection.java │ │ │ │ │ └── progress/ │ │ │ │ │ ├── ListenerFactory.java │ │ │ │ │ ├── ProgressListener.java │ │ │ │ │ └── SFTPProgressListener.java │ │ │ │ └── exception/ │ │ │ │ ├── ClientConnectionException.java │ │ │ │ ├── ClientDisconnectException.java │ │ │ │ ├── DeleteFileException.java │ │ │ │ ├── DownloadFailedException.java │ │ │ │ ├── FTPException.java │ │ │ │ └── FileListingException.java │ │ │ ├── util/ │ │ │ │ ├── FileStreamFactory.java │ │ │ │ ├── FileUtils.java │ │ │ │ └── PatternBuilder.java │ │ │ └── web/ │ │ │ ├── API.java │ │ │ ├── Filter.java │ │ │ ├── Host.java │ │ │ ├── Notifications.java │ │ │ ├── Pushbullet.java │ │ │ ├── SNS.java │ │ │ ├── Schedule.java │ │ │ ├── ScheduleCommand.java │ │ │ ├── Settings.java │ │ │ ├── Transfer.java │ │ │ ├── VersionChecker.java │ │ │ ├── controller/ │ │ │ │ ├── APIController.java │ │ │ │ ├── FragmentController.java │ │ │ │ ├── ViewController.java │ │ │ │ └── response/ │ │ │ │ ├── APIResponse.java │ │ │ │ └── APIResponseBuilder.java │ │ │ └── selectors/ │ │ │ ├── IntervalSelector.java │ │ │ ├── LogLevelSelector.java │ │ │ ├── MethodSelector.java │ │ │ ├── ProtocolSelector.java │ │ │ └── TransferSelector.java │ │ └── resources/ │ │ ├── static/ │ │ │ ├── browserconfig.xml │ │ │ ├── css/ │ │ │ │ └── davos.css │ │ │ ├── js/ │ │ │ │ └── davos.js │ │ │ └── manifest.json │ │ └── templates/ │ │ ├── fragments/ │ │ │ ├── api.html │ │ │ ├── filter.html │ │ │ ├── header.html │ │ │ ├── pushbullet.html │ │ │ ├── sns.html │ │ │ └── transfers.html │ │ └── v2/ │ │ ├── edit-host.html │ │ ├── edit-schedule.html │ │ ├── hosts.html │ │ ├── schedules.html │ │ └── settings.html │ └── test/ │ └── java/ │ └── io/ │ └── linuxserver/ │ └── davos/ │ ├── VersionTest.java │ ├── delegation/ │ │ └── services/ │ │ ├── ScheduleServiceImplTest.java │ │ └── SettingsServiceImplTest.java │ ├── persistence/ │ │ └── dao/ │ │ └── DefaultScheduleDAOTest.java │ ├── schedule/ │ │ ├── ScheduleConfigurationFactoryTest.java │ │ ├── ScheduleExecutorTest.java │ │ └── workflow/ │ │ ├── ConnectWorkflowStepTest.java │ │ ├── DisconnectWorkflowStepTest.java │ │ ├── DownloadFilesWorkflowStepTest.java │ │ ├── FilterFilesWorkflowStepTest.java │ │ ├── actions/ │ │ │ ├── HttpAPICallActionTest.java │ │ │ ├── MoveFileActionTest.java │ │ │ └── PushbulletNotifyActionTest.java │ │ ├── filter/ │ │ │ └── ReferentialFileFilterTest.java │ │ └── transfer/ │ │ ├── FilesAndFoldersTranferStrategyTest.java │ │ ├── FilesOnlyTransferStrategyTest.java │ │ ├── TransferStrategyFactoryTest.java │ │ └── TransferStrategyTest.java │ ├── transfer/ │ │ └── ftp/ │ │ ├── client/ │ │ │ ├── ClientFactoryTest.java │ │ │ ├── FTPClientTest.java │ │ │ ├── FTPSClientTest.java │ │ │ └── SFTPClientTest.java │ │ └── connection/ │ │ ├── FTPConnectionTest.java │ │ ├── SFTPConnectionTest.java │ │ └── progress/ │ │ ├── ListenerFactoryTest.java │ │ ├── ProgressListenerTest.java │ │ └── SFTPProgressListenerTest.java │ ├── util/ │ │ └── PatternBuilderTest.java │ └── web/ │ └── controller/ │ ├── APIControllerTest.java │ └── ViewControllerTest.java └── version.txt
SYMBOL INDEX (847 symbols across 139 files)
FILE: src/cucumber/java/io/linuxserver/davos/bdd/ClientStepDefs.java
class ClientStepDefs (line 23) | public class ClientStepDefs {
method after (line 31) | @After("@Client")
method davos_connects_to_the_server (line 36) | @When("^davos connects to the server$")
method davos_connects_to_the_SFTP_server (line 47) | @When("^davos connects to the SFTP server$")
method deletes_an_SFTP_directory (line 58) | @When("^deletes an SFTP directory$")
method the_SFTP_directory_is_deleted_on_the_server (line 63) | @Then("^the SFTP directory is deleted on the server$")
method listing_the_files_will_show_the_correct_files (line 68) | @Then("^listing the files will show the correct files$")
method downloads_a_file (line 79) | @When("^downloads a file$")
method the_file_is_located_in_the_specified_local_directory (line 84) | @Then("^the file is located in the specified local directory$")
method initialises_a_Progress_Listener_for_that_connection (line 92) | @When("^initialises a Progress Listener for that connection$")
method the_Progress_Listener_will_have_its_values_updated (line 99) | @Then("^the Progress Listener will have its values updated$")
method deletes_a_directory (line 106) | @When("^deletes a directory$")
method the_directory_is_deleted_on_the_server (line 111) | @Then("^the directory is deleted on the server$")
class CountingFTPProgressListener (line 116) | class CountingFTPProgressListener extends ProgressListener {
method setBytesWritten (line 120) | @Override
method getTimesCalled (line 126) | public int getTimesCalled() {
FILE: src/cucumber/java/io/linuxserver/davos/bdd/ScheduleStepDefs.java
class ScheduleStepDefs (line 21) | public class ScheduleStepDefs {
method a_schedule_exists_for_that_server_with_filters (line 27) | @Given("^a schedule exists for that server, with filters$")
method the_schedule_is_set_to_delete_host_files (line 41) | @Given("^the schedule is set to delete host files$")
method the_schedule_is_set_to_invert_filters (line 46) | @Given("^the schedule is set to invert filters$")
method the_schedule_is_set_to_have_mandatory_filters (line 51) | @Given("^the schedule is set to have mandatory filters$")
method a_schedule_exists_for_that_server (line 56) | @Given("^a schedule exists for that server, without filters$")
method that_schedule_is_run (line 61) | @When("^that schedule is run$")
method no_files_are_downloaded (line 66) | @Then("^no files are downloaded$")
method all_files_not_matching_the_filters_are_downloaded (line 78) | @Then("^all files not matching the filters are downloaded$")
method those_files_are_deleted_on_the_host (line 92) | @Then("^those files are deleted on the host$")
method only_the_filtered_files_are_downloaded (line 100) | @Then("^only the filtered files are downloaded$")
method createBasicSchedule (line 115) | private void createBasicSchedule() {
class CucumberScheduleConfigurationDAO (line 129) | class CucumberScheduleConfigurationDAO implements ScheduleDAO {
method getAll (line 131) | @Override
method fetchSchedule (line 136) | @Override
method updateConfig (line 141) | @Override
method fetchSchedulesUsingHost (line 146) | @Override
method updateScannedFilesOnSchedule (line 152) | @Override
method deleteSchedule (line 158) | @Override
FILE: src/cucumber/java/io/linuxserver/davos/bdd/ServerStepDefs.java
class ServerStepDefs (line 15) | public class ServerStepDefs {
method there_is_an_FTP_server_running (line 19) | @Given("^there is an FTP server running$")
method the_FTP_server_has_a_directory_with_contents (line 24) | @Given("^the FTP server has a directory with contents$")
method the_FTP_server_has_a_directory_without_contents (line 29) | @Given("^the FTP server has a directory without contents$")
method there_is_an_SFTP_server_running (line 34) | @Given("^there is an SFTP server running$")
method the_SFTP_server_has_a_directory_with_contents (line 39) | @Given("^the SFTP server has a directory with contents$")
method the_SFTP_server_has_a_directory_without_contents (line 50) | @Given("^the SFTP server has a directory without contents$")
method after (line 55) | @After("@Server")
method afterSFTP (line 60) | @After("@SFTPServer")
FILE: src/cucumber/java/io/linuxserver/davos/bdd/helpers/FakeFTPServerFactory.java
class FakeFTPServerFactory (line 10) | public class FakeFTPServerFactory {
method getPort (line 14) | public static int getPort() {
method setup (line 18) | public static FakeFtpServer setup() {
method checkFileExists (line 36) | public static boolean checkFileExists(String filePath) {
method addDirectoryWithNameAndNumberOfFiles (line 40) | public static void addDirectoryWithNameAndNumberOfFiles(String name, i...
method stop (line 49) | public static void stop() {
FILE: src/cucumber/java/io/linuxserver/davos/bdd/helpers/FakeSFTPServerFactory.java
class FakeSFTPServerFactory (line 23) | public class FakeSFTPServerFactory {
method setup (line 31) | public static void setup() throws IOException {
method stop (line 59) | public static void stop() throws IOException {
method addDirectoryWithNameAndNumberOfFiles (line 63) | public static void addDirectoryWithNameAndNumberOfFiles(String name, i...
method getPort (line 73) | public static int getPort() {
FILE: src/cucumber/java/io/linuxserver/davos/bdd/helpers/Logging.java
class Logging (line 8) | public class Logging {
method before (line 10) | @Before
FILE: src/main/java/io/linuxserver/davos/DavosApplication.java
class DavosApplication (line 6) | @SpringBootApplication
method main (line 9) | public static void main(String[] args) {
FILE: src/main/java/io/linuxserver/davos/Version.java
class Version (line 3) | public class Version {
method Version (line 9) | public Version(int major, int minor, int patch) {
method Version (line 16) | public Version(String version) {
method getMajor (line 25) | public int getMajor() {
method getMinor (line 29) | public int getMinor() {
method getPatch (line 33) | public int getPatch() {
method isNewerThan (line 37) | public boolean isNewerThan(Version version) {
method toString (line 53) | @Override
FILE: src/main/java/io/linuxserver/davos/converters/Converter.java
type Converter (line 3) | public interface Converter<S, T> {
method convertTo (line 5) | T convertTo(S source);
method convertFrom (line 7) | S convertFrom(T source);
FILE: src/main/java/io/linuxserver/davos/converters/HostConverter.java
class HostConverter (line 10) | @Component
method convertTo (line 13) | @Override
method convertFrom (line 31) | @Override
FILE: src/main/java/io/linuxserver/davos/converters/ScheduleConverter.java
class ScheduleConverter (line 23) | @Component
method convertTo (line 28) | @Override
method convertFrom (line 97) | @Override
FILE: src/main/java/io/linuxserver/davos/delegation/services/HostService.java
type HostService (line 7) | public interface HostService {
method fetchAllHosts (line 9) | List<Host> fetchAllHosts();
method fetchHost (line 11) | Host fetchHost(Long id);
method saveHost (line 13) | Host saveHost(Host host);
method deleteHost (line 15) | void deleteHost(Long id);
method fetchSchedulesUsingHost (line 17) | List<Long> fetchSchedulesUsingHost(Long id);
method testConnection (line 19) | void testConnection(Host host);
FILE: src/main/java/io/linuxserver/davos/delegation/services/HostServiceImpl.java
class HostServiceImpl (line 23) | @Component
method fetchHost (line 37) | @Override
method saveHost (line 42) | @Override
method deleteHost (line 49) | @Override
method fetchAllHosts (line 61) | @Override
method toHost (line 66) | private Host toHost(HostModel model) {
method fetchSchedulesUsingHost (line 70) | @Override
method testConnection (line 75) | @Override
FILE: src/main/java/io/linuxserver/davos/delegation/services/ScheduleService.java
type ScheduleService (line 7) | public interface ScheduleService {
method startSchedule (line 9) | void startSchedule(Long id);
method stopSchedule (line 11) | void stopSchedule(Long id);
method deleteSchedule (line 13) | void deleteSchedule(Long id);
method fetchAllSchedules (line 15) | List<Schedule> fetchAllSchedules();
method fetchSchedule (line 17) | Schedule fetchSchedule(Long id);
method createSchedule (line 19) | Schedule createSchedule(Schedule schedule);
method updateSchedule (line 21) | Schedule updateSchedule(Schedule schedule);
method clearScannedFilesFromSchedule (line 23) | void clearScannedFilesFromSchedule(Long id);
FILE: src/main/java/io/linuxserver/davos/delegation/services/ScheduleServiceImpl.java
class ScheduleServiceImpl (line 25) | @Component
method startSchedule (line 45) | @Override
method stopSchedule (line 53) | @Override
method deleteSchedule (line 61) | @Override
method fetchAllSchedules (line 73) | @Override
method fetchSchedule (line 78) | @Override
method createSchedule (line 83) | @Override
method updateSchedule (line 91) | @Override
method clearScannedFilesFromSchedule (line 106) | @Override
method getHostForSchedule (line 114) | private HostModel getHostForSchedule(Long id) {
method toSchedule (line 127) | private Schedule toSchedule(ScheduleModel model) {
method toTransfer (line 142) | private Transfer toTransfer(FTPTransfer ftpTransfer) {
FILE: src/main/java/io/linuxserver/davos/delegation/services/SettingsService.java
type SettingsService (line 6) | public interface SettingsService {
method setLoggingLevel (line 8) | void setLoggingLevel(LogLevelSelector level);
method getCurrentLoggingLevel (line 10) | LogLevelSelector getCurrentLoggingLevel();
method retrieveRemoteVersion (line 12) | Version retrieveRemoteVersion();
FILE: src/main/java/io/linuxserver/davos/delegation/services/SettingsServiceImpl.java
class SettingsServiceImpl (line 19) | @Component
method setLoggingLevel (line 27) | @Override
method getCurrentLoggingLevel (line 33) | @Override
method retrieveRemoteVersion (line 38) | @Override
FILE: src/main/java/io/linuxserver/davos/dto/ActionDTO.java
class ActionDTO (line 6) | public class ActionDTO {
method toString (line 16) | public String toString() {
FILE: src/main/java/io/linuxserver/davos/dto/FTPFileDTO.java
class FTPFileDTO (line 3) | public class FTPFileDTO {
FILE: src/main/java/io/linuxserver/davos/dto/FilterDTO.java
class FilterDTO (line 6) | public class FilterDTO {
method toString (line 11) | public String toString() {
FILE: src/main/java/io/linuxserver/davos/dto/HostDTO.java
class HostDTO (line 5) | public class HostDTO {
FILE: src/main/java/io/linuxserver/davos/dto/ScheduleDTO.java
class ScheduleDTO (line 12) | public class ScheduleDTO {
method toString (line 31) | public String toString() {
FILE: src/main/java/io/linuxserver/davos/dto/ScheduleProcessResponse.java
class ScheduleProcessResponse (line 3) | public class ScheduleProcessResponse {
FILE: src/main/java/io/linuxserver/davos/exception/HostInUseException.java
class HostInUseException (line 3) | public class HostInUseException extends RuntimeException {
method HostInUseException (line 7) | public HostInUseException(String message) {
FILE: src/main/java/io/linuxserver/davos/exception/ScheduleAlreadyRunningException.java
class ScheduleAlreadyRunningException (line 3) | public class ScheduleAlreadyRunningException extends RuntimeException {
method ScheduleAlreadyRunningException (line 7) | public ScheduleAlreadyRunningException() {
FILE: src/main/java/io/linuxserver/davos/exception/ScheduleNotRunningException.java
class ScheduleNotRunningException (line 3) | public class ScheduleNotRunningException extends RuntimeException {
method ScheduleNotRunningException (line 7) | public ScheduleNotRunningException() {
FILE: src/main/java/io/linuxserver/davos/logging/LoggingManager.java
class LoggingManager (line 8) | public class LoggingManager {
method enableDebug (line 12) | public static void enableDebug() {
method disableDebug (line 17) | public static void disableDebug() {
method setLogLevel (line 22) | public static void setLogLevel(Level level) {
FILE: src/main/java/io/linuxserver/davos/persistence/dao/DefaultHostDAO.java
class DefaultHostDAO (line 12) | @Component
method saveHost (line 18) | @Override
method fetchHost (line 23) | @Override
method fetchAllHosts (line 28) | @Override
method deleteHost (line 33) | @Override
FILE: src/main/java/io/linuxserver/davos/persistence/dao/DefaultScheduleDAO.java
class DefaultScheduleDAO (line 18) | @Component
method getAll (line 26) | @Override
method fetchSchedule (line 31) | @Override
method updateConfig (line 36) | @Override
method fetchSchedulesUsingHost (line 53) | @Override
method updateScannedFilesOnSchedule (line 61) | @Override
method toScannedFileModel (line 73) | private ScannedFileModel toScannedFileModel(String fileName, ScheduleM...
method deleteSchedule (line 82) | @Override
FILE: src/main/java/io/linuxserver/davos/persistence/dao/HostDAO.java
type HostDAO (line 7) | public interface HostDAO {
method saveHost (line 9) | HostModel saveHost(HostModel host);
method fetchHost (line 11) | HostModel fetchHost(Long id);
method fetchAllHosts (line 13) | List<HostModel> fetchAllHosts();
method deleteHost (line 15) | void deleteHost(Long id);
FILE: src/main/java/io/linuxserver/davos/persistence/dao/ScheduleDAO.java
type ScheduleDAO (line 7) | public interface ScheduleDAO {
method getAll (line 9) | List<ScheduleModel> getAll();
method fetchSchedulesUsingHost (line 11) | List<ScheduleModel> fetchSchedulesUsingHost(Long hostId);
method fetchSchedule (line 13) | ScheduleModel fetchSchedule(Long id);
method updateConfig (line 15) | ScheduleModel updateConfig(ScheduleModel model);
method updateScannedFilesOnSchedule (line 17) | void updateScannedFilesOnSchedule(Long id, List<String> newlyScannedFi...
method deleteSchedule (line 19) | void deleteSchedule(Long id);
FILE: src/main/java/io/linuxserver/davos/persistence/model/ActionModel.java
class ActionModel (line 10) | @Entity
method toString (line 36) | @Override
FILE: src/main/java/io/linuxserver/davos/persistence/model/FilterModel.java
class FilterModel (line 10) | @Entity
method toString (line 24) | @Override
FILE: src/main/java/io/linuxserver/davos/persistence/model/HostModel.java
class HostModel (line 17) | @Entity
method isIdentityFileEnabled (line 48) | public boolean isIdentityFileEnabled() {
method setIdentityFileEnabled (line 56) | public void setIdentityFileEnabled(boolean identityFileEnabled) {
method toString (line 64) | @Override
FILE: src/main/java/io/linuxserver/davos/persistence/model/ScannedFileModel.java
class ScannedFileModel (line 10) | @Entity
FILE: src/main/java/io/linuxserver/davos/persistence/model/ScheduleModel.java
class ScheduleModel (line 21) | @Entity
method getLastRunTime (line 58) | public long getLastRunTime() {
method getFiltersMandatory (line 66) | public Boolean getFiltersMandatory() {
method setLastRunTime (line 74) | public void setLastRunTime(long millis) {
method setFiltersMandatory (line 78) | public void setFiltersMandatory(boolean filtersMandatory) {
method getDeleteHostFile (line 82) | public Boolean getDeleteHostFile() {
method setDeleteHostFile (line 90) | public void setDeleteHostFile(boolean deleteHostFile) {
method getStartAutomatically (line 94) | public Boolean getStartAutomatically() {
method setStartAutomatically (line 102) | public void setStartAutomatically(boolean startAutomatically) {
method getInvertFilters (line 106) | public Boolean getInvertFilters() {
method setInvertFilters (line 114) | public void setInvertFilters(boolean invertFilters) {
method toString (line 137) | @Override
FILE: src/main/java/io/linuxserver/davos/persistence/repository/HostRepository.java
type HostRepository (line 9) | public interface HostRepository extends CrudRepository<HostModel, Long> {
method findAll (line 11) | List<HostModel> findAll();
FILE: src/main/java/io/linuxserver/davos/persistence/repository/ScheduleRepository.java
type ScheduleRepository (line 9) | public interface ScheduleRepository extends CrudRepository<ScheduleModel...
method findAll (line 11) | List<ScheduleModel> findAll();
method findByHost_Id (line 13) | List<ScheduleModel> findByHost_Id(Long hostId);
FILE: src/main/java/io/linuxserver/davos/schedule/RunnableSchedule.java
class RunnableSchedule (line 15) | public class RunnableSchedule implements Runnable {
method RunnableSchedule (line 23) | public RunnableSchedule(Long scheduleId, ScheduleDAO configurationDAO) {
method run (line 29) | @Override
method getTransfers (line 50) | public List<FTPTransfer> getTransfers() {
FILE: src/main/java/io/linuxserver/davos/schedule/RunningSchedule.java
class RunningSchedule (line 5) | public class RunningSchedule {
method RunningSchedule (line 10) | public RunningSchedule(ScheduledFuture<?> future, RunnableSchedule sch...
method getFuture (line 15) | public ScheduledFuture<?> getFuture() {
method getSchedule (line 19) | public RunnableSchedule getSchedule() {
FILE: src/main/java/io/linuxserver/davos/schedule/ScheduleConfiguration.java
class ScheduleConfiguration (line 11) | public class ScheduleConfiguration {
method ScheduleConfiguration (line 27) | public ScheduleConfiguration(final String scheduleName, final Transfer...
method getConnectionType (line 44) | public TransferProtocol getConnectionType() {
method getHostName (line 48) | public String getHostName() {
method getPort (line 52) | public int getPort() {
method getCredentials (line 56) | public UserCredentials getCredentials() {
method getRemoteFilePath (line 60) | public String getRemoteFilePath() {
method getLocalFilePath (line 64) | public String getLocalFilePath() {
method getFilters (line 68) | public List<String> getFilters() {
method setFilters (line 72) | public void setFilters(List<String> filters) {
method getScheduleName (line 76) | public String getScheduleName() {
method getActions (line 80) | public List<PostDownloadAction> getActions() {
method setActions (line 84) | public void setActions(List<PostDownloadAction> actions) {
method getTransferType (line 88) | public FileTransferType getTransferType() {
method isFiltersMandatory (line 92) | public boolean isFiltersMandatory() {
method isInvertFilters (line 96) | public boolean isInvertFilters() {
method isDeleteHostFile (line 100) | public boolean isDeleteHostFile() {
FILE: src/main/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactory.java
class ScheduleConfigurationFactory (line 16) | public class ScheduleConfigurationFactory {
method createConfig (line 18) | public static ScheduleConfiguration createConfig(ScheduleModel model) {
method buildCredentials (line 36) | private static UserCredentials buildCredentials(HostModel host) {
method addActions (line 44) | private static void addActions(ScheduleModel model, ScheduleConfigurat...
method addFilters (line 59) | private static void addFilters(ScheduleModel model, ScheduleConfigurat...
FILE: src/main/java/io/linuxserver/davos/schedule/ScheduleExecutor.java
class ScheduleExecutor (line 22) | @Component
method ScheduleExecutor (line 34) | public ScheduleExecutor() {
method isScheduleRunning (line 38) | public boolean isScheduleRunning(Long id) {
method getRunningSchedule (line 42) | public RunningSchedule getRunningSchedule(Long id) {
method runAutomaticStartupSchedules (line 46) | @PostConstruct
method startSchedule (line 66) | public void startSchedule(Long id) throws ScheduleAlreadyRunningExcept...
method stopSchedule (line 84) | public void stopSchedule(Long id) throws ScheduleNotRunningException {
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/ConnectWorkflowStep.java
class ConnectWorkflowStep (line 10) | public class ConnectWorkflowStep extends WorkflowStep {
method ConnectWorkflowStep (line 16) | public ConnectWorkflowStep() {
method runStep (line 20) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/DisconnectWorkflowStep.java
class DisconnectWorkflowStep (line 8) | public class DisconnectWorkflowStep extends WorkflowStep {
method runStep (line 12) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/DownloadFilesWorkflowStep.java
class DownloadFilesWorkflowStep (line 15) | public class DownloadFilesWorkflowStep extends WorkflowStep {
method DownloadFilesWorkflowStep (line 21) | public DownloadFilesWorkflowStep() {
method runStep (line 25) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/FilterFilesWorkflowStep.java
class FilterFilesWorkflowStep (line 19) | public class FilterFilesWorkflowStep extends WorkflowStep {
method FilterFilesWorkflowStep (line 23) | public FilterFilesWorkflowStep() {
method runStep (line 29) | @Override
method noFilteringRequired (line 81) | private boolean noFilteringRequired(ScheduleWorkflow schedule, List<St...
method filterFilesByName (line 85) | private void filterFilesByName(boolean invertFilters, List<String> fil...
method removeCurrentAndParentDirs (line 124) | private Predicate<? super FTPFile> removeCurrentAndParentDirs() {
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/ScheduleWorkflow.java
class ScheduleWorkflow (line 14) | public class ScheduleWorkflow {
method ScheduleWorkflow (line 25) | public ScheduleWorkflow(ScheduleConfiguration config) {
method getClient (line 29) | protected Client getClient() {
method getConfig (line 33) | protected ScheduleConfiguration getConfig() {
method getConnection (line 37) | protected Connection getConnection() {
method start (line 41) | public void start() {
method setConnection (line 48) | protected void setConnection(Connection connection) {
method setClient (line 52) | protected void setClient(Client client) {
method getFilesFromLastScan (line 56) | public List<String> getFilesFromLastScan() {
method getFilesToDownload (line 60) | public List<FTPTransfer> getFilesToDownload() {
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/WorkflowStep.java
class WorkflowStep (line 3) | public abstract class WorkflowStep {
method runStep (line 8) | abstract public void runStep(ScheduleWorkflow schedule);
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/HttpAPICallAction.java
class HttpAPICallAction (line 12) | public class HttpAPICallAction implements PostDownloadAction {
method HttpAPICallAction (line 23) | public HttpAPICallAction(String url, String method, String contentType...
method execute (line 31) | @Override
method toString (line 51) | @Override
method resolveFilename (line 56) | private String resolveFilename(String value, String filename) {
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/MoveFileAction.java
class MoveFileAction (line 10) | public class MoveFileAction implements PostDownloadAction {
method MoveFileAction (line 19) | public MoveFileAction(String currentFilePath, String newFilePath) {
method execute (line 25) | @Override
method toString (line 41) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/PostDownloadAction.java
type PostDownloadAction (line 3) | public interface PostDownloadAction {
method execute (line 5) | void execute(PostDownloadExecution execution);
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/PostDownloadExecution.java
class PostDownloadExecution (line 3) | public class PostDownloadExecution {
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/PushbulletNotifyAction.java
class PushbulletNotifyAction (line 13) | public class PushbulletNotifyAction implements PostDownloadAction {
method PushbulletNotifyAction (line 19) | public PushbulletNotifyAction(String apiKey) {
method execute (line 23) | @Override
method toString (line 50) | @Override
class PushbulletRequest (line 55) | class PushbulletRequest {
method toString (line 61) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/actions/SNSNotifyAction.java
class SNSNotifyAction (line 15) | public class SNSNotifyAction implements PostDownloadAction {
method SNSNotifyAction (line 26) | public SNSNotifyAction(String region, String arn, String accessKey, St...
method execute (line 34) | @Override
method formatJsonMessage (line 59) | private String formatJsonMessage(String message) {
method toString (line 63) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/filter/FileFilter.java
type FileFilter (line 7) | public interface FileFilter {
method filter (line 9) | List<FTPFile> filter(List<FTPFile> allFiles);
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/filter/ReferentialFileFilter.java
class ReferentialFileFilter (line 13) | public class ReferentialFileFilter implements FileFilter {
method ReferentialFileFilter (line 19) | public ReferentialFileFilter(List<String> files) {
method filter (line 23) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/filter/TemporalFileFilter.java
class TemporalFileFilter (line 14) | public class TemporalFileFilter implements FileFilter {
method TemporalFileFilter (line 20) | public TemporalFileFilter(DateTime lastRun) {
method filter (line 24) | @Override
method after (line 29) | private Predicate<? super FTPFile> after(DateTime lastRun) {
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FTPTransfer.java
class FTPTransfer (line 6) | public class FTPTransfer {
method FTPTransfer (line 12) | public FTPTransfer(FTPFile file) {
method getFile (line 16) | public FTPFile getFile() {
method getListener (line 20) | public ProgressListener getListener() {
method setListener (line 24) | public void setListener(ProgressListener listener) {
method getState (line 28) | public State getState() {
method setState (line 32) | public void setState(State state) {
type State (line 36) | public enum State {
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FilesAndFoldersTranferStrategy.java
class FilesAndFoldersTranferStrategy (line 10) | public class FilesAndFoldersTranferStrategy extends TransferStrategy {
method FilesAndFoldersTranferStrategy (line 14) | public FilesAndFoldersTranferStrategy(Connection connection) {
method transferFile (line 18) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FilesOnlyTransferStrategy.java
class FilesOnlyTransferStrategy (line 10) | public class FilesOnlyTransferStrategy extends TransferStrategy {
method FilesOnlyTransferStrategy (line 14) | public FilesOnlyTransferStrategy(Connection connection) {
method transferFile (line 18) | @Override
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategy.java
class TransferStrategy (line 14) | public abstract class TransferStrategy {
method TransferStrategy (line 21) | public TransferStrategy(Connection connection) {
method setPostDownloadActions (line 25) | public void setPostDownloadActions(List<PostDownloadAction> postDownlo...
method toString (line 29) | @Override
method transferFile (line 34) | public abstract void transferFile(FTPTransfer fileToTransfer, String d...
method runPostDownloadAction (line 36) | protected void runPostDownloadAction(FTPFile file) {
FILE: src/main/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategyFactory.java
class TransferStrategyFactory (line 6) | public class TransferStrategyFactory {
method getStrategy (line 8) | public TransferStrategy getStrategy(FileTransferType type, Connection ...
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/FTPFile.java
class FTPFile (line 7) | public class FTPFile {
method FTPFile (line 15) | public FTPFile(String name, long size, String path, long mTime, boolea...
method getName (line 24) | public String getName() {
method getSize (line 28) | public long getSize() {
method getPath (line 32) | public String getPath() {
method getLastModified (line 36) | public DateTime getLastModified() {
method isDirectory (line 40) | public boolean isDirectory() {
method toString (line 44) | @Override
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/FileTransferType.java
type FileTransferType (line 3) | public enum FileTransferType {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/TransferProtocol.java
type TransferProtocol (line 3) | public enum TransferProtocol {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/Client.java
class Client (line 5) | public abstract class Client {
method setCredentials (line 12) | public void setCredentials(UserCredentials userCredentials) {
method setHost (line 16) | public void setHost(String host) {
method setPort (line 20) | public void setPort(int port) {
method connect (line 24) | public abstract Connection connect();
method disconnect (line 26) | public abstract void disconnect();
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/ClientFactory.java
class ClientFactory (line 5) | public class ClientFactory {
method getClient (line 7) | public Client getClient(TransferProtocol protocol) {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/FTPClient.java
class FTPClient (line 16) | public class FTPClient extends Client {
method FTPClient (line 24) | public FTPClient() {
method connect (line 30) | public Connection connect() {
method disconnect (line 45) | public void disconnect() {
method connectClientAndCheckStatus (line 63) | private void connectClientAndCheckStatus() throws SocketException, IOE...
method login (line 81) | private void login() throws IOException, FTPException {
method setSpecificModesOnClient (line 95) | private void setSpecificModesOnClient() throws IOException {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/FTPSClient.java
class FTPSClient (line 6) | public class FTPSClient extends FTPClient {
method FTPSClient (line 10) | public FTPSClient() {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/SFTPClient.java
class SFTPClient (line 17) | public class SFTPClient extends Client {
method SFTPClient (line 27) | public SFTPClient() {
method connect (line 33) | @Override
method disconnect (line 51) | @Override
method configureSessionAndConnect (line 63) | private void configureSessionAndConnect() throws JSchException {
method openChannelFromSession (line 91) | private void openChannelFromSession() throws JSchException {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/client/UserCredentials.java
class UserCredentials (line 3) | public class UserCredentials {
method UserCredentials (line 11) | public UserCredentials(final String username, final String password) {
method UserCredentials (line 17) | public UserCredentials(final String username, final Identity identity) {
method getIdentity (line 23) | public Identity getIdentity() {
method getUsername (line 27) | public String getUsername() {
method getPassword (line 31) | public String getPassword() {
class Identity (line 35) | public static class Identity {
method Identity (line 39) | public Identity(String identityFile) {
method getIdentityFile (line 43) | public String getIdentityFile() {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/Connection.java
type Connection (line 9) | public interface Connection {
method currentDirectory (line 11) | String currentDirectory() throws FTPException;
method download (line 13) | void download(FTPFile remoteFilePath, String localFilePath) throws FTP...
method deleteRemoteFile (line 15) | void deleteRemoteFile(FTPFile file) throws FTPException;
method listFiles (line 17) | List<FTPFile> listFiles() throws FTPException;
method listFiles (line 19) | List<FTPFile> listFiles(String remoteDirectory) throws FTPException;
method setProgressListener (line 21) | void setProgressListener(ProgressListener progressListener);
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/ConnectionFactory.java
class ConnectionFactory (line 9) | public class ConnectionFactory {
method createSFTPConnection (line 13) | public SFTPConnection createSFTPConnection(Channel channel) {
method createFTPConnection (line 18) | public FTPConnection createFTPConnection(org.apache.commons.net.ftp.FT...
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/FTPConnection.java
class FTPConnection (line 24) | public class FTPConnection implements Connection {
method FTPConnection (line 33) | public FTPConnection(org.apache.commons.net.ftp.FTPClient client) {
method currentDirectory (line 37) | @Override
method download (line 49) | @Override
method listFiles (line 74) | @Override
method listFiles (line 79) | @Override
method setProgressListener (line 102) | @Override
method listenOn (line 107) | private CountingOutputStream listenOn(OutputStream outputStream) {
method doDownload (line 124) | private void doDownload(FTPFile file, String cleanRemotePath, String c...
method downloadDirectoryAndContents (line 152) | private void downloadDirectoryAndContents(FTPFile file, String localDo...
method removeCurrentAndParentDirs (line 180) | private Predicate<? super FTPFile> removeCurrentAndParentDirs() {
method toFtpFile (line 184) | private FTPFile toFtpFile(org.apache.commons.net.ftp.FTPFile ftpFile, ...
method deleteRemoteFile (line 194) | @Override
method deleteDirectoryAndContents (line 214) | private void deleteDirectoryAndContents(FTPFile file, String remoteDir...
method doDelete (line 236) | private void doDelete(String subItemPath) throws IOException {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/SFTPConnection.java
class SFTPConnection (line 25) | public class SFTPConnection implements Connection {
method SFTPConnection (line 33) | public SFTPConnection(ChannelSftp channel) {
method currentDirectory (line 37) | @Override
method download (line 49) | @Override
method listFiles (line 70) | @Override
method listFiles (line 75) | @Override
method setProgressListener (line 102) | @Override
method doGet (line 107) | private void doGet(String fullRemotePath, String fullLocalDownloadPath...
method downloadDirectoryAndContents (line 120) | private void downloadDirectoryAndContents(FTPFile file, String localDo...
method removeCurrentAndParentDirs (line 150) | private Predicate<? super FTPFile> removeCurrentAndParentDirs() {
method toFtpFile (line 154) | private FTPFile toFtpFile(LsEntry lsEntry, String filePath) throws Sft...
method deleteRemoteFile (line 164) | @Override
method deleteDirectoryAndContents (line 184) | private void deleteDirectoryAndContents(FTPFile file, String remoteDir...
method doDelete (line 206) | private void doDelete(String subItemPath) throws SftpException {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/progress/ListenerFactory.java
class ListenerFactory (line 8) | public class ListenerFactory {
method createListener (line 12) | public ProgressListener createListener(TransferProtocol protocol) {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/progress/ProgressListener.java
class ProgressListener (line 3) | public class ProgressListener {
method getProgress (line 11) | public double getProgress() {
method getTransferSpeed (line 19) | public double getTransferSpeed() {
method reset (line 23) | public void reset() {
method updateBytesWritten (line 27) | public void updateBytesWritten(long bytes) {
method setBytesWritten (line 31) | public void setBytesWritten(long bytesWritten) {
method setTotalBytes (line 43) | public void setTotalBytes(long totalBytes) {
method start (line 47) | public void start() {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/connection/progress/SFTPProgressListener.java
class SFTPProgressListener (line 5) | public class SFTPProgressListener extends ProgressListener implements Sf...
method init (line 7) | @Override
method count (line 14) | @Override
method end (line 20) | @Override
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/exception/ClientConnectionException.java
class ClientConnectionException (line 3) | public class ClientConnectionException extends FTPException {
method ClientConnectionException (line 7) | public ClientConnectionException() {
method ClientConnectionException (line 11) | public ClientConnectionException(String message) {
method ClientConnectionException (line 15) | public ClientConnectionException(String message, Exception cause) {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/exception/ClientDisconnectException.java
class ClientDisconnectException (line 3) | public class ClientDisconnectException extends FTPException {
method ClientDisconnectException (line 7) | public ClientDisconnectException() {
method ClientDisconnectException (line 11) | public ClientDisconnectException(String message) {
method ClientDisconnectException (line 15) | public ClientDisconnectException(String message, Exception cause) {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/exception/DeleteFileException.java
class DeleteFileException (line 3) | public class DeleteFileException extends FTPException {
method DeleteFileException (line 7) | public DeleteFileException() {
method DeleteFileException (line 11) | public DeleteFileException(String message) {
method DeleteFileException (line 15) | public DeleteFileException(String message, Exception cause) {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/exception/DownloadFailedException.java
class DownloadFailedException (line 3) | public class DownloadFailedException extends FTPException {
method DownloadFailedException (line 7) | public DownloadFailedException() {
method DownloadFailedException (line 11) | public DownloadFailedException(String message) {
method DownloadFailedException (line 15) | public DownloadFailedException(String message, Exception cause) {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/exception/FTPException.java
class FTPException (line 3) | public abstract class FTPException extends RuntimeException {
method FTPException (line 7) | public FTPException() {
method FTPException (line 11) | public FTPException(String message) {
method FTPException (line 15) | public FTPException(String message, Exception cause) {
FILE: src/main/java/io/linuxserver/davos/transfer/ftp/exception/FileListingException.java
class FileListingException (line 3) | public class FileListingException extends FTPException {
method FileListingException (line 7) | public FileListingException() {
method FileListingException (line 11) | public FileListingException(String message) {
method FileListingException (line 15) | public FileListingException(String message, Exception cause) {
FILE: src/main/java/io/linuxserver/davos/util/FileStreamFactory.java
class FileStreamFactory (line 8) | public class FileStreamFactory {
method createInputStream (line 10) | public FileInputStream createInputStream(String filePath) throws FileN...
method createOutputStream (line 14) | public FileOutputStream createOutputStream(String filePath) throws Fil...
FILE: src/main/java/io/linuxserver/davos/util/FileUtils.java
class FileUtils (line 9) | public class FileUtils {
method getFile (line 13) | public File getFile(String filePath) {
method moveFileToDirectory (line 17) | public void moveFileToDirectory(String oldPath, String newPath) throws...
method createLocalDirectory (line 21) | public void createLocalDirectory(String directoryPath) {
method ensureTrailingSlash (line 28) | public static String ensureTrailingSlash(String path) {
FILE: src/main/java/io/linuxserver/davos/util/PatternBuilder.java
class PatternBuilder (line 3) | public class PatternBuilder {
method buildFromFilterString (line 5) | public static String buildFromFilterString(String filter) {
FILE: src/main/java/io/linuxserver/davos/web/API.java
class API (line 8) | public class API {
method getId (line 16) | public Long getId() {
method setId (line 20) | public void setId(Long id) {
method getUrl (line 24) | public String getUrl() {
method setUrl (line 28) | public void setUrl(String url) {
method getMethod (line 32) | public MethodSelector getMethod() {
method setMethod (line 36) | public void setMethod(MethodSelector method) {
method getContentType (line 40) | public String getContentType() {
method setContentType (line 44) | public void setContentType(String contentType) {
method getBody (line 48) | public String getBody() {
method setBody (line 52) | public void setBody(String body) {
method toString (line 56) | @Override
FILE: src/main/java/io/linuxserver/davos/web/Filter.java
class Filter (line 6) | public class Filter {
method getValue (line 11) | public String getValue() {
method setValue (line 15) | public void setValue(String value) {
method getId (line 19) | public Long getId() {
method setId (line 23) | public void setId(Long id) {
method toString (line 27) | @Override
FILE: src/main/java/io/linuxserver/davos/web/Host.java
class Host (line 8) | public class Host {
method getId (line 20) | public Long getId() {
method setId (line 24) | public void setId(Long id) {
method getName (line 28) | public String getName() {
method setName (line 32) | public void setName(String name) {
method getAddress (line 36) | public String getAddress() {
method setAddress (line 40) | public void setAddress(String address) {
method getPort (line 44) | public int getPort() {
method setPort (line 48) | public void setPort(int port) {
method getProtocol (line 52) | public ProtocolSelector getProtocol() {
method setProtocol (line 56) | public void setProtocol(ProtocolSelector protocol) {
method getUsername (line 60) | public String getUsername() {
method setUsername (line 64) | public void setUsername(String username) {
method getPassword (line 68) | public String getPassword() {
method setPassword (line 72) | public void setPassword(String password) {
method toString (line 76) | @Override
method getIdentityFile (line 81) | public String getIdentityFile() {
method setIdentityFile (line 85) | public void setIdentityFile(String identityFile) {
method isIdentityFileEnabled (line 89) | public boolean isIdentityFileEnabled() {
method setIdentityFileEnabled (line 93) | public void setIdentityFileEnabled(boolean identityFileEnabled) {
FILE: src/main/java/io/linuxserver/davos/web/Notifications.java
class Notifications (line 6) | public class Notifications {
method getPushbullet (line 11) | public List<Pushbullet> getPushbullet() {
method getSns (line 15) | public List<SNS> getSns() {
method setPushbullet (line 19) | public void setPushbullet(List<Pushbullet> pushbullet) {
method setSns (line 23) | public void setSns(List<SNS> sns) {
FILE: src/main/java/io/linuxserver/davos/web/Pushbullet.java
class Pushbullet (line 6) | public class Pushbullet {
method getId (line 11) | public Long getId() {
method setId (line 15) | public void setId(Long id) {
method getApiKey (line 19) | public String getApiKey() {
method setApiKey (line 23) | public void setApiKey(String apiKey) {
method toString (line 27) | @Override
FILE: src/main/java/io/linuxserver/davos/web/SNS.java
class SNS (line 3) | public class SNS {
method getTopicArn (line 11) | public String getTopicArn() {
method setTopicArn (line 15) | public void setTopicArn(String topicArn) {
method getRegion (line 19) | public String getRegion() {
method setRegion (line 23) | public void setRegion(String region) {
method getAccessKey (line 27) | public String getAccessKey() {
method setAccessKey (line 31) | public void setAccessKey(String accessKey) {
method getSecretAccessKey (line 35) | public String getSecretAccessKey() {
method setSecretAccessKey (line 39) | public void setSecretAccessKey(String secretAccessKey) {
method getId (line 43) | public Long getId() {
method setId (line 47) | public void setId(Long id) {
FILE: src/main/java/io/linuxserver/davos/web/Schedule.java
class Schedule (line 11) | public class Schedule {
method getId (line 34) | public Long getId() {
method setId (line 38) | public void setId(Long id) {
method getName (line 42) | public String getName() {
method setName (line 46) | public void setName(String name) {
method getInterval (line 50) | public int getInterval() {
method setInterval (line 54) | public void setInterval(int interval) {
method getHost (line 58) | public Long getHost() {
method setHost (line 62) | public void setHost(Long host) {
method getHostDirectory (line 66) | public String getHostDirectory() {
method setHostDirectory (line 70) | public void setHostDirectory(String hostDirectory) {
method getLocalDirectory (line 74) | public String getLocalDirectory() {
method setLocalDirectory (line 78) | public void setLocalDirectory(String localDirectory) {
method getTransferType (line 82) | public TransferSelector getTransferType() {
method setTransferType (line 86) | public void setTransferType(TransferSelector transferType) {
method isAutomatic (line 90) | public boolean isAutomatic() {
method setAutomatic (line 94) | public void setAutomatic(boolean automatic) {
method getFilters (line 98) | public List<Filter> getFilters() {
method getMoveFileTo (line 102) | public String getMoveFileTo() {
method setMoveFileTo (line 106) | public void setMoveFileTo(String moveFileTo) {
method getApis (line 110) | public List<API> getApis() {
method isRunning (line 114) | public boolean isRunning() {
method setRunning (line 118) | public void setRunning(boolean running) {
method toString (line 122) | @Override
method getLastScannedFiles (line 127) | public List<String> getLastScannedFiles() {
method getTransfers (line 131) | public List<Transfer> getTransfers() {
method isFiltersMandatory (line 135) | public boolean isFiltersMandatory() {
method setFiltersMandatory (line 139) | public void setFiltersMandatory(boolean filtersMandatory) {
method isInvertFilters (line 143) | public boolean isInvertFilters() {
method setInvertFilters (line 147) | public void setInvertFilters(boolean invertFilters) {
method isDeleteHostFile (line 151) | public boolean isDeleteHostFile() {
method setDeleteHostFile (line 155) | public void setDeleteHostFile(boolean deleteHostFile) {
method getNotifications (line 159) | public Notifications getNotifications() {
method setNotifications (line 163) | public void setNotifications(Notifications notifications) {
method setLastRunTime (line 167) | public void setLastRunTime(String lastRunTime) {
method getLastRunTime (line 171) | public String getLastRunTime() {
FILE: src/main/java/io/linuxserver/davos/web/ScheduleCommand.java
class ScheduleCommand (line 3) | public class ScheduleCommand {
type Command (line 7) | public enum Command {
FILE: src/main/java/io/linuxserver/davos/web/Settings.java
class Settings (line 5) | public class Settings {
method getLogLevel (line 9) | public LogLevelSelector getLogLevel() {
method setLogLevel (line 13) | public void setLogLevel(LogLevelSelector logLevel) {
FILE: src/main/java/io/linuxserver/davos/web/Transfer.java
class Transfer (line 3) | public class Transfer {
method getFileName (line 11) | public String getFileName() {
method setFileName (line 15) | public void setFileName(String fileName) {
method getFileSize (line 19) | public long getFileSize() {
method setFileSize (line 23) | public void setFileSize(long fileSize) {
method isDirectory (line 27) | public boolean isDirectory() {
method setDirectory (line 31) | public void setDirectory(boolean directory) {
method getProgress (line 35) | public Progress getProgress() {
method setProgress (line 39) | public void setProgress(Progress progress) {
method getStatus (line 43) | public String getStatus() {
method setStatus (line 47) | public void setStatus(String status) {
class Progress (line 51) | public static class Progress {
method getPercentageComplete (line 56) | public double getPercentageComplete() {
method setPercentageComplete (line 60) | public void setPercentageComplete(double percentageComplete) {
method getTransferSpeed (line 64) | public double getTransferSpeed() {
method setTransferSpeed (line 68) | public void setTransferSpeed(double transferSpeed) {
FILE: src/main/java/io/linuxserver/davos/web/VersionChecker.java
class VersionChecker (line 8) | public class VersionChecker {
method VersionChecker (line 15) | public VersionChecker(Version currentVersion, Version remoteVersion) {
method isNewVersionAvailable (line 23) | public boolean isNewVersionAvailable() {
method getNewVersion (line 27) | public String getNewVersion() {
FILE: src/main/java/io/linuxserver/davos/web/controller/APIController.java
class APIController (line 29) | @RestController
method createSchedule (line 44) | @RequestMapping(value = "/schedule", method = RequestMethod.POST)
method isSchedulePostPayloadValid (line 72) | private boolean isSchedulePostPayloadValid(Schedule schedule) {
method fetchSchedule (line 85) | @RequestMapping(value = "/schedule/{id}", method = RequestMethod.GET)
method updateSchedule (line 94) | @RequestMapping(value = "/schedule/{id}", method = RequestMethod.PUT)
method deleteSchedule (line 108) | @RequestMapping(value = "/schedule/{id}", method = RequestMethod.DELETE)
method deleteScheduleScannedFiles (line 117) | @RequestMapping(value = "/schedule/{id}/scannedFiles", method = Reques...
method executeSchedule (line 126) | @RequestMapping(value = "/schedule/{id}/execute", method = RequestMeth...
method getHost (line 138) | @RequestMapping(value = "/host/{id}", method = RequestMethod.GET)
method createHost (line 147) | @RequestMapping(value = "/host", method = RequestMethod.POST)
method updateHost (line 158) | @RequestMapping(value = "/host/{id}", method = RequestMethod.PUT)
method deleteHost (line 172) | @RequestMapping(value = "/host/{id}", method = RequestMethod.DELETE)
method testConnection (line 186) | @RequestMapping(value = "/testConnection", method = RequestMethod.POST)
method setLogLevel (line 206) | @RequestMapping(value = "/settings/log", method = RequestMethod.POST)
method handleException (line 214) | @ExceptionHandler(Exception.class)
FILE: src/main/java/io/linuxserver/davos/web/controller/FragmentController.java
class FragmentController (line 18) | @Controller
method populateMethods (line 25) | @ModelAttribute("allMethods")
method filter (line 30) | @RequestMapping("/filter")
method notificationPushbullet (line 38) | @RequestMapping("/notification/pushbullet")
method notificationSns (line 43) | @RequestMapping("/notification/sns")
method api (line 48) | @RequestMapping("/api")
method transfers (line 53) | @RequestMapping("/schedule/{id}/transfers")
FILE: src/main/java/io/linuxserver/davos/web/controller/ViewController.java
class ViewController (line 29) | @Controller
method currentVersion (line 44) | @ModelAttribute("currentVersion")
method populateIntervals (line 49) | @ModelAttribute("allIntervals")
method versionChecker (line 54) | @ModelAttribute("versionChecker")
method populateProtocols (line 59) | @ModelAttribute("allProtocols")
method populateTypes (line 64) | @ModelAttribute("allTransferTypes")
method populateMethods (line 69) | @ModelAttribute("allMethods")
method allHosts (line 74) | @ModelAttribute("allHosts")
method allLogLevels (line 79) | @ModelAttribute("allLogLevels")
method index (line 84) | @RequestMapping("/")
method settings (line 89) | @RequestMapping("/settings")
method schedules (line 100) | @RequestMapping("/schedules")
method newSchedule (line 107) | @RequestMapping("/schedules/new")
method schedules (line 114) | @RequestMapping("/schedules/{id}")
method hosts (line 121) | @RequestMapping("/hosts")
method newHost (line 126) | @RequestMapping("/hosts/new")
method hosts (line 133) | @RequestMapping("/hosts/{id}")
FILE: src/main/java/io/linuxserver/davos/web/controller/response/APIResponse.java
class APIResponse (line 3) | public class APIResponse {
method withBody (line 8) | public APIResponse withBody(Object body) {
method withStatus (line 14) | public APIResponse withStatus(String status) {
FILE: src/main/java/io/linuxserver/davos/web/controller/response/APIResponseBuilder.java
class APIResponseBuilder (line 3) | public class APIResponseBuilder {
method create (line 5) | public static APIResponse create() {
FILE: src/main/java/io/linuxserver/davos/web/selectors/IntervalSelector.java
type IntervalSelector (line 3) | public enum IntervalSelector {
method IntervalSelector (line 17) | private IntervalSelector(int minutes, String text) {
method getMinutes (line 25) | public int getMinutes() {
method getText (line 29) | public String getText() {
FILE: src/main/java/io/linuxserver/davos/web/selectors/LogLevelSelector.java
type LogLevelSelector (line 3) | public enum LogLevelSelector {
FILE: src/main/java/io/linuxserver/davos/web/selectors/MethodSelector.java
type MethodSelector (line 3) | public enum MethodSelector {
FILE: src/main/java/io/linuxserver/davos/web/selectors/ProtocolSelector.java
type ProtocolSelector (line 3) | public enum ProtocolSelector {
FILE: src/main/java/io/linuxserver/davos/web/selectors/TransferSelector.java
type TransferSelector (line 3) | public enum TransferSelector {
FILE: src/test/java/io/linuxserver/davos/VersionTest.java
class VersionTest (line 9) | public class VersionTest {
method shouldSetVersionBitsFromString (line 11) | @Test
method shouldSetVersionBits (line 21) | @Test
method shouldCompareToOthers (line 31) | @Test
FILE: src/test/java/io/linuxserver/davos/delegation/services/ScheduleServiceImplTest.java
class ScheduleServiceImplTest (line 30) | public class ScheduleServiceImplTest {
method before (line 50) | @Before
method shouldStartScheduleFromExecutor (line 55) | @Test
method shouldStopScheduleFromExecutor (line 62) | @Test
method shouldDeleteScheduleWhenNotRunning (line 69) | @Test
method shouldCheckIfScheduleIsRunningAndStopIfSoBeforeDeleting (line 78) | @Test
method shouldGetAllSchedulesAndConvert (line 89) | @Test
method shouldReturnOneSchedule (line 120) | @Test
method shouldGetHostFromDatabaseToCheckItExistsWhenCreating (line 136) | @Test(expected = IllegalArgumentException.class)
method shouldOverlayHostFromDatabaseInScheduleWhenCreating (line 145) | @Test
method shouldReturnConvertedScheduleOnceCreated (line 167) | @Test
method shouldOverlayHostFromDatabaseInScheduleWhenUpdating (line 188) | @Test
method shouldReturnConvertedScheduleOnceUpdated (line 206) | @Test
method shouldOverlayLastRunTimeOfExistingScheduleToNewOne (line 220) | @Test
method shouldThrowExceptionIfScheduleHasNoIdWhenUpdating (line 235) | @Test(expected = IllegalArgumentException.class)
method shouldClearScannedFiles (line 247) | @Test
method setUpScheduleMocks (line 264) | private void setUpScheduleMocks() {
FILE: src/test/java/io/linuxserver/davos/delegation/services/SettingsServiceImplTest.java
class SettingsServiceImplTest (line 25) | public class SettingsServiceImplTest {
method before (line 36) | @Before
method checkVersionShouldCallGitHub (line 45) | @Test
method checkVersionShouldReturnVersionFromGithub (line 54) | @Test
method ifRestTemplateFailsThenReturnEmptyVersion (line 62) | @Test
FILE: src/test/java/io/linuxserver/davos/persistence/dao/DefaultScheduleDAOTest.java
class DefaultScheduleDAOTest (line 19) | public class DefaultScheduleDAOTest {
method setUp (line 27) | @Before
method updatingScannedFilesShouldWork (line 32) | @Test
method toScannedFileModel (line 55) | private ScannedFileModel toScannedFileModel(String fileName, ScheduleM...
FILE: src/test/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactoryTest.java
class ScheduleConfigurationFactoryTest (line 20) | public class ScheduleConfigurationFactoryTest {
method shouldConvertAllMainFields (line 22) | @Test
method shouldUseCorrectCredentialsIfIdentityPresent (line 55) | @Test
method shouldAddAllFiltersIfAny (line 90) | @Test
method shouldAddAllActionsIfAny (line 119) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/ScheduleExecutorTest.java
class ScheduleExecutorTest (line 28) | public class ScheduleExecutorTest {
method setUp (line 39) | @Before
method shouldScheduleBasedOnIntervalAndAutoStartup (line 44) | @Test
method startScheduleShouldRunThatSchedule (line 66) | @Test
method startScheduleShouldNotRunScheduleIfAlreadyRunning (line 79) | @Test(expected = ScheduleAlreadyRunningException.class)
method stopScheduleShouldStopRunningSchedule (line 92) | @Test
method shouldBeAbleToInformWhetherScheduleIsRunningOrNot (line 112) | @Test
method stopScheduleShouldNotStopRunningScheduleIfItHasAlreadyBeenCancelled (line 135) | @Test
method stopScheduleShouldNotAttemptToStopNonRunningSchedule (line 156) | @Test(expected = ScheduleNotRunningException.class)
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/ConnectWorkflowStepTest.java
class ConnectWorkflowStepTest (line 26) | public class ConnectWorkflowStepTest {
method setUp (line 43) | @Before
method runStepShouldCreateNewClient (line 51) | @Test
method runStepShouldSetClientIntoWorkflow (line 62) | @Test
method runStepShouldConnectToNewlyCreatedClient (line 74) | @Test
method runStepShouldConnectToTheClientUsingTheConfigsHostAndCredentialInformation (line 85) | @Test
method runStepShouldPlaceConnectedClientConnectionIntoSchedule (line 105) | @Test
method runStepShouldCallOnNextStepWhenComplete (line 120) | @Test
method ifClientCannotConnectThenDoNotCallNextStep (line 135) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/DisconnectWorkflowStepTest.java
class DisconnectWorkflowStepTest (line 19) | public class DisconnectWorkflowStepTest {
method setUp (line 29) | @Before
method runStepShouldCloseTheConnection (line 34) | @Test
method ifDisconnectingFailsThenDoNothing (line 49) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/DownloadFilesWorkflowStepTest.java
class DownloadFilesWorkflowStepTest (line 39) | public class DownloadFilesWorkflowStepTest {
method setUp (line 64) | @Before
method shouldCallStrategyFactoryToGetCorrectStrategyAndPassFileThrough (line 75) | @Test
method shouldCallOnNextStepWhenFinished (line 109) | @Test
method ifStrategyTranferFailsThenShouldStillCallNextStep (line 130) | @Test
method shouldDeleteHostFileIfOptionSet (line 151) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/FilterFilesWorkflowStepTest.java
class FilterFilesWorkflowStepTest (line 27) | public class FilterFilesWorkflowStepTest {
method setUp (line 41) | @Before
method workflowStepShouldListFilesInTheRemoteDirectory (line 46) | @Test
method workflowStepShouldSetTheFilesFromLastScanToThisScanAtEnd (line 60) | @Test
method workflowStepShouldFilterOutAnyFilesThatAreNotInTheGivenConfigList (line 93) | @Test
method workflowStepShouldFilterOutAnyFilesThatAreNotInTheGivenConfigListAndWereNotScannedInLastRun (line 125) | @Test
method shouldOnlyAddOneInstanceOfAFileEvenIfTwoFiltersMatch (line 159) | @Test
method workflowStepShouldFilterOutAnyFilesThatDoNotMatchTheWildcards (line 191) | @Test
method workflowStepShouldCallNextStepRunMethodOnceSettingFilters (line 223) | @Test
method ifFilterListIsInitiallyEmptyThenAssumeThatAllFilesShouldBeDownloaded (line 250) | @Test
method ifFilterListIsInitiallyEmptyButFiltersAreMandatoryThenNoFilesShouldBeDownloaded (line 281) | @Test
method shouldFilterFilesThatDoNotMatchSetFiltersIfInvertingSet (line 311) | @Test
method ifListingFilesIsUnsuccessfulThenDoNotCallNextStepAndCallBackupStepInstead (line 343) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/actions/HttpAPICallActionTest.java
class HttpAPICallActionTest (line 24) | public class HttpAPICallActionTest {
method setUp (line 35) | @Before
method shouldCallRestTemplateWithCorrectParams (line 43) | @Test
method shouldResolveFilenameInUrlAsWell (line 58) | @Test
method postDataShouldHaveCorrectHeaderValue (line 76) | @Test
method ifRestTemplateFailsThenDoNothing (line 91) | @Test
method ifRestTemplateFailsBecauseMessageIsUnreadbleThenDoNothing (line 103) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/actions/MoveFileActionTest.java
class MoveFileActionTest (line 17) | public class MoveFileActionTest {
method setUp (line 25) | @Before
method executeShouldMoveTheFile (line 30) | @Test
method ifMovingOfFileFailsThenDoNotPerpetuateError (line 41) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/actions/PushbulletNotifyActionTest.java
class PushbulletNotifyActionTest (line 26) | public class PushbulletNotifyActionTest {
method setUp (line 37) | @Before
method executeShouldSendCorrectData (line 45) | @Test
method postDataShouldHaveCorrectHeaderValue (line 63) | @Test
method ifRestTemplateFailsThenDoNothing (line 80) | @Test
method ifRestTemplateFailsBecauseMessageIsUnreadbleThenDoNothing (line 89) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/filter/ReferentialFileFilterTest.java
class ReferentialFileFilterTest (line 13) | public class ReferentialFileFilterTest {
method shouldReturnAllFTPFilesIfLastScanIsEmpty (line 15) | @Test
method shouldReturnFilteredFTPFilesIfLastScanIsMissingFiles (line 33) | @Test
method shouldReturnEmptyListIfNewFilesAreEmpty (line 49) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/transfer/FilesAndFoldersTranferStrategyTest.java
class FilesAndFoldersTranferStrategyTest (line 13) | public class FilesAndFoldersTranferStrategyTest {
method setUp (line 20) | @Before
method strategyShouldCallDownloadMethodForFiles (line 28) | @Test
method strategyShouldCallDownloadMethodForDirectories (line 38) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/transfer/FilesOnlyTransferStrategyTest.java
class FilesOnlyTransferStrategyTest (line 18) | public class FilesOnlyTransferStrategyTest {
method setUp (line 25) | @Before
method strategyShouldCallDownloadMethodForFiles (line 33) | @Test
method strategyShouldNotCallDownloadMethodForDirectories (line 43) | @Test
method shouldNullifyListenerIfTransferIsForAFolder (line 53) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategyFactoryTest.java
class TransferStrategyFactoryTest (line 9) | public class TransferStrategyFactoryTest {
method shouldReturnCorrectStrategies (line 11) | @Test
FILE: src/test/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategyTest.java
class TransferStrategyTest (line 17) | public class TransferStrategyTest {
method toStringShouldPrintClassName (line 19) | @Test
method runPostDownloadActionShouldCallAllGivenActionsWithTheFile (line 25) | @Test
method ensureNulLActionsAreCheckedBeforeAttemptingToRun (line 46) | @Test
class TestTransferStrategy (line 54) | class TestTransferStrategy extends TransferStrategy {
method TestTransferStrategy (line 56) | public TestTransferStrategy(Connection connection) {
method transferFile (line 60) | @Override
class AnotherTestTransferStrategy (line 65) | class AnotherTestTransferStrategy extends TransferStrategy {
method AnotherTestTransferStrategy (line 67) | public AnotherTestTransferStrategy(Connection connection) {
method transferFile (line 71) | @Override
class DownloadActionImplTestTransferStrategy (line 76) | class DownloadActionImplTestTransferStrategy extends TransferStrategy {
method DownloadActionImplTestTransferStrategy (line 78) | public DownloadActionImplTestTransferStrategy(Connection connection) {
method transferFile (line 82) | @Override
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/client/ClientFactoryTest.java
class ClientFactoryTest (line 9) | public class ClientFactoryTest {
method shouldReturnSFTPClientWhenProtocolIsSFTP (line 11) | @Test
method shouldReturnFTPClientForAnythingElse (line 16) | @Test
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/client/FTPClientTest.java
class FTPClientTest (line 31) | public class FTPClientTest {
method setUp (line 49) | @Before
method newFtpClientShouldCreateFTPClientInstance (line 70) | @Test
method connectMethodShouldCallonUnderlyingFtpClientConnectMethodWithHostname (line 75) | @Test
method connectMethodShouldEnterPassiveModeLoginToUnderlyingFtpClient (line 83) | @Test
method connectMethodShouldSetKeepAliveCommandToEveryFiveMinutes (line 94) | @Test
method onceLoggedInTheClientShouldHaveFileTypeSetToBinary (line 102) | @Test
method connectMethodShouldReturnNewFtpConnectionTakingInUnderlyingFtpClient (line 113) | @Test
method disconnectMethodShouldCallOnUnderlyingFtpClientDisconnectMethod (line 122) | @Test
method ifConnectionFailsThenCatchThrownExceptionAndThrowFtpException (line 130) | @Test
method ifConnectionFailsDueToUnknownHostThenCatchThrownExceptionAndThrowFtpException (line 141) | @Test
method ifUnderlyingClientReturnsBadConnectionCodeThenThrowConnectionException (line 153) | @Test
method ifUnableToLoginToFtpClientThenThrowFtpException (line 165) | @Test
method whenDisconnectingThenClientShouldCheckToSeeIfAlreadyDisconnected (line 176) | @Test
method whenAlreadyDisconnectedThenClientShoudlNotCallOnUnderlyingClientDisconnectMethod (line 184) | @Test
method whenClientIsStillConnectedThenShouldCallOnUnderlyingClientDisconnectMethod (line 194) | @Test
method ifUnderlyingClientThrowsExceptionWhenDisconnectingThenClientShouldCatchAndRethrow (line 202) | @Test
method ifUnderlyingClientIsNullifiedBeforeDisconnectionThenDisconnectShouldThrow (line 213) | @Test
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/client/FTPSClientTest.java
class FTPSClientTest (line 7) | public class FTPSClientTest {
method newFtpsClientShouldCreateFTPSClientInstance (line 11) | @Test
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/client/SFTPClientTest.java
class SFTPClientTest (line 35) | public class SFTPClientTest {
method setUp (line 54) | @Before
method connectMethodShouldCreateSessionUsingHostPortAndUsername (line 68) | @Test
method sessionFromInitialConnectionNeedsConfigAndIdentitySettingBeforeConnecting (line 76) | @Test
method sessionFromInitialConnectionNeedsConfigAndPasswordSettingBeforeConnecting (line 95) | @Test
method returnedSessionObjectShouldSetChannelToSftpAndOpen (line 109) | @Test
method ifForAnyReasonTheUnderlyingSessionCantConnectThenCatchTheExceptionAndRethrow (line 119) | @Test
method sessionChannelShouldBeConnectedTo (line 131) | @Test
method connectMethodShouldReturnLiveInstanceOfSftpChannelWrappedInStfpConnection (line 142) | @Test
method disconnectMethodShouldDisconnectUnderlyingChannelAndSession (line 150) | @Test
method disconnectMethodShouldThrowExceptionWhenNotInitiallyConnected (line 163) | @Test
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/connection/FTPConnectionTest.java
class FTPConnectionTest (line 40) | public class FTPConnectionTest {
method setUp (line 62) | @Before
method whenListingFilesThenFtpClientListFilesMethodShouldBeCalledForCurrentWorkingDirectory (line 82) | @Test
method ifWhenListingFilesFtpClientThrowsExceptionThenCatchAndRethrowFileListingExcepton (line 90) | @Test
method whenListingFilesThenFileArrayThatListFilesReturnsShouldBeConvertedToListOfFtpFilesAndReturned (line 101) | @Test
method returnedFtpFilesShouldHaveCorrectModifiedDateTimesAgainstThem (line 123) | @Test
method whenListingFilesAndGivingRelativePathThenThatPathShouldBeUsedAlongsideCurrentWorkingDir (line 133) | @Test
method downloadMethodShouldCreateLocalFileStreamFromCorrectPathBasedOnRemoteFileName (line 141) | @Test
method downloadMethodShouldCreateLocalFileStreamContainingProgressListener (line 150) | @Test
method downloadMethodShouldCallOnFtpClientRetrieveFilesMethodWithRemoteFilename (line 162) | @Test
method downloadMethodShouldThrowExceptionIfUnableToOpenStreamToLocalFile (line 171) | @Test
method shouldDownloadFailForAnyReasonWhileInProgressThenCatchIOExceptionAndThrowNewDownloadFailedException (line 183) | @Test
method ifRetrieveFileMethodInClientReturnsFalseThenThrowDownloadFailedException (line 196) | @Test
method printingWorkingDirectoryShouldCallOnUnderlyingClientMethodToGetCurrentDirectory (line 208) | @Test
method printingWorkingDirectoryShouldReturnExactlyWhatTheUnderlyingClientReturns (line 216) | @Test
method ifClientThrowsExceptionWhenTryingToGetWorkingDirectoryThenCatchExceptionAndRethrow (line 221) | @Test
method shouldDeleteRemoteFile (line 232) | @Test
method ifDeleteFailsThenExceptionShouldBeThrown (line 242) | @Test
method ifDeleteThrowsExceptionItShouldBeCaughtAndRethrown (line 254) | @Test
method shouldRecursivelyDeleteRemoteFileIfItIsADirectoryWithContents (line 266) | @Test
method downloadShouldRecursivelyCheckFileIfFolderThenLsThatAndGetOnlyFiles (line 289) | @Test
method initRecursiveListings (line 338) | private void initRecursiveListings() throws IOException {
method createSingleEntry (line 370) | private org.apache.commons.net.ftp.FTPFile createSingleEntry(String fi...
method createRemoteFTPFiles (line 385) | private org.apache.commons.net.ftp.FTPFile[] createRemoteFTPFiles() {
method setTrueIfNumberIsEven (line 418) | private boolean setTrueIfNumberIsEven(int i) {
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/connection/SFTPConnectionTest.java
class SFTPConnectionTest (line 38) | public class SFTPConnectionTest {
method setUp (line 51) | @Before
method listFilesMethodShouldCallOnChannelLsMethodForPresentDirectory (line 66) | @Test
method whenListingFilesGivingRelativePathThenChannelLsMethodShouldUseGivenPath (line 74) | @Test
method ifUnderlyingChannelIsUnableToListFilesInPWDThenExceptionShouldBeCaughtAndRethrown (line 82) | @Test
method lsEntriesReturnedFromChannelShouldBeParsedIntoFtpFileAndReturnedInList (line 93) | @Test
method returnedFtpFilesShouldHaveCorrectModifiedDateTimesAgainstThem (line 114) | @Test
method printingWorkingDirectoryShouldCallOnUnderlyingClientMethodToGetCurrentDirectory (line 124) | @Test
method printingWorkingDirectoryShouldReturnExactlyWhatTheUnderlyingClientReturns (line 132) | @Test
method ifClientThrowsExceptionWhenTryingToGetWorkingDirectoryThenCatchExceptionAndRethrow (line 138) | @Test
method downloadMethodShouldCallChannelGetMethodWithFtpFileNameAndDirectory (line 149) | @Test
method downloadMethodShouldCallChannelGetMethodWithListenerIfSet (line 158) | @Test
method downloadMethodShouldThrowDownloadFailedExceptionWhenChannelThrowsSftpConnection (line 171) | @Test
method downloadShouldRecursivelyCheckFileIfFolderThenLsThatAndGetOnlyFiles (line 182) | @Test
method shouldRecursivelyDeleteRemoteFileIfItIsADirectoryAndHasContents (line 212) | @Test
method shouldDeleteRemoteFile (line 235) | @Test
method shouldDeleteRemoteDirectory (line 245) | @Test
method shouldCatchAndRethrowExceptionIfCaught (line 257) | @Test
method initRecursiveListings (line 271) | private void initRecursiveListings() throws SftpException {
method createEntries (line 303) | private Vector<LsEntry> createEntries() {
method createSingleEntry (line 314) | private LsEntry createSingleEntry(String fileName, long size, int mTim...
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/connection/progress/ListenerFactoryTest.java
class ListenerFactoryTest (line 9) | public class ListenerFactoryTest {
method shouldReturnCorrectListener (line 11) | @Test
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/connection/progress/ProgressListenerTest.java
class ProgressListenerTest (line 7) | public class ProgressListenerTest {
method shouldGiveCorrectSpeed (line 9) | @Test
method shouldGiveCorrectSpeedWhenAlternating (line 21) | @Test
method shouldReturn100IfTotalSizeIsZero (line 36) | @Test
method shouldReturn0IfTotalBytesWrittenIsZero (line 48) | @Test
method shouldShowProgress (line 60) | @Test
FILE: src/test/java/io/linuxserver/davos/transfer/ftp/connection/progress/SFTPProgressListenerTest.java
class SFTPProgressListenerTest (line 9) | public class SFTPProgressListenerTest {
method shouldReturnCorrectProgress (line 11) | @Test
FILE: src/test/java/io/linuxserver/davos/util/PatternBuilderTest.java
class PatternBuilderTest (line 7) | public class PatternBuilderTest {
method builderShouldTurnQuestionMarksIntoSingleCharacterRegexMatcher (line 9) | @Test
method builderShouldTurnAsterixesIntoManyCharacterRegexMatcher (line 18) | @Test
method regexStringReturnedShouldBeAbleToActuallyMatchUsingRegexOperation (line 27) | @Test
method stringWithBothAsterixAndQuestionMarkShouldMatchProperly (line 36) | @Test
method dotsShouldBeTreatedVerbatim (line 45) | @Test
FILE: src/test/java/io/linuxserver/davos/web/controller/APIControllerTest.java
class APIControllerTest (line 21) | public class APIControllerTest {
method before (line 32) | @Before
method createScheduleShouldCallFacadeMethod (line 37) | @Test
method onSuccessNewScheduleShouldBeReturnedWhenCreated (line 47) | @Test
method updateScheduleShouldCallFacadeWithIdInMethod (line 61) | @Test
method onSuccessUpdatedScheduleShouldBeReturnedWhenSaved (line 73) | @Test
method deleteScheduleShouldCallFacade (line 86) | @Test
method createHostShouldCallFacade (line 97) | @Test
method saveHostShouldReturnResponse (line 107) | @Test
method updateHostShouldCallFacadeWithIdInMethod (line 121) | @Test
method onSuccessUpdatedHostShouldBeReturnedWhenSaved (line 133) | @Test
method deleteHostShouldCallFacade (line 146) | @Test
FILE: src/test/java/io/linuxserver/davos/web/controller/ViewControllerTest.java
class ViewControllerTest (line 25) | public class ViewControllerTest {
method before (line 42) | @Before
method viewsShouldResolveCorrectly (line 49) | @Test
method schedulesShouldAddAllSchedulesToModel (line 62) | @Test
method schedulesWithIdShouldAddSpecificScheduleToModel (line 75) | @Test
method newScheduleShouldAddScheduleToModel (line 87) | @Test
method allHostsShouldAddHostsToModel (line 95) | @Test
method newHostShouldAddNewHostToModel (line 103) | @Test
method hostsWithIdShouldAddSpecificHostToModel (line 111) | @Test
Condensed preview — 184 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (472K chars).
[
{
"path": ".gitignore",
"chars": 427,
"preview": ".gradle\n*.sw?\n.#*\n*#\n*~\n/build\n/code\n.classpath\n.project\n.settings\n.metadata\n.factorypath\n.recommenders\nbin\nbuild\nlib/\nt"
},
{
"path": "LICENSE",
"chars": 1082,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 LinuxServer.io\n\nPermission is hereby granted, free of charge, to any person ob"
},
{
"path": "README.md",
"chars": 4571,
"preview": "# davos\n\n[](http://ci.l"
},
{
"path": "build.gradle",
"chars": 3233,
"preview": "import java.util.regex.Matcher;\n\nbuildscript {\n\n ext {\n springBootVersion = '1.4.2.RELEASE'\n }\n reposito"
},
{
"path": "conf/local/application.properties",
"chars": 20,
"preview": "davos.version=2.2.2\n"
},
{
"path": "conf/local/log4j2.xml",
"chars": 695,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration>\n\n\t<Appenders>\n\n\t\t<Console name=\"Console\" target=\"SYSTEM_OUT\" foll"
},
{
"path": "conf/release/application.properties",
"chars": 219,
"preview": "spring.datasource.url=jdbc:h2:file:/config/db/davos2\nspring.datasource.username=sa\nspring.datasource.password=sa\nspring."
},
{
"path": "conf/release/log4j2.xml",
"chars": 839,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration>\n\n\t<Appenders>\n\n\t\t<RollingFile name=\"File\" fileName=\"/config/logs/"
},
{
"path": "docs/Makefile",
"chars": 609,
"preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHI"
},
{
"path": "docs/make.bat",
"chars": 771,
"preview": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=python -m"
},
{
"path": "docs/source/conf.py",
"chars": 5191,
"preview": "# -*- coding: utf-8 -*-\n#\n# davos documentation build configuration file, created by\n# sphinx-quickstart on Sat Jul 29 0"
},
{
"path": "docs/source/developers/index.rst",
"chars": 3186,
"preview": "##########\nDevelopers\n##########\n\nIf you wish to contribute to davos (and help me tidy up some of its rather messy code!"
},
{
"path": "docs/source/faq/index.rst",
"chars": 5250,
"preview": "###\nFAQ\n###\n\n**********************************\nCan davos be used to upload files?\n**********************************\n\nN"
},
{
"path": "docs/source/guides/appsettings.rst",
"chars": 986,
"preview": "############\nApp Settings\n############\n\nUnder **Settings -> App Settings**, you can configure the log level that davos\nw"
},
{
"path": "docs/source/guides/gettingstarted/hosts.rst",
"chars": 1831,
"preview": "#####\nHosts\n#####\n\nA Host configuration provides one or more Schedules with information pertaining\nto the FTP server to "
},
{
"path": "docs/source/guides/gettingstarted/index.rst",
"chars": 1062,
"preview": "###############\nGetting Started\n###############\n\nThis section aims to help you understand how davos is pieced together, "
},
{
"path": "docs/source/guides/gettingstarted/schedules.rst",
"chars": 7867,
"preview": "#########\nSchedules\n#########\n\nA Schedule is the configuration that tells davos when to run, where to connect, what\nto l"
},
{
"path": "docs/source/guides/index.rst",
"chars": 308,
"preview": "######\nGuides\n######\n\nThis section will run you through the aspects of the application itself, including installation,\nf"
},
{
"path": "docs/source/guides/installation.rst",
"chars": 4304,
"preview": "############\nInstallation\n############\n\n.. note :: davos has been written with `Docker <https://www.docker.com/>`_ at th"
},
{
"path": "docs/source/index.rst",
"chars": 1012,
"preview": "##############################\ndavos: FTP Download Automation\n##############################\n\nThis is the documentation "
},
{
"path": "docs/source/reference/api.rst",
"chars": 11906,
"preview": "###\nAPI\n###\n\ndavos provides an HTTP API that exposes Schedules and Hosts so they can be managed\noutside the scope of the"
},
{
"path": "docs/source/reference/index.rst",
"chars": 68,
"preview": "#########\nReference\n#########\n\n.. toctree::\n :maxdepth: 1\n\n api\n"
},
{
"path": "docs/source/requirements.txt",
"chars": 16,
"preview": "sphinx_rtd_theme"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 231,
"preview": "#Fri Nov 11 19:22:20 GMT 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradlew",
"chars": 5046,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 2314,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
},
{
"path": "src/cucumber/java/io/linuxserver/davos/bdd/ClientStepDefs.java",
"chars": 4634,
"preview": "package io.linuxserver.davos.bdd;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport java.io.File;\nimpor"
},
{
"path": "src/cucumber/java/io/linuxserver/davos/bdd/ScheduleStepDefs.java",
"chars": 5378,
"preview": "package io.linuxserver.davos.bdd;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport java.io.File;\nimpor"
},
{
"path": "src/cucumber/java/io/linuxserver/davos/bdd/ServerStepDefs.java",
"chars": 2300,
"preview": "package io.linuxserver.davos.bdd;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport java.io.File;\nimpor"
},
{
"path": "src/cucumber/java/io/linuxserver/davos/bdd/helpers/FakeFTPServerFactory.java",
"chars": 1649,
"preview": "package io.linuxserver.davos.bdd.helpers;\n\nimport org.mockftpserver.fake.FakeFtpServer;\nimport org.mockftpserver.fake.Us"
},
{
"path": "src/cucumber/java/io/linuxserver/davos/bdd/helpers/FakeSFTPServerFactory.java",
"chars": 2777,
"preview": "package io.linuxserver.davos.bdd.helpers;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Path;\ni"
},
{
"path": "src/cucumber/java/io/linuxserver/davos/bdd/helpers/Logging.java",
"chars": 356,
"preview": "package io.linuxserver.davos.bdd.helpers;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.core.c"
},
{
"path": "src/cucumber/resources/Client.feature",
"chars": 1878,
"preview": "@Client\nFeature: General client tests\n\n @Server\n\tScenario: Connecting to the FTP server\n\t\n\t\tGiven there is an FTP ser"
},
{
"path": "src/cucumber/resources/Schedule.feature",
"chars": 1162,
"preview": "@Schedule @Server\nFeature: Scheduling\n\n\tScenario: Finding files that match filters\n\t\n\t\tGiven there is an FTP server runn"
},
{
"path": "src/main/java/io/linuxserver/davos/DavosApplication.java",
"chars": 322,
"preview": "package io.linuxserver.davos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoco"
},
{
"path": "src/main/java/io/linuxserver/davos/Version.java",
"chars": 1202,
"preview": "package io.linuxserver.davos;\n\npublic class Version {\n\n private int major;\n private int minor;\n private int pat"
},
{
"path": "src/main/java/io/linuxserver/davos/converters/Converter.java",
"chars": 141,
"preview": "package io.linuxserver.davos.converters;\n\npublic interface Converter<S, T> {\n\n T convertTo(S source);\n \n S conv"
},
{
"path": "src/main/java/io/linuxserver/davos/converters/HostConverter.java",
"chars": 1568,
"preview": "package io.linuxserver.davos.converters;\n\nimport org.springframework.stereotype.Component;\n\nimport io.linuxserver.davos."
},
{
"path": "src/main/java/io/linuxserver/davos/converters/ScheduleConverter.java",
"chars": 6612,
"preview": "package io.linuxserver.davos.converters;\n\nimport static java.util.stream.Collectors.toList;\n\nimport org.apache.commons.l"
},
{
"path": "src/main/java/io/linuxserver/davos/delegation/services/HostService.java",
"chars": 379,
"preview": "package io.linuxserver.davos.delegation.services;\n\nimport java.util.List;\n\nimport io.linuxserver.davos.web.Host;\n\npublic"
},
{
"path": "src/main/java/io/linuxserver/davos/delegation/services/HostServiceImpl.java",
"chars": 3212,
"preview": "package io.linuxserver.davos.delegation.services;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport ja"
},
{
"path": "src/main/java/io/linuxserver/davos/delegation/services/ScheduleService.java",
"chars": 492,
"preview": "package io.linuxserver.davos.delegation.services;\n\nimport java.util.List;\n\nimport io.linuxserver.davos.web.Schedule;\n\npu"
},
{
"path": "src/main/java/io/linuxserver/davos/delegation/services/ScheduleServiceImpl.java",
"chars": 4913,
"preview": "package io.linuxserver.davos.delegation.services;\n\nimport static java.util.stream.Collectors.toList;\n\nimport java.util.L"
},
{
"path": "src/main/java/io/linuxserver/davos/delegation/services/SettingsService.java",
"chars": 327,
"preview": "package io.linuxserver.davos.delegation.services;\n\nimport io.linuxserver.davos.Version;\nimport io.linuxserver.davos.web."
},
{
"path": "src/main/java/io/linuxserver/davos/delegation/services/SettingsServiceImpl.java",
"chars": 2231,
"preview": "package io.linuxserver.davos.delegation.services;\n\nimport org.apache.logging.log4j.Level;\nimport org.slf4j.Logger;\nimpor"
},
{
"path": "src/main/java/io/linuxserver/davos/dto/ActionDTO.java",
"chars": 448,
"preview": "package io.linuxserver.davos.dto;\n\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.la"
},
{
"path": "src/main/java/io/linuxserver/davos/dto/FTPFileDTO.java",
"chars": 221,
"preview": "package io.linuxserver.davos.dto;\n\npublic class FTPFileDTO {\n\n public String name;\n public String extension;\n p"
},
{
"path": "src/main/java/io/linuxserver/davos/dto/FilterDTO.java",
"chars": 354,
"preview": "package io.linuxserver.davos.dto;\n\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.la"
},
{
"path": "src/main/java/io/linuxserver/davos/dto/HostDTO.java",
"chars": 310,
"preview": "package io.linuxserver.davos.dto;\n\nimport io.linuxserver.davos.transfer.ftp.TransferProtocol;\n\npublic class HostDTO {\n\n "
},
{
"path": "src/main/java/io/linuxserver/davos/dto/ScheduleDTO.java",
"chars": 1031,
"preview": "package io.linuxserver.davos.dto;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.lang3.b"
},
{
"path": "src/main/java/io/linuxserver/davos/dto/ScheduleProcessResponse.java",
"chars": 131,
"preview": "package io.linuxserver.davos.dto;\n\npublic class ScheduleProcessResponse {\n\n public String message = \"OK\";\n public "
},
{
"path": "src/main/java/io/linuxserver/davos/exception/HostInUseException.java",
"chars": 252,
"preview": "package io.linuxserver.davos.exception;\n\npublic class HostInUseException extends RuntimeException {\n\n private static "
},
{
"path": "src/main/java/io/linuxserver/davos/exception/ScheduleAlreadyRunningException.java",
"chars": 273,
"preview": "package io.linuxserver.davos.exception;\n\npublic class ScheduleAlreadyRunningException extends RuntimeException {\n\n pr"
},
{
"path": "src/main/java/io/linuxserver/davos/exception/ScheduleNotRunningException.java",
"chars": 262,
"preview": "package io.linuxserver.davos.exception;\n\npublic class ScheduleNotRunningException extends RuntimeException {\n\n privat"
},
{
"path": "src/main/java/io/linuxserver/davos/logging/LoggingManager.java",
"chars": 826,
"preview": "package io.linuxserver.davos.logging;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.core.confi"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/dao/DefaultHostDAO.java",
"chars": 823,
"preview": "package io.linuxserver.davos.persistence.dao;\n\nimport java.util.List;\n\nimport javax.annotation.Resource;\n\nimport org.spr"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/dao/DefaultScheduleDAO.java",
"chars": 2753,
"preview": "package io.linuxserver.davos.persistence.dao;\n\nimport static java.util.stream.Collectors.toList;\n\nimport java.util.List;"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/dao/HostDAO.java",
"chars": 315,
"preview": "package io.linuxserver.davos.persistence.dao;\n\nimport java.util.List;\n\nimport io.linuxserver.davos.persistence.model.Hos"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/dao/ScheduleDAO.java",
"chars": 485,
"preview": "package io.linuxserver.davos.persistence.dao;\n\nimport java.util.List;\n\nimport io.linuxserver.davos.persistence.model.Sch"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/model/ActionModel.java",
"chars": 829,
"preview": "package io.linuxserver.davos.persistence.model;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimpor"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/model/FilterModel.java",
"chars": 606,
"preview": "package io.linuxserver.davos.persistence.model;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimpor"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/model/HostModel.java",
"chars": 1745,
"preview": "package io.linuxserver.davos.persistence.model;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.persis"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/model/ScannedFileModel.java",
"chars": 497,
"preview": "package io.linuxserver.davos.persistence.model;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimpor"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/model/ScheduleModel.java",
"chars": 3632,
"preview": "package io.linuxserver.davos.persistence.model;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.persis"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/repository/HostRepository.java",
"chars": 304,
"preview": "package io.linuxserver.davos.persistence.repository;\n\nimport java.util.List;\n\nimport org.springframework.data.repository"
},
{
"path": "src/main/java/io/linuxserver/davos/persistence/repository/ScheduleRepository.java",
"chars": 377,
"preview": "package io.linuxserver.davos.persistence.repository;\n\nimport java.util.List;\n\nimport org.springframework.data.repository"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/RunnableSchedule.java",
"chars": 1836,
"preview": "package io.linuxserver.davos.schedule;\n\nimport static java.util.stream.Collectors.toList;\n\nimport java.util.List;\n\nimpor"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/RunningSchedule.java",
"chars": 526,
"preview": "package io.linuxserver.davos.schedule;\n\nimport java.util.concurrent.ScheduledFuture;\n\npublic class RunningSchedule {\n\n "
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/ScheduleConfiguration.java",
"chars": 2935,
"preview": "package io.linuxserver.davos.schedule;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.linuxserver.davos."
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactory.java",
"chars": 2649,
"preview": "package io.linuxserver.davos.schedule;\n\nimport org.apache.commons.lang3.StringUtils;\n\nimport io.linuxserver.davos.persis"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/ScheduleExecutor.java",
"chars": 3374,
"preview": "package io.linuxserver.davos.schedule;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.Exec"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/ConnectWorkflowStep.java",
"chars": 1660,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.lin"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/DisconnectWorkflowStep.java",
"chars": 650,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.lin"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/DownloadFilesWorkflowStep.java",
"chars": 2931,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.lin"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/FilterFilesWorkflowStep.java",
"chars": 4822,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport static java.util.stream.Collectors.toList;\n\nimport java.util.Arr"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/ScheduleWorkflow.java",
"chars": 1714,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.slf4j.Lo"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/WorkflowStep.java",
"chars": 228,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\npublic abstract class WorkflowStep {\n\n protected WorkflowStep nextSt"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/actions/HttpAPICallAction.java",
"chars": 2113,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/actions/MoveFileAction.java",
"chars": 1365,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport or"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/actions/PostDownloadAction.java",
"chars": 149,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\npublic interface PostDownloadAction {\n\n void execute(PostDow"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/actions/PostDownloadExecution.java",
"chars": 125,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\npublic class PostDownloadExecution {\n\n public String fileNam"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/actions/PushbulletNotifyAction.java",
"chars": 2343,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/actions/SNSNotifyAction.java",
"chars": 2414,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimpor"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/filter/FileFilter.java",
"chars": 214,
"preview": "package io.linuxserver.davos.schedule.workflow.filter;\n\nimport java.util.List;\n\nimport io.linuxserver.davos.transfer.ftp"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/filter/ReferentialFileFilter.java",
"chars": 1400,
"preview": "package io.linuxserver.davos.schedule.workflow.filter;\n\nimport static java.util.stream.Collectors.toList;\n\nimport java.u"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/filter/TemporalFileFilter.java",
"chars": 965,
"preview": "package io.linuxserver.davos.schedule.workflow.filter;\n\nimport static java.util.stream.Collectors.toList;\n\nimport java.u"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FTPTransfer.java",
"chars": 852,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport io.linuxserver.davos.transfer.ftp.FTPFile;\nimport io.li"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FilesAndFoldersTranferStrategy.java",
"chars": 1312,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimpo"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/transfer/FilesOnlyTransferStrategy.java",
"chars": 1595,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimpo"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategy.java",
"chars": 1733,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org"
},
{
"path": "src/main/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategyFactory.java",
"chars": 493,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport io.linuxserver.davos.transfer.ftp.FileTransferType;\nimp"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/FTPFile.java",
"chars": 1084,
"preview": "package io.linuxserver.davos.transfer.ftp;\n\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.c"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/FileTransferType.java",
"chars": 98,
"preview": "package io.linuxserver.davos.transfer.ftp;\n\npublic enum FileTransferType {\n FILE, RECURSIVE;\n}\n"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/TransferProtocol.java",
"chars": 98,
"preview": "package io.linuxserver.davos.transfer.ftp;\n\npublic enum TransferProtocol {\n FTP, FTPS, SFTP;\n}\n"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/client/Client.java",
"chars": 638,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport io.linuxserver.davos.transfer.ftp.connection.Connection;\n\npubl"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/client/ClientFactory.java",
"chars": 443,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport io.linuxserver.davos.transfer.ftp.TransferProtocol;\n\npublic cl"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/client/FTPClient.java",
"chars": 3310,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport java.io.IOException;\nimport java.net.SocketException;\n\nimport "
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/client/FTPSClient.java",
"chars": 401,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic clas"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/client/SFTPClient.java",
"chars": 3057,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com."
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/client/UserCredentials.java",
"chars": 1109,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\npublic class UserCredentials {\n\n public static final UserCredentia"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/connection/Connection.java",
"chars": 722,
"preview": "package io.linuxserver.davos.transfer.ftp.connection;\n\nimport java.util.List;\n\nimport io.linuxserver.davos.transfer.ftp."
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/connection/ConnectionFactory.java",
"chars": 734,
"preview": "package io.linuxserver.davos.transfer.ftp.connection;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport "
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/connection/FTPConnection.java",
"chars": 9218,
"preview": "package io.linuxserver.davos.transfer.ftp.connection;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/connection/SFTPConnection.java",
"chars": 7494,
"preview": "package io.linuxserver.davos.transfer.ftp.connection;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.ut"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/connection/progress/ListenerFactory.java",
"chars": 722,
"preview": "package io.linuxserver.davos.transfer.ftp.connection.progress;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/connection/progress/ProgressListener.java",
"chars": 1364,
"preview": "package io.linuxserver.davos.transfer.ftp.connection.progress;\n\npublic class ProgressListener {\n\n private long lastWr"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/connection/progress/SFTPProgressListener.java",
"chars": 527,
"preview": "package io.linuxserver.davos.transfer.ftp.connection.progress;\n\nimport com.jcraft.jsch.SftpProgressMonitor;\n\npublic clas"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/exception/ClientConnectionException.java",
"chars": 459,
"preview": "package io.linuxserver.davos.transfer.ftp.exception;\n\npublic class ClientConnectionException extends FTPException {\n\n "
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/exception/ClientDisconnectException.java",
"chars": 459,
"preview": "package io.linuxserver.davos.transfer.ftp.exception;\n\npublic class ClientDisconnectException extends FTPException {\n\n "
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/exception/DeleteFileException.java",
"chars": 436,
"preview": "package io.linuxserver.davos.transfer.ftp.exception;\n\npublic class DeleteFileException extends FTPException {\n\n priva"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/exception/DownloadFailedException.java",
"chars": 451,
"preview": "package io.linuxserver.davos.transfer.ftp.exception;\n\npublic class DownloadFailedException extends FTPException {\n\n p"
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/exception/FTPException.java",
"chars": 420,
"preview": "package io.linuxserver.davos.transfer.ftp.exception;\n\npublic abstract class FTPException extends RuntimeException {\n\n "
},
{
"path": "src/main/java/io/linuxserver/davos/transfer/ftp/exception/FileListingException.java",
"chars": 439,
"preview": "package io.linuxserver.davos.transfer.ftp.exception;\n\npublic class FileListingException extends FTPException {\n\n priv"
},
{
"path": "src/main/java/io/linuxserver/davos/util/FileStreamFactory.java",
"chars": 511,
"preview": "package io.linuxserver.davos.util;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundExce"
},
{
"path": "src/main/java/io/linuxserver/davos/util/FileUtils.java",
"chars": 914,
"preview": "package io.linuxserver.davos.util;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport or"
},
{
"path": "src/main/java/io/linuxserver/davos/util/PatternBuilder.java",
"chars": 232,
"preview": "package io.linuxserver.davos.util;\n\npublic class PatternBuilder {\n\n public static String buildFromFilterString(String"
},
{
"path": "src/main/java/io/linuxserver/davos/web/API.java",
"chars": 1233,
"preview": "package io.linuxserver.davos.web;\n\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.la"
},
{
"path": "src/main/java/io/linuxserver/davos/web/Filter.java",
"chars": 617,
"preview": "package io.linuxserver.davos.web;\n\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.la"
},
{
"path": "src/main/java/io/linuxserver/davos/web/Host.java",
"chars": 2063,
"preview": "package io.linuxserver.davos.web;\n\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.la"
},
{
"path": "src/main/java/io/linuxserver/davos/web/Notifications.java",
"chars": 556,
"preview": "package io.linuxserver.davos.web;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Notifications {\n\n "
},
{
"path": "src/main/java/io/linuxserver/davos/web/Pushbullet.java",
"chars": 628,
"preview": "package io.linuxserver.davos.web;\n\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.la"
},
{
"path": "src/main/java/io/linuxserver/davos/web/SNS.java",
"chars": 966,
"preview": "package io.linuxserver.davos.web;\n\npublic class SNS {\n\n private Long id;\n private String topicArn;\n private Str"
},
{
"path": "src/main/java/io/linuxserver/davos/web/Schedule.java",
"chars": 4008,
"preview": "package io.linuxserver.davos.web;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.lang3.b"
},
{
"path": "src/main/java/io/linuxserver/davos/web/ScheduleCommand.java",
"chars": 154,
"preview": "package io.linuxserver.davos.web;\n\npublic class ScheduleCommand {\n\n public Command command;\n \n public enum Comm"
},
{
"path": "src/main/java/io/linuxserver/davos/web/Settings.java",
"chars": 336,
"preview": "package io.linuxserver.davos.web;\n\nimport io.linuxserver.davos.web.selectors.LogLevelSelector;\n\npublic class Settings {\n"
},
{
"path": "src/main/java/io/linuxserver/davos/web/Transfer.java",
"chars": 1542,
"preview": "package io.linuxserver.davos.web;\n\npublic class Transfer {\n\n private String fileName;\n private long fileSize;\n "
},
{
"path": "src/main/java/io/linuxserver/davos/web/VersionChecker.java",
"chars": 866,
"preview": "package io.linuxserver.davos.web;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.linuxserver.davos"
},
{
"path": "src/main/java/io/linuxserver/davos/web/controller/APIController.java",
"chars": 9096,
"preview": "package io.linuxserver.davos.web.controller;\n\nimport javax.annotation.Resource;\n\nimport org.slf4j.Logger;\nimport org.slf"
},
{
"path": "src/main/java/io/linuxserver/davos/web/controller/FragmentController.java",
"chars": 1709,
"preview": "package io.linuxserver.davos.web.controller;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.annotation.R"
},
{
"path": "src/main/java/io/linuxserver/davos/web/controller/ViewController.java",
"chars": 4189,
"preview": "package io.linuxserver.davos.web.controller;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.annotation.R"
},
{
"path": "src/main/java/io/linuxserver/davos/web/controller/response/APIResponse.java",
"chars": 353,
"preview": "package io.linuxserver.davos.web.controller.response;\n\npublic class APIResponse {\n\n public String status = \"OK\";\n "
},
{
"path": "src/main/java/io/linuxserver/davos/web/controller/response/APIResponseBuilder.java",
"chars": 173,
"preview": "package io.linuxserver.davos.web.controller.response;\n\npublic class APIResponseBuilder {\n\n public static APIResponse "
},
{
"path": "src/main/java/io/linuxserver/davos/web/selectors/IntervalSelector.java",
"chars": 848,
"preview": "package io.linuxserver.davos.web.selectors;\n\npublic enum IntervalSelector {\n\n MINS_1(1, \"Every minute\"),\n MINS_5(5"
},
{
"path": "src/main/java/io/linuxserver/davos/web/selectors/LogLevelSelector.java",
"chars": 193,
"preview": "package io.linuxserver.davos.web.selectors;\n\npublic enum LogLevelSelector {\n \n DEBUG, INFO, WARN, ERROR;\n\n publ"
},
{
"path": "src/main/java/io/linuxserver/davos/web/selectors/MethodSelector.java",
"chars": 185,
"preview": "package io.linuxserver.davos.web.selectors;\n\npublic enum MethodSelector {\n\n GET, POST, PUT, DELETE;\n \n public s"
},
{
"path": "src/main/java/io/linuxserver/davos/web/selectors/ProtocolSelector.java",
"chars": 175,
"preview": "package io.linuxserver.davos.web.selectors;\n\npublic enum ProtocolSelector {\n\n FTP, FTPS, SFTP;\n \n public static"
},
{
"path": "src/main/java/io/linuxserver/davos/web/selectors/TransferSelector.java",
"chars": 175,
"preview": "package io.linuxserver.davos.web.selectors;\n\npublic enum TransferSelector {\n\n FILE, RECURSIVE;\n \n public static"
},
{
"path": "src/main/resources/static/browserconfig.xml",
"chars": 246,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n <msapplication>\n <tile>\n <square150x150logo"
},
{
"path": "src/main/resources/static/css/davos.css",
"chars": 1018,
"preview": "body {\n padding-top: 40px;\n}\n\n.filter-label {\n padding: 10px;\n font-weight: normal;\n font-size: 12px;\n ma"
},
{
"path": "src/main/resources/static/js/davos.js",
"chars": 15601,
"preview": "/*global $, jQuery, base, Materialize */\nvar settings = (function($) {\n\n 'use strict';\n\n var initialise, makeNotif"
},
{
"path": "src/main/resources/static/manifest.json",
"chars": 403,
"preview": "{\n \"name\": \"\",\n \"icons\": [\n {\n \"src\": \"/android-chrome-192x192.png\",\n \"sizes\": \"192x1"
},
{
"path": "src/main/resources/templates/fragments/api.html",
"chars": 1546,
"preview": "<div class=\"well api\">\n\n\t<h4>API Call</h4>\n\n <div class=\"form-group\">\n <label class=\"col-lg-2 control-label\">U"
},
{
"path": "src/main/resources/templates/fragments/filter.html",
"chars": 163,
"preview": "<span class=\"label label-default filter-label\" th:attr=\"data-filter-value=${value}\" th:inline=\"text\">[[${value}]] <span "
},
{
"path": "src/main/resources/templates/fragments/header.html",
"chars": 2729,
"preview": "<!doctype html>\n<html lang=\"en\">\n\t<body>\n\t\n\t <div class=\"navbar navbar-default navbar-fixed-top\" th:fragment=\"header\""
},
{
"path": "src/main/resources/templates/fragments/pushbullet.html",
"chars": 509,
"preview": "<div class=\"well notification pushbullet\">\n\n\t<h4>Pushbullet</h4>\n\n <div class=\"form-group\">\n <label class=\"col"
},
{
"path": "src/main/resources/templates/fragments/sns.html",
"chars": 1667,
"preview": "<div class=\"well notification sns\">\n\n\t<h4>Amazon SNS</h4>\n\n <div class=\"form-group\">\n <label class=\"col-lg-2 c"
},
{
"path": "src/main/resources/templates/fragments/transfers.html",
"chars": 1729,
"preview": "<table class=\"table\" th:if=\"${not #lists.isEmpty(schedule.transfers)}\">\n <thead>\n <tr>\n <th>File</t"
},
{
"path": "src/main/resources/templates/v2/edit-host.html",
"chars": 11764,
"preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE"
},
{
"path": "src/main/resources/templates/v2/edit-schedule.html",
"chars": 24320,
"preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE"
},
{
"path": "src/main/resources/templates/v2/hosts.html",
"chars": 2862,
"preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE"
},
{
"path": "src/main/resources/templates/v2/schedules.html",
"chars": 7933,
"preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE"
},
{
"path": "src/main/resources/templates/v2/settings.html",
"chars": 3178,
"preview": "<!doctype html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE"
},
{
"path": "src/test/java/io/linuxserver/davos/VersionTest.java",
"chars": 1706,
"preview": "package io.linuxserver.davos;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport org.junit.Test;\n\nimport"
},
{
"path": "src/test/java/io/linuxserver/davos/delegation/services/ScheduleServiceImplTest.java",
"chars": 8705,
"preview": "package io.linuxserver.davos.delegation.services;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport stat"
},
{
"path": "src/test/java/io/linuxserver/davos/delegation/services/SettingsServiceImplTest.java",
"chars": 2427,
"preview": "package io.linuxserver.davos.delegation.services;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport stat"
},
{
"path": "src/test/java/io/linuxserver/davos/persistence/dao/DefaultScheduleDAOTest.java",
"chars": 2015,
"preview": "package io.linuxserver.davos.persistence.dao;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static o"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactoryTest.java",
"chars": 6540,
"preview": "package io.linuxserver.davos.schedule;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport java.util.Arra"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/ScheduleExecutorTest.java",
"chars": 5514,
"preview": "package io.linuxserver.davos.schedule;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mock"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/ConnectWorkflowStepTest.java",
"chars": 5352,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/DisconnectWorkflowStepTest.java",
"chars": 2105,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mo"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/DownloadFilesWorkflowStepTest.java",
"chars": 6678,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport static java.util.stream.Collectors.toList;\nimport static org.ass"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/FilterFilesWorkflowStepTest.java",
"chars": 15000,
"preview": "package io.linuxserver.davos.schedule.workflow;\n\nimport static java.util.stream.Collectors.toList;\nimport static org.ass"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/actions/HttpAPICallActionTest.java",
"chars": 3823,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimpor"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/actions/MoveFileActionTest.java",
"chars": 1429,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\nimport static org.mockito.Matchers.anyString;\nimport static org"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/actions/PushbulletNotifyActionTest.java",
"chars": 3446,
"preview": "package io.linuxserver.davos.schedule.workflow.actions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimpor"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/filter/ReferentialFileFilterTest.java",
"chars": 2054,
"preview": "package io.linuxserver.davos.schedule.workflow.filter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimpor"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/transfer/FilesAndFoldersTranferStrategyTest.java",
"chars": 1302,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mo"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/transfer/FilesOnlyTransferStrategyTest.java",
"chars": 1939,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimpo"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategyFactoryTest.java",
"chars": 635,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimp"
},
{
"path": "src/test/java/io/linuxserver/davos/schedule/workflow/transfer/TransferStrategyTest.java",
"chars": 3086,
"preview": "package io.linuxserver.davos.schedule.workflow.transfer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimpo"
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/client/ClientFactoryTest.java",
"chars": 707,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport org"
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/client/FTPClientTest.java",
"chars": 7353,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport stat"
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/client/FTPSClientTest.java",
"chars": 393,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport org"
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/client/SFTPClientTest.java",
"chars": 5554,
"preview": "package io.linuxserver.davos.transfer.ftp.client;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport stat"
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/connection/FTPConnectionTest.java",
"chars": 18298,
"preview": "package io.linuxserver.davos.transfer.ftp.connection;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport "
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/connection/SFTPConnectionTest.java",
"chars": 12900,
"preview": "package io.linuxserver.davos.transfer.ftp.connection;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport "
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/connection/progress/ListenerFactoryTest.java",
"chars": 731,
"preview": "package io.linuxserver.davos.transfer.ftp.connection.progress;\n\nimport static org.assertj.core.api.Assertions.assertThat"
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/connection/progress/ProgressListenerTest.java",
"chars": 2035,
"preview": "package io.linuxserver.davos.transfer.ftp.connection.progress;\n\nimport static org.assertj.core.api.Assertions.assertThat"
},
{
"path": "src/test/java/io/linuxserver/davos/transfer/ftp/connection/progress/SFTPProgressListenerTest.java",
"chars": 744,
"preview": "package io.linuxserver.davos.transfer.ftp.connection.progress;\n\nimport static org.assertj.core.api.Assertions.assertThat"
},
{
"path": "src/test/java/io/linuxserver/davos/util/PatternBuilderTest.java",
"chars": 1766,
"preview": "package io.linuxserver.davos.util;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport org.junit.Test;\n\np"
},
{
"path": "src/test/java/io/linuxserver/davos/web/controller/APIControllerTest.java",
"chars": 4386,
"preview": "package io.linuxserver.davos.web.controller;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static or"
},
{
"path": "src/test/java/io/linuxserver/davos/web/controller/ViewControllerTest.java",
"chars": 3676,
"preview": "package io.linuxserver.davos.web.controller;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static or"
},
{
"path": "version.txt",
"chars": 5,
"preview": "2.2.2"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the linuxserver/davos GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 184 files (424.6 KB), approximately 100.6k tokens, and a symbol index with 847 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.