refactor(android): use file-sync as lib

This commit is contained in:
Andelf
2022-09-16 16:08:22 +08:00
parent 2a73019b34
commit 00ae42d89d
15 changed files with 1 additions and 484 deletions

View File

@@ -40,7 +40,6 @@ dependencies {
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
implementation project(':capacitor-cordova-android-plugins')
implementation project(':file-sync')
}
apply from: 'capacitor.build.gradle'

View File

@@ -1,351 +0,0 @@
package com.logseq.app;
import android.net.Uri;
import android.util.Log;
import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.logseq.sync.FileMeta;
import com.logseq.sync.RSFileSync;
import org.json.JSONException;
import java.util.List;
@CapacitorPlugin(name = "FileSync")
public class FileSync extends Plugin {
@Override
public void load() {
super.load();
Log.i("FileSync", "Android plugin loaded");
}
@PluginMethod()
public void keygen(PluginCall call) {
call.setKeepAlive(true);
Thread runner = new Thread() {
@Override
public void run() {
String[] keyPairs = RSFileSync.keygen();
JSObject data = new JSObject();
data.put("secretKey", keyPairs[0]);
data.put("publicKey", keyPairs[1]);
call.resolve(data);
}
};
runner.start();
}
@PluginMethod()
public void setKey(PluginCall call) {
String secretKey = call.getString("secretKey");
String publicKey = call.getString("publicKey");
long code = RSFileSync.setKeys(secretKey, publicKey);
if (code != -1) {
JSObject ret = new JSObject();
ret.put("ok", true);
call.resolve(ret);
} else {
call.reject("invalid setKey call");
}
}
@PluginMethod()
public void setEnv(PluginCall call) {
String env = call.getString("env");
if (env == null) {
call.reject("required parameter: env");
return;
}
this.setKey(call);
long code = RSFileSync.setEnvironment(env);
if (code != -1) {
JSObject ret = new JSObject();
ret.put("ok", true);
call.resolve(ret);
} else {
call.reject("invalid setEnv call");
}
}
@PluginMethod()
public void encryptFnames(PluginCall call) {
call.setKeepAlive(true);
Thread runner = new Thread() {
@Override
public void run() {
List<String> filePaths = null;
try {
filePaths = call.getArray("filePaths").toList();
} catch (JSONException e) {
e.printStackTrace();
return;
}
for (int i = 0; i < filePaths.size(); i++) {
String filePath = filePaths.get(i);
filePaths.set(i, Uri.decode(filePath));
}
String[] raw;
raw = RSFileSync.encryptFilenames(filePaths);
if (raw != null) {
JSObject ret = new JSObject();
ret.put("value", JSArray.from(raw));
call.resolve(ret);
}
}
};
runner.start();
}
@PluginMethod()
public void decryptFnames(PluginCall call) {
call.setKeepAlive(true);
Thread runner = new Thread() {
@Override
public void run() {
JSArray filePaths = call.getArray("filePaths");
String[] raw;
try {
raw = RSFileSync.decryptFilenames(filePaths.toList());
for (int i = 0; i < raw.length; i++) {
raw[i] = Uri.encode(raw[i], "/");
}
if (raw != null) {
JSObject ret = new JSObject();
ret.put("value", JSArray.from(raw));
call.resolve(ret);
}
} catch (JSONException e) {
e.printStackTrace();
call.reject("cannot decrypt fnames: " + e.toString());
}
}
};
runner.start();
}
//@PluginMethod(returnType = PluginMethod.RETURN_CALLBACK)
@PluginMethod()
public void getLocalFilesMeta(PluginCall call) throws JSONException {
String basePath = call.getString("basePath");
List<String> filePaths = call.getArray("filePaths").toList();
call.setKeepAlive(true);
Thread runner = new Thread() {
@Override
public void run() {
for (int i = 0; i < filePaths.size(); i++) {
String filePath = filePaths.get(i);
filePaths.set(i, Uri.decode(filePath));
}
FileMeta[] metas = RSFileSync.getLocalFilesMeta(basePath, filePaths);
if (metas == null) {
call.reject(RSFileSync.getLastError());
return;
}
JSObject dict = new JSObject();
for (FileMeta meta : metas) {
if (meta == null) {
continue;
}
Log.i("FileSync", "got meta " + meta.toString());
JSObject item = new JSObject();
item.put("md5", meta.md5);
item.put("size", meta.size);
item.put("encryptedFname", meta.encryptedFilename);
item.put("mtime", meta.mtime); // not used for now
dict.put(Uri.encode(meta.filePath, "/"), item);
}
JSObject ret = new JSObject();
ret.put("result", dict);
call.resolve(ret);
}
};
runner.start();
}
@PluginMethod()
public void getLocalAllFilesMeta(PluginCall call) {
call.setKeepAlive(true);
Thread runner = new Thread() {
@Override
public void run() {
String basePath = call.getString("basePath");
FileMeta[] metas = RSFileSync.getLocalAllFilesMeta(basePath);
if (metas == null) {
call.reject(RSFileSync.getLastError());
return;
}
JSObject dict = new JSObject();
for (FileMeta meta : metas) {
JSObject item = new JSObject();
item.put("md5", meta.md5);
item.put("size", meta.size);
item.put("encryptedFname", meta.encryptedFilename);
item.put("mtime", meta.mtime); // not used for now
dict.put(Uri.encode(meta.filePath, "/"), item);
}
JSObject ret = new JSObject();
ret.put("result", dict);
call.resolve(ret);
}
};
runner.start();
}
@PluginMethod()
public void deleteLocalFiles(PluginCall call) throws JSONException {
String basePath = call.getString("basePath");
List<String> filePaths = call.getArray("filePaths").toList();
for (int i = 0; i < filePaths.size(); i++) {
filePaths.set(i, Uri.decode(filePaths.get(i)));
}
RSFileSync.deleteLocalFiles(basePath, filePaths);
JSObject ret = new JSObject();
ret.put("ok", true);
call.resolve(ret);
}
@PluginMethod()
public void updateLocalFiles(PluginCall call) throws JSONException {
String basePath = call.getString("basePath");
List<String> filePaths = call.getArray("filePaths").toList();
String graphUUID = call.getString("graphUUID");
String token = call.getString("token");
for (int i = 0; i < filePaths.size(); i++) {
filePaths.set(i, Uri.decode(filePaths.get(i)));
}
call.setKeepAlive(true);
Thread runner = new Thread() {
@Override
public void run() {
long code = RSFileSync.updateLocalFiles(basePath, filePaths, graphUUID, token);
if (code != -1) {
JSObject ret = new JSObject();
ret.put("ok", true);
call.resolve(ret);
} else {
call.reject(RSFileSync.getLastError());
}
}
};
runner.start();
}
@PluginMethod()
public void updateLocalVersionFiles(PluginCall call) throws JSONException {
String basePath = call.getString("basePath");
List<String> filePaths = call.getArray("filePaths").toList();
String graphUUID = call.getString("graphUUID");
String token = call.getString("token");
for (int i = 0; i < filePaths.size(); i++) {
filePaths.set(i, Uri.decode(filePaths.get(i)));
}
call.setKeepAlive(true);
Thread runner = new Thread() {
@Override
public void run() {
long code = RSFileSync.updateLocalVersionFiles(basePath, filePaths, graphUUID, token);
if (code != -1) {
JSObject ret = new JSObject();
ret.put("ok", true);
call.resolve(ret);
} else {
call.reject(RSFileSync.getLastError());
}
}
};
runner.start();
}
@PluginMethod()
public void deleteRemoteFiles(PluginCall call) throws JSONException {
List<String> filePaths = call.getArray("filePaths").toList();
String graphUUID = call.getString("graphUUID");
String token = call.getString("token");
long txid = call.getInt("txid").longValue();
for (int i = 0; i < filePaths.size(); i++) {
filePaths.set(i, Uri.decode(filePaths.get(i)));
}
call.setKeepAlive(true);
Thread runner = new Thread() {
@Override
public void run() {
long code = RSFileSync.deleteRemoteFiles(filePaths, graphUUID, token, txid);
if (code != -1) {
JSObject ret = new JSObject();
ret.put("ok", true);
ret.put("txid", code);
call.resolve(ret);
} else {
call.reject(RSFileSync.getLastError());
}
}
};
runner.start();
}
@PluginMethod()
public void updateRemoteFiles(PluginCall call) throws JSONException {
String basePath = call.getString("basePath");
List<String> filePaths = call.getArray("filePaths").toList();
String graphUUID = call.getString("graphUUID");
String token = call.getString("token");
long txid = call.getInt("txid").longValue();
// NOTE: fnameEncryption is ignored. since it's always on.
for (int i = 0; i < filePaths.size(); i++) {
filePaths.set(i, Uri.decode(filePaths.get(i)));
}
Thread runner = new Thread() {
@Override
public void run() {
long code = RSFileSync.updateRemoteFiles(basePath, filePaths, graphUUID, token, txid);
if (code != -1) {
JSObject ret = new JSObject();
ret.put("ok", true);
ret.put("txid", code);
call.resolve(ret);
} else {
call.reject(RSFileSync.getLastError());
}
}
};
runner.start();
}
@PluginMethod()
public void ageEncryptWithPassphrase(PluginCall call) {
call.reject("unimplemented");
}
@PluginMethod()
public void ageDecryptWithPassphrase(PluginCall call) {
call.reject("unimplemented");
}
}

