mirror of
https://github.com/linuxserver/davos.git
synced 2026-02-05 10:28:02 +08:00
Added patterns for schedule steps and actions
- Defined pattern for schedule workflow and steps - Implemented first 2 post-download actions (move, pushbullet)
This commit is contained in:
parent
5176a12827
commit
28bc100670
@ -45,6 +45,7 @@ dependencies {
|
||||
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'
|
||||
|
||||
runtime 'com.h2database:h2'
|
||||
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
package io.linuxserver.davos.schedule;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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>();
|
||||
|
||||
public ScheduleConfiguration(final String scheduleName, final TransferProtocol protocol, final String hostname,
|
||||
final int port, final UserCredentials credentials, final String remoteFilePath, final String localFilePath) {
|
||||
|
||||
this.scheduleName = scheduleName;
|
||||
this.connectionType = protocol;
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
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.steps.ConnectWorkflowStep;
|
||||
|
||||
public class ScheduleWorkflow implements Runnable {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleWorkflow.class);
|
||||
|
||||
private ScheduleConfiguration config;
|
||||
|
||||
public ScheduleWorkflow(ScheduleConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
LOGGER.info("Running schedule: {}", config.getScheduleName());
|
||||
new ConnectWorkflowStep().runSchedule(this);
|
||||
LOGGER.info("Finished schedule run: {}", config.getScheduleName());
|
||||
}
|
||||
|
||||
public ScheduleConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
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);
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
LOGGER.error("Unable to move {} to {}. Reason given: {}", execution.fileName, newFilePath, e.getMessage());
|
||||
LOGGER.debug("Full stack trace on error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package io.linuxserver.davos.schedule.workflow.actions;
|
||||
|
||||
public interface PostDownloadAction {
|
||||
|
||||
void execute(PostDownloadExecution execution);
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
package io.linuxserver.davos.schedule.workflow.actions;
|
||||
|
||||
public class PostDownloadExecution {
|
||||
|
||||
public String fileName;
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
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.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
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);
|
||||
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, PushbulletResponse.class);
|
||||
|
||||
} catch (RestClientException e) {
|
||||
LOGGER.debug("Full stacktrace", e);
|
||||
LOGGER.error("Unable to complete notification to Pushbullet. Given error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
class PushbulletResponse {
|
||||
|
||||
}
|
||||
|
||||
class PushbulletRequest {
|
||||
|
||||
public String type;
|
||||
public String title;
|
||||
public String body;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PushbulletRequest [type=" + type + ", title=" + title + ", body=" + body + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package io.linuxserver.davos.schedule.workflow.steps;
|
||||
|
||||
import io.linuxserver.davos.schedule.workflow.ScheduleWorkflow;
|
||||
|
||||
public class ConnectWorkflowStep extends WorkflowStep {
|
||||
|
||||
public ConnectWorkflowStep() {
|
||||
this.nextStep = new FilterFilesWorkflowStep();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runSchedule(ScheduleWorkflow schedule) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package io.linuxserver.davos.schedule.workflow.steps;
|
||||
|
||||
import io.linuxserver.davos.schedule.workflow.ScheduleWorkflow;
|
||||
|
||||
public class DisconnectWorkflowStep extends WorkflowStep {
|
||||
|
||||
@Override
|
||||
public void runSchedule(ScheduleWorkflow schedule) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package io.linuxserver.davos.schedule.workflow.steps;
|
||||
|
||||
import io.linuxserver.davos.schedule.workflow.ScheduleWorkflow;
|
||||
|
||||
public class DownloadFilesWorkflowStep extends WorkflowStep {
|
||||
|
||||
public DownloadFilesWorkflowStep() {
|
||||
this.nextStep = new DisconnectWorkflowStep();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runSchedule(ScheduleWorkflow schedule) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package io.linuxserver.davos.schedule.workflow.steps;
|
||||
|
||||
import io.linuxserver.davos.schedule.workflow.ScheduleWorkflow;
|
||||
|
||||
public class FilterFilesWorkflowStep extends WorkflowStep {
|
||||
|
||||
public FilterFilesWorkflowStep() {
|
||||
this.nextStep = new DownloadFilesWorkflowStep();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runSchedule(ScheduleWorkflow schedule) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package io.linuxserver.davos.schedule.workflow.steps;
|
||||
|
||||
import io.linuxserver.davos.schedule.workflow.ScheduleWorkflow;
|
||||
|
||||
public abstract class WorkflowStep {
|
||||
|
||||
protected WorkflowStep nextStep;
|
||||
|
||||
abstract public void runSchedule(ScheduleWorkflow schedule);
|
||||
}
|
||||
23
src/main/java/io/linuxserver/davos/util/FileUtils.java
Normal file
23
src/main/java/io/linuxserver/davos/util/FileUtils.java
Normal file
@ -0,0 +1,23 @@
|
||||
package io.linuxserver.davos.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public File getFile(String filePath) {
|
||||
return new File(filePath);
|
||||
}
|
||||
|
||||
public void moveFileToDirectory(String oldPath, String newPath) throws IOException {
|
||||
org.apache.commons.io.FileUtils.moveToDirectory(getFile(oldPath), getFile(newPath), true);
|
||||
}
|
||||
|
||||
public static String ensureTrailingSlash(String path) {
|
||||
|
||||
if (!path.endsWith("/"))
|
||||
return path + "/";
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@ -2,4 +2,4 @@
|
||||
#spring.datasource.username=sa
|
||||
#spring.datasource.password=sa
|
||||
#spring.datasource.driverClassName=org.h2.Driver
|
||||
#spring.jpa.hibernate.ddl-auto=none
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
|
||||
@ -1,39 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
|
||||
<Properties>
|
||||
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%rEx</Property>
|
||||
<Property name="LOG_LEVEL_PATTERN">%highlight{%-5p}</Property>
|
||||
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} - ${LOG_LEVEL_PATTERN} - [%c{1}] - %msg%n</Property>
|
||||
</Properties>
|
||||
|
||||
|
||||
<Appenders>
|
||||
|
||||
|
||||
<Console name="Console" target="SYSTEM_OUT" follow="true">
|
||||
<PatternLayout pattern="${LOG_PATTERN}" />
|
||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} - %5p - [%c{1}] - %msg%n" />
|
||||
</Console>
|
||||
|
||||
<RollingFile name="File" fileName="davos.log" filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log">
|
||||
|
||||
<RollingFile name="File" fileName="davos.log"
|
||||
filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log">
|
||||
<PatternLayout>
|
||||
<Pattern>${LOG_PATTERN}</Pattern>
|
||||
<Pattern>
|
||||
%d{yyyy-MM-dd HH:mm:ss.SSS} - $5p - [%c{1}] - %msg%n
|
||||
</Pattern>
|
||||
</PatternLayout>
|
||||
<Policies>
|
||||
<SizeBasedTriggeringPolicy size="10 MB" />
|
||||
</Policies>
|
||||
</RollingFile>
|
||||
|
||||
|
||||
</Appenders>
|
||||
|
||||
|
||||
<Loggers>
|
||||
|
||||
|
||||
<Logger name="io.linuxserver" level="debug" />
|
||||
<Logger name="org.thymeleaf" level="warn" />
|
||||
|
||||
<Root level="info">
|
||||
|
||||
<Root level="debug">
|
||||
<AppenderRef ref="Console" />
|
||||
<AppenderRef ref="File" />
|
||||
<!-- <AppenderRef ref="File" /> -->
|
||||
</Root>
|
||||
|
||||
|
||||
</Loggers>
|
||||
|
||||
|
||||
</Configuration>
|
||||
@ -0,0 +1,51 @@
|
||||
package io.linuxserver.davos.schedule.workflow.actions;
|
||||
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import io.linuxserver.davos.util.FileUtils;
|
||||
|
||||
public class MoveFileActionTest {
|
||||
|
||||
@InjectMocks
|
||||
private MoveFileAction moveFileAction = new MoveFileAction("oldPath", "newPath");
|
||||
|
||||
@Mock
|
||||
private FileUtils mockFileUtils;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeShouldMoveTheFile() throws IOException {
|
||||
|
||||
PostDownloadExecution execution = new PostDownloadExecution();
|
||||
execution.fileName = "filename";
|
||||
|
||||
moveFileAction.execute(execution);
|
||||
|
||||
verify(mockFileUtils).moveFileToDirectory("oldPath/filename", "newPath/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ifMovingOfFileFailsThenDoNotPerpetuateError() throws IOException {
|
||||
|
||||
doThrow(new IOException()).when(mockFileUtils).moveFileToDirectory(anyString(), anyString());
|
||||
|
||||
PostDownloadExecution execution = new PostDownloadExecution();
|
||||
execution.fileName = "filename";
|
||||
|
||||
moveFileAction.execute(execution);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package io.linuxserver.davos.schedule.workflow.actions;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import io.linuxserver.davos.schedule.workflow.actions.PushbulletNotifyAction.PushbulletRequest;
|
||||
import io.linuxserver.davos.schedule.workflow.actions.PushbulletNotifyAction.PushbulletResponse;
|
||||
|
||||
public class PushbulletNotifyActionTest {
|
||||
|
||||
@InjectMocks
|
||||
private PushbulletNotifyAction pushbulletNotifyAction;
|
||||
|
||||
@Mock
|
||||
private RestTemplate mockRestTemplate;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<HttpEntity<PushbulletRequest>> entityCaptor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
pushbulletNotifyAction = new PushbulletNotifyAction("apiKey");
|
||||
|
||||
initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeShouldSendCorrectData() {
|
||||
|
||||
PostDownloadExecution execution = new PostDownloadExecution();
|
||||
execution.fileName = "filename";
|
||||
|
||||
pushbulletNotifyAction.execute(execution);
|
||||
|
||||
verify(mockRestTemplate).exchange(eq("https://api.pushbullet.com/v2/pushes"), eq(HttpMethod.POST), entityCaptor.capture(),
|
||||
eq(PushbulletResponse.class));
|
||||
|
||||
PushbulletRequest request = entityCaptor.getValue().getBody();
|
||||
|
||||
assertThat(request.type).isEqualTo("note");
|
||||
assertThat(request.title).isEqualTo("A new file has been downloaded");
|
||||
assertThat(request.body).isEqualTo("filename");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postDataShouldHaveCorrectHeaderValue() {
|
||||
|
||||
PostDownloadExecution execution = new PostDownloadExecution();
|
||||
execution.fileName = "filename";
|
||||
|
||||
pushbulletNotifyAction.execute(execution);
|
||||
|
||||
verify(mockRestTemplate).exchange(eq("https://api.pushbullet.com/v2/pushes"), eq(HttpMethod.POST), entityCaptor.capture(),
|
||||
eq(PushbulletResponse.class));
|
||||
|
||||
HttpHeaders headers = entityCaptor.getValue().getHeaders();
|
||||
|
||||
assertThat(headers.getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
|
||||
assertThat(headers.get("Authorization").get(0)).isEqualTo("Bearer apiKey");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ifRestTemplateFailsThenDoNothing() {
|
||||
|
||||
when(mockRestTemplate.exchange(eq("https://api.pushbullet.com/v2/pushes"), eq(HttpMethod.POST), any(HttpEntity.class),
|
||||
eq(PushbulletResponse.class))).thenThrow(new RestClientException(""));
|
||||
|
||||
pushbulletNotifyAction.execute(new PostDownloadExecution());
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user