package com.wouterbreukink.onedrive.tasks;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.util.Preconditions;
import com.wouterbreukink.onedrive.TaskQueue;
import com.wouterbreukink.onedrive.client.OneDriveItem;
import com.wouterbreukink.onedrive.client.OneDriveProvider;
import com.wouterbreukink.onedrive.filesystem.FileSystemProvider;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import static com.wouterbreukink.onedrive.CommandLineOpts.getCommandLineOpts;
public abstract class Task implements Runnable, Comparable<Task> {
private static final Logger log = LogManager.getLogger(Task.class.getName());
private static AtomicInteger taskIdCounter = new AtomicInteger(1);
protected final TaskQueue queue;
protected final OneDriveProvider api;
protected final FileSystemProvider fileSystem;
protected final TaskReporter reporter;
private final int id;
private int attempt;
protected Task(TaskOptions options) {
this.queue = Preconditions.checkNotNull(options.getQueue());
this.api = Preconditions.checkNotNull(options.getApi());
this.fileSystem = Preconditions.checkNotNull(options.getFileSystem());
this.reporter = Preconditions.checkNotNull(options.getReporter());
this.id = taskIdCounter.getAndIncrement();
this.attempt = 0;
}
protected static boolean isSizeInvalid(File localFile) {
return isSizeInvalid(localFile.getPath(), localFile.length());
}
protected static boolean isSizeInvalid(OneDriveItem remoteFile) {
return isSizeInvalid(remoteFile.getFullName(), remoteFile.getSize());
}
private static boolean isSizeInvalid(String filename, long size) {
int maxSizeKb = getCommandLineOpts().getMaxSizeKb();
if (maxSizeKb > 0 && size > maxSizeKb * 1024) {
log.debug(String.format("Skipping file %s - size is %dKB (bigger than maximum of %dKB)",
filename,
size / 1024,
maxSizeKb));
return true;
}
return false;
}
protected static boolean isIgnored(OneDriveItem remoteFile) {
boolean ignored = isIgnored(remoteFile.getName() + (remoteFile.isDirectory() ? "/" : ""));
if (ignored) {
log.debug(String.format("Skipping ignored remote file %s", remoteFile.getFullName()));
}
return ignored;
}
protected static boolean isIgnored(File localFile) {
boolean ignored = isIgnored(localFile.getName() + (localFile.isDirectory() ? "/" : ""));
if (ignored) {
log.debug(String.format("Skipping ignored local file %s", localFile.getPath()));
}
return ignored;
}
private static boolean isIgnored(String name) {
Set<String> ignoredSet = getCommandLineOpts().getIgnored();
return ignoredSet != null && ignoredSet.contains(name);
}
protected TaskOptions getTaskOptions() {
return new TaskOptions(queue, api, fileSystem, reporter);
}
protected abstract int priority();
protected abstract void taskBody() throws IOException;
protected String getId() {
return this.id + ":" + this.attempt;
}
public void run() {
attempt++;
try {
log.debug(String.format("Starting task %d:%d - %s", id, attempt, this.toString()));
taskBody();
return;
} catch (HttpResponseException ex) {
switch (ex.getStatusCode()) {
case 401:
log.warn(String.format("Task %s encountered %s", getId(), ex.getMessage()));
break;
case 500:
case 502:
case 503:
case 504:
log.warn(String.format("Task %s encountered %s - sleeping 10 seconds", getId(), ex.getMessage()));
queue.suspend(10);
break;
case 429:
case 509:
log.warn(String.format("Task %s encountered %s - sleeping 60 seconds", getId(), ex.getMessage()));
queue.suspend(60);
break;
default:
log.warn(String.format("Task %s encountered %s", getId(), ex.getMessage()));
}
} catch (Exception ex) {
log.error(String.format("Task %s encountered exception", getId()), ex);
queue.suspend(1);
}
if (attempt < getCommandLineOpts().getTries()) {
queue.add(this);
} else {
reporter.error();
log.error(String.format("Task %d did not complete - %s", id, this.toString()));
}
}
@SuppressWarnings("NullableProblems")
public int compareTo(Task o) {
return o.priority() - priority();
}
public static class TaskOptions {
private final TaskQueue queue;
private final OneDriveProvider api;
private final FileSystemProvider fileSystem;
private final TaskReporter reporter;
public TaskOptions(TaskQueue queue, OneDriveProvider api, FileSystemProvider fileSystem, TaskReporter reporter) {
this.queue = queue;
this.api = api;
this.fileSystem = fileSystem;
this.reporter = reporter;
}
public TaskQueue getQueue() {
return queue;
}
public OneDriveProvider getApi() {
return api;
}
public FileSystemProvider getFileSystem() {
return fileSystem;
}
public TaskReporter getReporter() {
return reporter;
}
}
}