Skip to content

Commit

Permalink
Merge branch 'develop' into 'master'
Browse files Browse the repository at this point in the history
Develop

See merge request papers/airgap/airgap-vault!431
  • Loading branch information
godenzim committed May 16, 2023
2 parents 35f35e6 + f665565 commit 6730f17
Show file tree
Hide file tree
Showing 78 changed files with 3,151 additions and 468 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ interface StaticSourcesExplorer {
fun readIsolatedModulesScript(): ByteArray
}

interface DynamicSourcesExplorer<in M : JSModule> {
interface DynamicSourcesExplorer {
fun removeModules(identifiers: List<String>)
fun removeAllModules()
}

interface SourcesExplorer<in M : JSModule> {
fun listModules(): List<String>

fun readModuleSources(module: M): Sequence<ByteArray>
Expand Down Expand Up @@ -55,6 +60,14 @@ class FileExplorer private constructor(
}
}

fun removeInstalledModules(identifiers: List<String>) {
filesExplorer.removeModules(identifiers)
}

fun removeAllInstalledModules() {
filesExplorer.removeAllModules()
}

fun readModuleSources(module: JSModule): Sequence<ByteArray> =
when (module) {
is JSModule.Asset -> assetsExplorer.readModuleSources(module)
Expand All @@ -70,7 +83,7 @@ class FileExplorer private constructor(
}

private fun <T : JSModule> loadModules(
explorer: DynamicSourcesExplorer<T>,
explorer: SourcesExplorer<T>,
constructor: (identifier: String, namespace: String?, preferredEnvironment: JSEnvironment.Type, paths: List<String>) -> T,
): List<T> = explorer.listModules().map { module ->
val manifest = JSObject(explorer.readModuleManifest(module).decodeToString())
Expand All @@ -96,7 +109,7 @@ class FileExplorer private constructor(
}
}

private class AssetsExplorer(private val context: Context) : StaticSourcesExplorer, DynamicSourcesExplorer<JSModule.Asset> {
private class AssetsExplorer(private val context: Context) : StaticSourcesExplorer, SourcesExplorer<JSModule.Asset> {
override fun readJavaScriptEngineUtils(): ByteArray = context.assets.readBytes(JAVA_SCRIPT_ENGINE_UTILS)
override fun readIsolatedModulesScript(): ByteArray = context.assets.readBytes(SCRIPT)

Expand All @@ -117,10 +130,20 @@ private class AssetsExplorer(private val context: Context) : StaticSourcesExplor
}
}

private class FilesExplorer(private val context: Context) : DynamicSourcesExplorer<JSModule.Installed> {
private class FilesExplorer(private val context: Context) : DynamicSourcesExplorer, SourcesExplorer<JSModule.Installed> {
private val modulesDir: File
get() = File(context.filesDir, MODULES_DIR)

override fun removeModules(identifiers: List<String>) {
identifiers.forEach {
File(modulesDir, it).deleteRecursively()
}
}

override fun removeAllModules() {
modulesDir.deleteRecursively()
}

override fun listModules(): List<String> = modulesDir.list()?.toList() ?: emptyList()

override fun readModuleSources(module: JSModule.Installed): Sequence<ByteArray> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class IsolatedModules : Plugin() {
private val fileExplorer: FileExplorer by lazy { FileExplorer(context) }

@PluginMethod
fun previewModule(call: PluginCall) {
fun previewDynamicModule(call: PluginCall) {
call.executeCatching {
assertReceived(Param.PATH, Param.DIRECTORY)

Expand All @@ -44,7 +44,7 @@ class IsolatedModules : Plugin() {
}

@PluginMethod
fun registerModule(call: PluginCall) {
fun registerDynamicModule(call: PluginCall) {
call.executeCatching {
assertReceived(Param.IDENTIFIER, Param.PROTOCOL_IDENTIFIERS)

Expand All @@ -60,7 +60,26 @@ class IsolatedModules : Plugin() {
}

@PluginMethod
fun loadModules(call: PluginCall) {
fun removeDynamicModules(call: PluginCall) {
activity.lifecycleScope.launch {
call.executeCatching {
val jsEvaluator = jsEvaluator.await()

identifiers?.let {
fileExplorer.removeInstalledModules(it)
jsEvaluator.deregisterModules(it)
} ?: run {
fileExplorer.removeAllInstalledModules()
jsEvaluator.deregisterAllModules()
}

resolve()
}
}
}

@PluginMethod
fun loadAllModules(call: PluginCall) {
activity.lifecycleScope.launch {
call.executeCatching {
val modules = fileExplorer.loadAssetModules() + fileExplorer.loadInstalledModules()
Expand Down Expand Up @@ -117,6 +136,9 @@ class IsolatedModules : Plugin() {
private val PluginCall.identifier: String
get() = getString(Param.IDENTIFIER)!!

private val PluginCall.identifiers: List<String>?
get() = getArray(Param.PROTOCOL_IDENTIFIERS, null)?.toList()

private val PluginCall.protocolIdentifiers: List<String>
get() = getArray(Param.PROTOCOL_IDENTIFIERS).toList()

Expand Down Expand Up @@ -145,6 +167,7 @@ class IsolatedModules : Plugin() {
const val PATH = "path"
const val DIRECTORY = "directory"
const val IDENTIFIER = "identifier"
const val IDENTIFIERS = "identifiers"
const val PROTOCOL_IDENTIFIERS = "protocolIdentifiers"
const val PROTOCOL_TYPE = "protocolType"
const val TARGET = "target"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ class JSEvaluator constructor(
module.registerFor(protocolIdentifiers)
}

fun deregisterModules(identifiers: List<String>) {
identifiers.forEach { modules.remove(it) }
}

fun deregisterAllModules() {
modules.clear()
}

suspend fun evaluatePreviewModule(module: JSModule): JSObject =
module.environment.run(module, JSModuleAction.Load(null)).also {
module.appendType(it)
Expand Down
53 changes: 46 additions & 7 deletions ios/App/App/IsolatedModules/FileExplorer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ struct FileExplorer {
})
}

func removeModules(_ identifiers: [String]) throws {
try documentExplorer.removeModules(identifiers)
}

func removeAllModules() throws {
try documentExplorer.removeAllModules()
}

func readModuleSources(_ module: JSModule) throws -> [Data] {
switch module {
case .asset(let asset):
Expand All @@ -77,7 +85,7 @@ struct FileExplorer {
}
}

private func loadModules<T: JSModuleProtocol, E: DynamicSourcesExplorer>(
private func loadModules<T: JSModuleProtocol, E: SourcesExplorer>(
using explorer: E,
creatingModuleWith moduleInit: (_ identifier: String, _ namespace: String?, _ preferredEnvironment: JSEnvironmentKind, _ sources: [String]) -> T
) throws -> [T] where E.T == T {
Expand Down Expand Up @@ -107,7 +115,7 @@ struct FileExplorer {

// MARK: AssetsExplorer

private struct AssetsExplorer: DynamicSourcesExplorer {
private struct AssetsExplorer: SourcesExplorer {
typealias T = JSModule.Asset

static let assetsURL: URL = Bundle.main.url(forResource: "public", withExtension: nil)!.appendingPathComponent("assets")
Expand Down Expand Up @@ -149,23 +157,49 @@ private struct AssetsExplorer: DynamicSourcesExplorer {

// MARK: DocumentExplorer

private struct DocumentExplorer: DynamicSourcesExplorer {
private struct DocumentExplorer: SourcesExplorer, DynamicSourcesExplorer {
typealias T = JSModule.Instsalled

private static let modulesDir: String = "protocol_modules"

private let fileManager: FileManager

private var documentsURL: URL? { fileManager.urls(for: .documentDirectory, in: .userDomainMask).first }
private var modulesDirURL: URL? { documentsURL?.appendingPathComponent(Self.modulesDir) }

init(fileManager: FileManager) {
self.fileManager = fileManager
}

func removeModules(_ identifiers: [String]) throws {
guard let modulesDirURL = modulesDirURL else {
return
}

var isDirectory: ObjCBool = true
try identifiers.forEach {
if fileManager.fileExists(atPath: modulesDirURL.path, isDirectory: &isDirectory) {
try fileManager.removeItem(at: modulesDirURL.appendingPathComponent($0))
}
}
}

func removeAllModules() throws {
var isDirectory: ObjCBool = true
guard let modulesDirURL = modulesDirURL, fileManager.fileExists(atPath: modulesDirURL.path, isDirectory: &isDirectory) else {
return
}

try fileManager.removeItem(at: modulesDirURL)
}

func listModules() throws -> [String] {
guard let url = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else {
guard let modulesDirURL = modulesDirURL else {
return []
}

let modulesDirPath = url.appendingPathComponent(Self.modulesDir).path
let modulesDirPath = modulesDirURL.path

guard fileManager.fileExists(atPath: modulesDirPath) else {
return []
}
Expand Down Expand Up @@ -194,9 +228,9 @@ private struct DocumentExplorer: DynamicSourcesExplorer {
}
}

// MARK: DynamicSourcesExplorer
// MARK: SourcesExplorer

private protocol DynamicSourcesExplorer {
private protocol SourcesExplorer {
associatedtype T

func listModules() throws -> [String]
Expand All @@ -205,6 +239,11 @@ private protocol DynamicSourcesExplorer {
func readModuleManifest(_ module: String) throws -> Data
}

private protocol DynamicSourcesExplorer {
func removeModules(_ identifiers: [String]) throws
func removeAllModules() throws
}

// MARK: Extensions

private extension FileExplorer {
Expand Down
7 changes: 4 additions & 3 deletions ios/App/App/IsolatedModules/IsolatedModules.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@

// disable true isolation until it's production ready
//CAP_PLUGIN(IsolatedModules, "IsolatedModules",
// CAP_PLUGIN_METHOD(previewModule, CAPPluginReturnPromise);
// CAP_PLUGIN_METHOD(registerModule, CAPPluginReturnPromise);
// CAP_PLUGIN_METHOD(loadModules, CAPPluginReturnPromise);
// CAP_PLUGIN_METHOD(previewDynamicModule, CAPPluginReturnPromise);
// CAP_PLUGIN_METHOD(registerDynamicModule, CAPPluginReturnPromise);
// CAP_PLUGIN_METHOD(removeDynamicModules, CAPPluginReturnPromise);
// CAP_PLUGIN_METHOD(loadAllModules, CAPPluginReturnPromise);
// CAP_PLUGIN_METHOD(callMethod, CAPPluginReturnPromise);
//)
33 changes: 30 additions & 3 deletions ios/App/App/IsolatedModules/IsolatedModules.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class IsolatedModules: CAPPlugin {
private let fileExplorer: FileExplorer = .shared
private lazy var jsEvaluator: JSEvaluator = .init(fileExplorer: fileExplorer)

@objc func previewModule(_ call: CAPPluginCall) {
@objc func previewDynamicModule(_ call: CAPPluginCall) {
call.assertReceived(forMethod: "previewModule", requiredParams: Param.PATH, Param.DIRECTORY)

do {
Expand All @@ -41,7 +41,7 @@ public class IsolatedModules: CAPPlugin {
}
}

@objc func registerModule(_ call: CAPPluginCall) {
@objc func registerDynamicModule(_ call: CAPPluginCall) {
call.assertReceived(forMethod: "registerModule", requiredParams: Param.IDENTIFIER, Param.PROTOCOL_IDENTIFIERS)

do {
Expand All @@ -64,7 +64,24 @@ public class IsolatedModules: CAPPlugin {
}
}

@objc func loadModules(_ call: CAPPluginCall) {
@objc func removeDynamicModules(_ call: CAPPluginCall) {
Task {
do {
if let identifiers = call.identifiers {
try fileExplorer.removeModules(identifiers)
await jsEvaluator.deregisterModules(identifiers)
} else {
try fileExplorer.removeAllModules()
await jsEvaluator.deregisterAllModules()
}
call.resolve()
} catch {
call.reject("Error: \(error)")
}
}
}

@objc func loadAllModules(_ call: CAPPluginCall) {
Task {
do {
let protocolType = call.protocolType
Expand Down Expand Up @@ -152,6 +169,7 @@ public class IsolatedModules: CAPPlugin {
static let PATH = "path"
static let DIRECTORY = "directory"
static let IDENTIFIER = "identifier"
static let IDENTIFIERS = "identifiers"
static let PROTOCOL_IDENTIFIERS = "protocolIdentifiers"
static let PROTOCOL_TYPE = "protocolType"
static let TARGET = "target"
Expand All @@ -176,6 +194,15 @@ private extension CAPPluginCall {
}

var identifier: String? { return getString(IsolatedModules.Param.IDENTIFIER) }
var identifiers: [String]? {
return getArray(IsolatedModules.Param.IDENTIFIERS)?.compactMap {
if let string = $0 as? String {
return string
} else {
return nil
}
}
}
var protocolIdentifiers: [String]? {
return getArray(IsolatedModules.Param.PROTOCOL_IDENTIFIERS)?.compactMap {
if let string = $0 as? String {
Expand Down
16 changes: 16 additions & 0 deletions ios/App/App/IsolatedModules/JS/JSEvaluator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ class JSEvaluator {
await modulesManager.registerModule(module, forProtocols: protocolIdentifiers)
}

func deregisterModules(_ identifiers: [String]) async {
await modulesManager.deregisterModules(identifiers)
}

func deregisterAllModules() async {
await modulesManager.deregisterAllModules()
}

func evaluatePreviewModule(_ module: JSModule) async throws -> [String: Any] {
return try await self.webViewEnv.run(.load(.init(protocolType: nil)), in: module)
}
Expand Down Expand Up @@ -146,6 +154,14 @@ class JSEvaluator {
modules[module.identifier] = module
protocolIdentifiers.forEach { identifier in modules[identifier] = module }
}

func deregisterModules(_ identifiers: [String]) {
identifiers.forEach { modules.removeValue(forKey: $0) }
}

func deregisterAllModules() {
modules.removeAll()
}
}

enum Error: Swift.Error {
Expand Down

0 comments on commit 6730f17

Please sign in to comment.