View File

@@ -14,7 +14,6 @@ public class MainActivity extends BridgeActivity {
public void onCreate(Bundle savedInstanceState) {
registerPlugin(FolderPicker.class);
registerPlugin(FsWatcher.class);
registerPlugin(FileSync.class);
super.onCreate(savedInstanceState);
new Timer().schedule(new TimerTask() {

View File

@@ -1 +0,0 @@
/build

View File

@@ -1,36 +0,0 @@
plugins {
id 'com.android.library'
}
android {
compileSdkVersion 30
defaultConfig {
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

View File

@@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.logseq.sync">
</manifest>

View File

@@ -1,33 +0,0 @@
package com.logseq.sync;
public class FileMeta {
public String filePath;
public long size;
public long mtime;
public String md5;
public String encryptedFilename;
public FileMeta(String filePath, long size, long mtime, String md5) {
this.filePath = filePath;
this.size = size;
this.mtime = mtime;
this.md5 = md5;
this.encryptedFilename = encryptedFilename;
}
public FileMeta(long size, long mtime, String md5) {
this.size = size;
this.mtime = mtime;
this.md5 = md5;
this.encryptedFilename = null;
}
public String toString() {
return "FileMeta{" +
"size=" + size +
", mtime=" + mtime +
", md5='" + md5 + '\'' +
", encryptedFilename='" + encryptedFilename + '\'' +
'}';
}
}

View File

@@ -1,34 +0,0 @@
package com.logseq.sync;
import java.util.List;
public class RSFileSync {
static {
System.loadLibrary("rsapi");
}
public static native String getLastError();
public static native String[] keygen();
public static native long setEnvironment(String env);
public static native long setKeys(String secretKey, String publicKey);
public static native String[] encryptFilenames(List<String> filenames);
public static native String[] decryptFilenames(List<String> encryptedFilenames);
public static native FileMeta[] getLocalFilesMeta(String basePath, List<String> filePaths);
public static native FileMeta[] getLocalAllFilesMeta(String basePath);
public static native long renameLocalFile(String basePath, String oldPath, String newPath);
public static native void deleteLocalFiles(String basePath, List<String> filePaths);
public static native long updateLocalFiles(String basePath, List<String> filePaths, String graphUUID, String token);
public static native long updateLocalVersionFiles(String basePath, List<String> filePaths, String graphUUID, String token);
public static native long deleteRemoteFiles(List<String> filePaths, String graphUUID, String token, long txid);
public static native long updateRemoteFiles(String basePath, List<String> filePaths, String graphUUID, String token, long txid);
}

View File

@@ -3,4 +3,4 @@ include ':capacitor-cordova-android-plugins'
project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
apply from: 'capacitor.settings.gradle'
include ':file-sync'