big change: move the json loading and random server selection to main PieCannon class (so that it has a reason to live :)) and implement loading the json file in the android app.
I deliberated between re-using the json file in the android app and using a sqlite database or some such thing, given that a UI for editing these will have to be implemented at some point. I figure the json file is more config than data, and probably should be as consistent as possible between platforms. For now at least this makes the app usable for me, without having to hard-code my server credentials.
This commit is contained in:
parent
432cfa4d21
commit
da39586c4d
@ -21,6 +21,6 @@ TODO
|
||||
TODO
|
||||
|
||||
## How to use
|
||||
Place a `servers.json` in your `XDG_DATA_HOME`, by default this would be `~/.local/share/piecannon` (create this directory if it does not exist. See `servers.example.json` for an example of such a file. Whenever you initiate a file upload, Pie Cannon will select one of your defined servers at random and upload the file.
|
||||
Place a `servers.json` in the Pie Cannon data directory. For GNU/Linux this is `XDG_DATA_HOME` (by default this would be `~/.local/share/piecannon`) (create this directory if it does not exist. For Android this would be the app's "externalFilesDir" (probably something like `Android/data/net.monarchpass.piecannon/files` - the app will tell you when you launch it). See `servers.example.json` for an example of such a file. Whenever you initiate a file upload, Pie Cannon will select one of your defined servers at random and upload the file.
|
||||
|
||||
For SFTP servers (the only supported type as of now), the `path` is relative to your home directory and should be where `url` points to. i.e. a file uploaded to `path` should be downloadable at `url`. In the future Pie Cannon should be able to get SSH credentials from your agent so you won't need to put a password in this file.
|
||||
|
@ -6,8 +6,9 @@
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/jcraft/jsch/0.1.55/jsch-0.1.55.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/jcraft/jsch/0.1.55/jsch-0.1.55.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/jodd/jodd-util/6.0.0/jodd-util-6.0.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/android/android/4.1.1.4/android-4.1.1.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpclient/4.0.1/httpclient-4.0.1.jar" enabled="true" runInBatchMode="false"/>
|
||||
|
@ -34,11 +34,6 @@
|
||||
<artifactId>jodd-util</artifactId>
|
||||
<version>6.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
|
@ -1,12 +1,22 @@
|
||||
package net.monarchpass.piecannon;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class Main extends Activity {
|
||||
@Override
|
||||
public void onCreate (final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
final File serversJson = new File(getExternalFilesDir(null), "servers.json");
|
||||
final TextView text = (TextView)findViewById(R.id.welcome);
|
||||
text.append("\n---\n");
|
||||
text.append(serversJson.exists() ? "servers.json file found at: " : "Please place a servers.json file at: ");
|
||||
text.append("\n");
|
||||
text.append(serversJson.getPath());
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import android.content.ContentResolver;
|
||||
import com.google.common.io.ByteSource;
|
||||
|
||||
import java.net.URI;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
@ -42,25 +43,34 @@ public class Send extends Activity {
|
||||
public void uploadImage (final Uri imageUri) {
|
||||
// handle image
|
||||
final TextView text = (TextView)findViewById(R.id.text);
|
||||
text.setText(imageUri.toString());
|
||||
text.append("\n---\nReceived file url: \n");
|
||||
text.append(imageUri.toString());
|
||||
|
||||
final ContentResolver resolver = getContentResolver();
|
||||
final Server testServer = new TestServer();
|
||||
final PieCannon cannon = new PieCannon();
|
||||
|
||||
try
|
||||
{
|
||||
cannon.loadServersFrom(new File(getExternalFilesDir(null), "servers.json"));
|
||||
}
|
||||
catch (final Exception exception)
|
||||
{
|
||||
logException(exception);
|
||||
return;
|
||||
}
|
||||
|
||||
executor.submit(() -> {
|
||||
try
|
||||
{
|
||||
final URI uploaded = testServer.upload(createFileNameForUri(imageUri, resolver), new ContentByteSource(resolver, imageUri));
|
||||
final URI uploaded = cannon.selectServer().upload(createFileNameForUri(imageUri, resolver), new ContentByteSource(resolver, imageUri));
|
||||
runOnUiThread(() -> {
|
||||
text.setText(uploaded.toString());
|
||||
text.append("\n---\nUploaded file to url: \n");
|
||||
text.append(uploaded.toString());
|
||||
shareUploadUrl(uploaded);
|
||||
});
|
||||
}
|
||||
catch (final Exception exception) {
|
||||
final StringWriter buf = new StringWriter();
|
||||
final PrintWriter out = new PrintWriter(buf);
|
||||
exception.printStackTrace(out);
|
||||
runOnUiThread(() -> text.setText(buf.toString()));
|
||||
logException(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -87,6 +97,17 @@ public class Send extends Activity {
|
||||
throw new RuntimeException("Could not construct a file name");
|
||||
}
|
||||
|
||||
private void logException (final Exception exception) {
|
||||
final StringWriter buf = new StringWriter();
|
||||
final PrintWriter out = new PrintWriter(buf);
|
||||
exception.printStackTrace(out);
|
||||
runOnUiThread(() -> {
|
||||
final TextView text = (TextView)findViewById(R.id.text);
|
||||
text.append("\n---\n");
|
||||
text.append(buf.toString());
|
||||
});
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
public static class ContentByteSource extends ByteSource {
|
||||
private final ContentResolver resolver;
|
||||
|
@ -1,18 +0,0 @@
|
||||
package net.monarchpass.piecannon;
|
||||
|
||||
import net.monarchpass.piecannon.impl.SftpServer;
|
||||
import java.net.URI;
|
||||
|
||||
public class TestServer extends SftpServer {
|
||||
public TestServer () {
|
||||
super(
|
||||
"Test Server",
|
||||
"",
|
||||
22,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
URI.create("")
|
||||
);
|
||||
}
|
||||
}
|
@ -5,4 +5,9 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="net.monarchpass.piecannon.Main">
|
||||
|
||||
<TextView android:id="@+id/welcome"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Welcome to Pie Cannon! There is no GUI for editing servers yet." />
|
||||
</ScrollView>
|
||||
|
14
android/src/main/res/layout/activity_send.xml
Normal file
14
android/src/main/res/layout/activity_send.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context="net.monarchpass.piecannon.Send">
|
||||
|
||||
<TextView android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Pie Cannon at work!" />
|
||||
|
||||
</ScrollView>
|
@ -27,11 +27,6 @@
|
||||
<artifactId>xdg-java</artifactId>
|
||||
<version>0.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
@ -3,34 +3,22 @@ package net.monarchpass.piecannon;
|
||||
import java.net.URI;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.freedesktop.BaseDirectory;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import lombok.extern.java.Log;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import net.monarchpass.piecannon.util.ServerFactory;
|
||||
|
||||
@Log
|
||||
public class App {
|
||||
public static void main (final String... args) throws Exception {
|
||||
final File serversJson = getServersJson();
|
||||
final List<Server> servers = loadServersFrom(serversJson);
|
||||
final PieCannon cannon = new PieCannon();
|
||||
final List<Server> servers = cannon.loadServersFrom(serversJson);
|
||||
log.log(Level.INFO, "{0} servers loaded from {1}", new Object[] {
|
||||
servers.size(), serversJson
|
||||
});
|
||||
@ -40,7 +28,7 @@ public class App {
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
final Server server = servers.get(new Random().nextInt(servers.size()));
|
||||
final Server server = cannon.selectServer();
|
||||
log.log(Level.INFO, "Randomly selected server: {0}", server.getLabel());
|
||||
|
||||
if (args.length == 0) {
|
||||
@ -57,23 +45,7 @@ public class App {
|
||||
final URI result = server.upload(source);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
public static List<Server> loadServersFrom (final File serversJson) throws IOException {
|
||||
if (!serversJson.exists()) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
final ServerFactory factory = new ServerFactory();
|
||||
try (final InputStream in = new FileInputStream(serversJson)) {
|
||||
final JsonParser parser = new JsonParser();
|
||||
return Streams.stream(parser.parse(new InputStreamReader(in)).getAsJsonArray())
|
||||
.filter(JsonElement::isJsonObject)
|
||||
.map(JsonObject.class::cast)
|
||||
.map(factory)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static File getServersJson () {
|
||||
return new File(getDataDirectory(), "servers.json");
|
||||
}
|
||||
|
44
lib/.classpath
Normal file
44
lib/.classpath
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" path="target/generated-sources/annotations">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="ignore_optional_problems" value="true"/>
|
||||
<attribute name="m2e-apt" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="ignore_optional_problems" value="true"/>
|
||||
<attribute name="m2e-apt" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
11
lib/.factorypath
Normal file
11
lib/.factorypath
Normal file
@ -0,0 +1,11 @@
|
||||
<factorypath>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/github/mwiede/jsch/0.1.60/jsch-0.1.60.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/guava/30.0-android/guava-30.0-android.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/errorprone/error_prone_annotations/2.3.4/error_prone_annotations-2.3.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/projectlombok/lombok/1.18.16/lombok-1.18.16.jar" enabled="true" runInBatchMode="false"/>
|
||||
</factorypath>
|
34
lib/.project
Normal file
34
lib/.project
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>libpiecannon</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
<filteredResources>
|
||||
<filter>
|
||||
<id>1603692553450</id>
|
||||
<name></name>
|
||||
<type>30</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
</filteredResources>
|
||||
</projectDescription>
|
4
lib/.settings/org.eclipse.jdt.apt.core.prefs
Normal file
4
lib/.settings/org.eclipse.jdt.apt.core.prefs
Normal file
@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.apt.aptEnabled=true
|
||||
org.eclipse.jdt.apt.genSrcDir=target/generated-sources/annotations
|
||||
org.eclipse.jdt.apt.genTestSrcDir=target/generated-test-sources/test-annotations
|
9
lib/.settings/org.eclipse.jdt.core.prefs
Normal file
9
lib/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,9 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
|
||||
org.eclipse.jdt.core.compiler.processAnnotations=enabled
|
||||
org.eclipse.jdt.core.compiler.release=disabled
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
4
lib/.settings/org.eclipse.m2e.core.prefs
Normal file
4
lib/.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
@ -22,6 +22,11 @@
|
||||
<artifactId>guava</artifactId>
|
||||
<version>30.0-android</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
@ -2,18 +2,62 @@ package net.monarchpass.piecannon;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.CharSource;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
public class PieCannon {
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import net.monarchpass.piecannon.util.ServerFactory;
|
||||
|
||||
public class PieCannon {
|
||||
public List<Server> servers;
|
||||
|
||||
public List<Server> loadServersFrom (final File serversJson) throws IOException {
|
||||
try (final InputStream in = new FileInputStream(serversJson)) {
|
||||
return loadServersFrom(in);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Server> loadServersFrom (final InputStream in) throws IOException {
|
||||
final ServerFactory factory = new ServerFactory();
|
||||
final JsonParser parser = new JsonParser();
|
||||
final List<Server> loadedServers = new ArrayList<>();
|
||||
for (final JsonElement element : parser.parse(new InputStreamReader(in)).getAsJsonArray()) {
|
||||
if (!element.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
loadedServers.add(factory.apply((JsonObject)element));
|
||||
}
|
||||
servers = loadedServers;
|
||||
return loadedServers;
|
||||
}
|
||||
|
||||
public Server selectServer () {
|
||||
if (servers == null) {
|
||||
throw new IllegalStateException("Servers are not loaded");
|
||||
}
|
||||
|
||||
return servers.get(new Random().nextInt(servers.size()));
|
||||
}
|
||||
|
||||
public static boolean testServer (final Server server) {
|
||||
final String testString = "piecannon-test-" + System.currentTimeMillis();
|
||||
final URI result = server.upload("piecannon.test", CharSource.wrap(testString).asByteSource(Charsets.UTF_8));
|
||||
|
@ -1,10 +1,11 @@
|
||||
package net.monarchpass.piecannon;
|
||||
package net.monarchpass.piecannon.util;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.monarchpass.piecannon.Server;
|
||||
import net.monarchpass.piecannon.impl.SftpServer;
|
||||
|
||||
public class ServerFactory implements Function<JsonObject, Server> {
|
Loading…
x
Reference in New Issue
Block a user