[WIP] refactor service
This commit is contained in:
8 files changed
+141
-17
No files matched your search
@@ -1,5 +1,6 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
object Constants {
|
||||
const val CLASH_DIR = "clash"
|
||||
const val PROFILES_DIR = "profiles"
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.github.kr328.clash.core.model.ProxyGroup
|
||||
import com.github.kr328.clash.core.transact.DoneCallbackImpl
|
||||
import com.github.kr328.clash.core.transact.ProxyCollectionImpl
|
||||
import com.github.kr328.clash.core.transact.ProxyGroupCollectionImpl
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.lang.IllegalStateException
|
||||
import java.util.concurrent.BrokenBarrierException
|
||||
@@ -55,27 +56,27 @@ object Clash{
|
||||
Bridge.stopTunDevice()
|
||||
}
|
||||
|
||||
fun loadProfile(path: String, baseDir: String): CompletableFuture<Unit> {
|
||||
fun loadProfile(path: File, baseDir: File): CompletableFuture<Unit> {
|
||||
return DoneCallbackImpl().apply {
|
||||
Bridge.loadProfileFile(path, baseDir, this)
|
||||
Bridge.loadProfileFile(path.absolutePath, baseDir.absolutePath, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadProfile(url: String, output: String, baseDir: String): CompletableFuture<Unit> {
|
||||
fun downloadProfile(url: String, output: File, baseDir: File): CompletableFuture<Unit> {
|
||||
return DoneCallbackImpl().apply {
|
||||
Bridge.downloadProfileAndCheck(url, output, baseDir, this)
|
||||
Bridge.downloadProfileAndCheck(url, output.absolutePath, baseDir.absolutePath, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveProfile(data: ByteArray, output: String, baseDir: String): CompletableFuture<Unit> {
|
||||
fun saveProfile(data: ByteArray, output: File, baseDir: File): CompletableFuture<Unit> {
|
||||
return DoneCallbackImpl().apply {
|
||||
Bridge.saveProfileAndCheck(data, output, baseDir, this)
|
||||
Bridge.saveProfileAndCheck(data, output.absolutePath, baseDir.absolutePath, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun moveProfile(source: String, target: String, baseDir: String): CompletableFuture<Unit> {
|
||||
fun moveProfile(source: File, target: File, baseDir: File): CompletableFuture<Unit> {
|
||||
return DoneCallbackImpl().apply {
|
||||
Bridge.moveProfileAndCheck(source, target, baseDir, this)
|
||||
Bridge.moveProfileAndCheck(source.absolutePath, target.absolutePath, baseDir.absolutePath, this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package com.github.kr328.clash.service;
|
||||
|
||||
import com.github.kr328.clash.service.ipc.IPCParcelables;
|
||||
import com.github.kr328.clash.service.data.ClashProfileEntity;
|
||||
|
||||
interface IClashProfileManager {
|
||||
ParcelableCompletedFuture addProfile(String url);
|
||||
ParcelableCompletedFuture addProfile(String name, int type, String uri);
|
||||
ParcelableCompletedFuture updateProfile(int id);
|
||||
ParcelableCompletedFuture queryAllProfiles();
|
||||
ClashProfileEntity[] queryAllProfiles();
|
||||
}
|
||||
@@ -1,24 +1,114 @@
|
||||
package com.github.kr328.clash.service
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.github.kr328.clash.core.Clash
|
||||
import com.github.kr328.clash.service.data.ClashDatabase
|
||||
import com.github.kr328.clash.service.data.ClashProfileEntity
|
||||
import com.github.kr328.clash.service.ipc.ParcelableCompletedFuture
|
||||
import com.github.kr328.clash.service.util.DefaultThreadPool
|
||||
import com.github.kr328.clash.service.util.FileUtils
|
||||
|
||||
class ClashProfileManager(private val context: Context, private val database: ClashDatabase) :
|
||||
IClashProfileManager.Stub() {
|
||||
private val clashDir = context.filesDir.resolve(Constants.CLASH_DIR)
|
||||
private val profileDir = context.filesDir.resolve(Constants.PROFILES_DIR)
|
||||
|
||||
class ClashProfileManager(private val database: ClashDatabase): IClashProfileManager.Stub() {
|
||||
override fun updateProfile(id: Int): ParcelableCompletedFuture {
|
||||
val entity = database.openClashProfileDao().queryProfileById(id)
|
||||
|
||||
require(entity != null && entity.type == ClashProfileEntity.Type.URL)
|
||||
require(entity != null && (entity.type == ClashProfileEntity.Type.URL ||
|
||||
entity.type == ClashProfileEntity.Type.FILE))
|
||||
|
||||
val result = ParcelableCompletedFuture()
|
||||
|
||||
downloadProfile(Uri.parse(entity.uri), entity.file, entity.base,
|
||||
onSuccess = {
|
||||
result.complete(null)
|
||||
|
||||
database.openClashProfileDao().touchProfile(id)
|
||||
},
|
||||
onFailure = {
|
||||
result.completeExceptionally(it)
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun queryAllProfiles(): ParcelableCompletedFuture {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun queryAllProfiles(): Array<ClashProfileEntity> {
|
||||
return database.openClashProfileDao().queryProfiles()
|
||||
}
|
||||
|
||||
override fun addProfile(url: String?): ParcelableCompletedFuture {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
override fun addProfile(name: String, type: Int, uri: String?): ParcelableCompletedFuture {
|
||||
require(uri != null && (uri.startsWith("http") || uri.startsWith("content")))
|
||||
|
||||
val result = ParcelableCompletedFuture()
|
||||
val fileName = FileUtils.generateRandomFileName(profileDir, ".yaml")
|
||||
val baseDirName = FileUtils.generateRandomFileName(clashDir)
|
||||
|
||||
downloadProfile(Uri.parse(uri), fileName, baseDirName,
|
||||
onSuccess = {
|
||||
database.openClashProfileDao().addProfile(
|
||||
ClashProfileEntity(
|
||||
name,
|
||||
ClashProfileEntity.intToType(type),
|
||||
uri,
|
||||
fileName,
|
||||
baseDirName,
|
||||
false,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
)
|
||||
|
||||
result.complete(null)
|
||||
},
|
||||
onFailure = {
|
||||
result.completeExceptionally(it)
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun downloadProfile(
|
||||
uri: Uri?,
|
||||
fileName: String,
|
||||
baseDirName: String,
|
||||
onSuccess: () -> Unit,
|
||||
onFailure: (Throwable) -> Unit
|
||||
) {
|
||||
require(uri != null && uri != Uri.EMPTY)
|
||||
|
||||
if (uri.scheme == "http" || uri.scheme == "https") {
|
||||
Clash.downloadProfile(
|
||||
uri.toString(),
|
||||
profileDir.resolve(fileName),
|
||||
clashDir.resolve(baseDirName)
|
||||
)
|
||||
.whenComplete { _, u ->
|
||||
if (u != null)
|
||||
onFailure(u)
|
||||
else
|
||||
onSuccess()
|
||||
}
|
||||
} else {
|
||||
DefaultThreadPool.submit {
|
||||
try {
|
||||
val input = context.contentResolver.openInputStream(uri)
|
||||
?: throw NullPointerException("Unable to open profile")
|
||||
|
||||
input.use {
|
||||
Clash.saveProfile(
|
||||
it.readBytes(),
|
||||
profileDir.resolve(fileName),
|
||||
clashDir.resolve(baseDirName)
|
||||
)
|
||||
}
|
||||
|
||||
onSuccess()
|
||||
} catch (e: Exception) {
|
||||
onFailure(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,7 @@ package com.github.kr328.clash.service
|
||||
object Constants {
|
||||
const val CLASH_PROCESS_BROADCAST_ACTION = "com.github.kr328.clash.ClashService.ClashProcessEvent"
|
||||
const val CLASH_RELOAD_BROADCAST_ACTION = "com.github.kr328.clash.ClashService.ProfileReloadEvent"
|
||||
|
||||
const val CLASH_DIR = "clash"
|
||||
const val PROFILES_DIR = "profiles"
|
||||
}
|
||||
+2
-1
@@ -5,8 +5,9 @@ import android.os.Parcelable
|
||||
import android.os.RemoteException
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ParcelableCompletedFuture(private val pipe: ParcelablePipe = ParcelablePipe()) :
|
||||
class ParcelableCompletedFuture private constructor(private val pipe: ParcelablePipe) :
|
||||
CompletableFuture<Parcelable?>(), Parcelable {
|
||||
constructor(): this(ParcelablePipe())
|
||||
constructor(parcel: Parcel) : this(
|
||||
parcel.readParcelable<ParcelablePipe>(
|
||||
ParcelableCompletedFuture::class.java.classLoader
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.github.kr328.clash.service.util
|
||||
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
val DefaultThreadPool: ExecutorService = Executors.newCachedThreadPool()
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.github.kr328.clash.service.util
|
||||
|
||||
import java.io.File
|
||||
import java.security.SecureRandom
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
object FileUtils {
|
||||
private val random = SecureRandom()
|
||||
|
||||
fun generateRandomFileName(dir: File, suffix: String = ""): String {
|
||||
dir.mkdirs()
|
||||
|
||||
var fileName: String
|
||||
|
||||
do {
|
||||
fileName = random.nextLong().absoluteValue.toString() + suffix
|
||||
} while (dir.resolve(fileName).exists())
|
||||
|
||||
return fileName
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user