mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-01 01:29:31 +08:00
feat(core): new worker workspace engine (#9257)
This commit is contained in:
@@ -24,6 +24,9 @@
|
||||
9D90BE2B2CCB9876006677DB /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 9D90BE1F2CCB9876006677DB /* config.xml */; };
|
||||
9D90BE2D2CCB9876006677DB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D90BE222CCB9876006677DB /* Main.storyboard */; };
|
||||
9D90BE2E2CCB9876006677DB /* public in Resources */ = {isa = PBXBuildFile; fileRef = 9D90BE232CCB9876006677DB /* public */; };
|
||||
9DEC593B2D3002E70027CEBD /* AffineHttpHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DEC593A2D3002C70027CEBD /* AffineHttpHandler.swift */; };
|
||||
9DEC593F2D30EFA40027CEBD /* AffineWsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DEC593E2D30EFA40027CEBD /* AffineWsHandler.swift */; };
|
||||
9DEC59432D323EE40027CEBD /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DEC59422D323EE00027CEBD /* Mutex.swift */; };
|
||||
9DFCD1462D27D1D70028C92B /* libaffine_mobile_native.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DFCD1452D27D1D70028C92B /* libaffine_mobile_native.a */; };
|
||||
C4C413792CBE705D00337889 /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
|
||||
C4C97C7C2D030BE000BC2AD1 /* affine_mobile_native.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4C97C6F2D0307B700BC2AD1 /* affine_mobile_native.swift */; };
|
||||
@@ -52,6 +55,9 @@
|
||||
9D90BE202CCB9876006677DB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
9D90BE212CCB9876006677DB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
9D90BE232CCB9876006677DB /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
|
||||
9DEC593A2D3002C70027CEBD /* AffineHttpHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffineHttpHandler.swift; sourceTree = "<group>"; };
|
||||
9DEC593E2D30EFA40027CEBD /* AffineWsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffineWsHandler.swift; sourceTree = "<group>"; };
|
||||
9DEC59422D323EE00027CEBD /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = "<group>"; };
|
||||
9DFCD1452D27D1D70028C92B /* libaffine_mobile_native.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libaffine_mobile_native.a; sourceTree = "<group>"; };
|
||||
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
|
||||
@@ -156,6 +162,9 @@
|
||||
9D90BE242CCB9876006677DB /* App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9DEC59422D323EE00027CEBD /* Mutex.swift */,
|
||||
9DEC593A2D3002C70027CEBD /* AffineHttpHandler.swift */,
|
||||
9DEC593E2D30EFA40027CEBD /* AffineWsHandler.swift */,
|
||||
9D52FC422D26CDB600105D0A /* JSValueContainerExt.swift */,
|
||||
9D90BE1A2CCB9876006677DB /* Plugins */,
|
||||
9D90BE1C2CCB9876006677DB /* AppDelegate.swift */,
|
||||
@@ -331,13 +340,16 @@
|
||||
9D52FC432D26CDBF00105D0A /* JSValueContainerExt.swift in Sources */,
|
||||
5075136E2D1925BC00AD60C0 /* IntelligentsPlugin.swift in Sources */,
|
||||
5075136A2D1924C600AD60C0 /* RootViewController.swift in Sources */,
|
||||
9DEC593B2D3002E70027CEBD /* AffineHttpHandler.swift in Sources */,
|
||||
C4C97C7C2D030BE000BC2AD1 /* affine_mobile_native.swift in Sources */,
|
||||
C4C97C7D2D030BE000BC2AD1 /* affine_mobile_nativeFFI.h in Sources */,
|
||||
C4C97C7E2D030BE000BC2AD1 /* affine_mobile_nativeFFI.modulemap in Sources */,
|
||||
E93B276C2CED92B1001409B8 /* NavigationGesturePlugin.swift in Sources */,
|
||||
9DEC59432D323EE40027CEBD /* Mutex.swift in Sources */,
|
||||
9D90BE252CCB9876006677DB /* CookieManager.swift in Sources */,
|
||||
9D90BE262CCB9876006677DB /* CookiePlugin.swift in Sources */,
|
||||
9D6A85332CCF6DA700DAB35F /* HashcashPlugin.swift in Sources */,
|
||||
9DEC593F2D30EFA40027CEBD /* AffineWsHandler.swift in Sources */,
|
||||
9D90BE272CCB9876006677DB /* AffineViewController.swift in Sources */,
|
||||
9D90BE282CCB9876006677DB /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// RequestUrlSchemeHandler.swift
|
||||
// App
|
||||
//
|
||||
// Created by EYHN on 2025/1/9.
|
||||
//
|
||||
|
||||
import WebKit
|
||||
|
||||
enum AffineHttpError: Error {
|
||||
case invalidOperation(reason: String), invalidState(reason: String)
|
||||
}
|
||||
|
||||
class AffineHttpHandler: NSObject, WKURLSchemeHandler {
|
||||
func webView(_ webView: WKWebView, start urlSchemeTask: any WKURLSchemeTask) {
|
||||
urlSchemeTask.stopped = Mutex.init(false)
|
||||
guard let rawUrl = urlSchemeTask.request.url else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidOperation(reason: "bad request"))
|
||||
return
|
||||
}
|
||||
guard let scheme = rawUrl.scheme else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidOperation(reason: "bad request"))
|
||||
return
|
||||
}
|
||||
let httpProtocol = scheme == "affine-http" ? "http" : "https"
|
||||
guard let urlComponents = URLComponents(url: rawUrl, resolvingAgainstBaseURL: true) else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidOperation(reason: "bad request"))
|
||||
return
|
||||
}
|
||||
guard let host = urlComponents.host else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidOperation(reason: "bad url"))
|
||||
return
|
||||
}
|
||||
let path = urlComponents.path
|
||||
let query = urlComponents.query != nil ? "?\(urlComponents.query!)" : ""
|
||||
guard let targetUrl = URL(string: "\(httpProtocol)://\(host)\(path)\(query)") else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidOperation(reason: "bad url"))
|
||||
return
|
||||
}
|
||||
|
||||
var request = URLRequest(url: targetUrl);
|
||||
request.httpMethod = urlSchemeTask.request.httpMethod;
|
||||
request.httpShouldHandleCookies = true
|
||||
request.httpBody = urlSchemeTask.request.httpBody
|
||||
urlSchemeTask.request.allHTTPHeaderFields?.filter({
|
||||
key, value in
|
||||
let normalizedKey = key.lowercased()
|
||||
return normalizedKey == "content-type" ||
|
||||
normalizedKey == "content-length" ||
|
||||
normalizedKey == "accept"
|
||||
}).forEach {
|
||||
key, value in
|
||||
request.setValue(value, forHTTPHeaderField: key)
|
||||
}
|
||||
|
||||
URLSession.shared.dataTask(with: request) {
|
||||
rawData, rawResponse, error in
|
||||
urlSchemeTask.stopped?.withLock({
|
||||
if $0 {
|
||||
return
|
||||
}
|
||||
|
||||
if error != nil {
|
||||
urlSchemeTask.didFailWithError(error!)
|
||||
} else {
|
||||
guard let httpResponse = rawResponse as? HTTPURLResponse else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidState(reason: "bad response"))
|
||||
return
|
||||
}
|
||||
let inheritedHeaders = httpResponse.allHeaderFields.filter({
|
||||
key, value in
|
||||
let normalizedKey = (key as? String)?.lowercased()
|
||||
return normalizedKey == "content-type" ||
|
||||
normalizedKey == "content-length"
|
||||
}) as? [String: String] ?? [:]
|
||||
let newHeaders: [String: String] = [
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "*"
|
||||
]
|
||||
|
||||
guard let response = HTTPURLResponse.init(url: rawUrl, statusCode: httpResponse.statusCode, httpVersion: nil, headerFields: inheritedHeaders.merging(newHeaders, uniquingKeysWith: { (_, newHeaders) in newHeaders })) else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidState(reason: "failed to create response"))
|
||||
return
|
||||
}
|
||||
|
||||
urlSchemeTask.didReceive(response)
|
||||
if rawData != nil {
|
||||
urlSchemeTask.didReceive(rawData!)
|
||||
}
|
||||
urlSchemeTask.didFinish()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
||||
urlSchemeTask.stopped?.withLock({
|
||||
$0 = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private extension WKURLSchemeTask {
|
||||
var stopped: Mutex<Bool>? {
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &stoppedKey) as? Mutex<Bool> ?? nil
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &stoppedKey, newValue, .OBJC_ASSOCIATION_ASSIGN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var stoppedKey = malloc(1)
|
||||
@@ -13,6 +13,19 @@ class AFFiNEViewController: CAPBridgeViewController {
|
||||
intelligentsButton.delegate = self
|
||||
dismissIntelligentsButton()
|
||||
}
|
||||
|
||||
override func webViewConfiguration(for instanceConfiguration: InstanceConfiguration) -> WKWebViewConfiguration {
|
||||
let configuration = super.webViewConfiguration(for: instanceConfiguration)
|
||||
return configuration
|
||||
}
|
||||
|
||||
override func webView(with frame: CGRect, configuration: WKWebViewConfiguration) -> WKWebView {
|
||||
configuration.setURLSchemeHandler(AffineHttpHandler(), forURLScheme: "affine-http")
|
||||
configuration.setURLSchemeHandler(AffineHttpHandler(), forURLScheme: "affine-https")
|
||||
configuration.setURLSchemeHandler(AffineWsHandler(), forURLScheme: "affine-ws")
|
||||
configuration.setURLSchemeHandler(AffineWsHandler(), forURLScheme: "affine-wss")
|
||||
return super.webView(with: frame, configuration: configuration)
|
||||
}
|
||||
|
||||
override func capacitorDidLoad() {
|
||||
let plugins: [CAPPlugin] = [
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// RequestUrlSchemeHandler.swift
|
||||
// App
|
||||
//
|
||||
// Created by EYHN on 2025/1/9.
|
||||
//
|
||||
|
||||
import WebKit
|
||||
|
||||
enum AffineWsError: Error {
|
||||
case invalidOperation(reason: String), invalidState(reason: String)
|
||||
}
|
||||
|
||||
/**
|
||||
this custom url scheme handler simulates websocket connection through an http request.
|
||||
frontend open websocket connections and send messages by sending requests to affine-ws:// or affine-wss://
|
||||
the handler has two endpoints:
|
||||
`affine-ws:///open?uuid={uuid}&url={wsUrl}`: open a websocket connection and return received data through the SSE protocol. If the front-end closes the http connection, the websocket connection will also be closed.
|
||||
`affine-ws:///send?uuid={uuid}`: send the request body data to the websocket connection with the specified uuid.
|
||||
*/
|
||||
class AffineWsHandler: NSObject, WKURLSchemeHandler {
|
||||
var wsTasks: [UUID: URLSessionWebSocketTask] = [:]
|
||||
func webView(_ webView: WKWebView, start urlSchemeTask: any WKURLSchemeTask) {
|
||||
urlSchemeTask.stopped = Mutex.init(false)
|
||||
guard let rawUrl = urlSchemeTask.request.url else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "bad request"))
|
||||
return
|
||||
}
|
||||
guard let urlComponents = URLComponents(url: rawUrl, resolvingAgainstBaseURL: true) else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "bad request"))
|
||||
return
|
||||
}
|
||||
let path = urlComponents.path
|
||||
if path == "/open" {
|
||||
guard let targetUrlStr = urlComponents.queryItems?.first(where: { $0.name == "url" })?.value else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "url is request"))
|
||||
return
|
||||
}
|
||||
|
||||
guard let targetUrl = URL(string: targetUrlStr) else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "failed to parse url"))
|
||||
return
|
||||
}
|
||||
|
||||
guard let uuidStr = urlComponents.queryItems?.first(where: { $0.name == "uuid" })?.value else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "url is request"))
|
||||
return
|
||||
}
|
||||
guard let uuid = UUID(uuidString: uuidStr) else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "invalid uuid"))
|
||||
return
|
||||
}
|
||||
|
||||
guard let response = HTTPURLResponse.init(url: rawUrl, statusCode: 200, httpVersion: nil, headerFields: [
|
||||
"X-Accel-Buffering": "no",
|
||||
"Content-Type": "text/event-stream",
|
||||
"Cache-Control": "no-cache",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "*"
|
||||
]) else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidState(reason: "failed to create response"))
|
||||
return
|
||||
}
|
||||
|
||||
urlSchemeTask.didReceive(response)
|
||||
let jsonEncoder = JSONEncoder()
|
||||
let json = String(data: try! jsonEncoder.encode(["type": "start"]), encoding: .utf8)!
|
||||
urlSchemeTask.didReceive("data: \(json)\n\n".data(using: .utf8)!)
|
||||
|
||||
var request = URLRequest(url: targetUrl);
|
||||
request.httpShouldHandleCookies = true
|
||||
|
||||
let webSocketTask = URLSession.shared.webSocketTask(with: targetUrl)
|
||||
self.wsTasks[uuid] = webSocketTask
|
||||
webSocketTask.resume()
|
||||
|
||||
urlSchemeTask.wsTask = webSocketTask
|
||||
|
||||
var completionHandler: ((Result<URLSessionWebSocketTask.Message, any Error>) -> Void)!
|
||||
completionHandler = {
|
||||
let result = $0
|
||||
urlSchemeTask.stopped?.withLock({
|
||||
let stopped = $0
|
||||
if stopped {
|
||||
return
|
||||
}
|
||||
let jsonEncoder = JSONEncoder()
|
||||
switch result {
|
||||
case .success(let message):
|
||||
if case .string(let string) = message {
|
||||
let json = String(data: try! jsonEncoder.encode(["type": "message", "data": string]), encoding: .utf8)!
|
||||
urlSchemeTask.didReceive("data: \(json)\n\n".data(using: .utf8)!)
|
||||
}
|
||||
case .failure(let error):
|
||||
let json = String(data: try! jsonEncoder.encode(["type": "error", "error": error.localizedDescription]), encoding: .utf8)!
|
||||
urlSchemeTask.didReceive("data: \(json)\n\n".data(using: .utf8)!)
|
||||
urlSchemeTask.didFinish()
|
||||
}
|
||||
})
|
||||
|
||||
// recursive calls
|
||||
webSocketTask.receive(completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
webSocketTask.receive(completionHandler: completionHandler)
|
||||
} else if path == "/send" {
|
||||
if urlSchemeTask.request.httpMethod != "POST" {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "Method should be POST"))
|
||||
return
|
||||
}
|
||||
guard let uuidStr = urlComponents.queryItems?.first(where: { $0.name == "uuid" })?.value else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "url is request"))
|
||||
return
|
||||
}
|
||||
guard let uuid = UUID(uuidString: uuidStr) else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "invalid uuid"))
|
||||
return
|
||||
}
|
||||
guard let ContentType = urlSchemeTask.request.allHTTPHeaderFields?.first(where: {$0.key.lowercased() == "content-type"})?.value else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "content-type is request"))
|
||||
return
|
||||
}
|
||||
if ContentType != "text/plain" {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "content-type not support"))
|
||||
return
|
||||
}
|
||||
guard let body = urlSchemeTask.request.httpBody else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "no body"))
|
||||
return
|
||||
}
|
||||
let stringBody = String(decoding: body, as: UTF8.self)
|
||||
guard let webSocketTask = self.wsTasks[uuid] else {
|
||||
urlSchemeTask.didFailWithError(AffineWsError.invalidOperation(reason: "connection not found"))
|
||||
return
|
||||
}
|
||||
|
||||
guard let response = HTTPURLResponse.init(url: rawUrl, statusCode: 200, httpVersion: nil, headerFields: [
|
||||
"Content-Type": "application/json",
|
||||
"Cache-Control": "no-cache",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "*"
|
||||
]) else {
|
||||
urlSchemeTask.didFailWithError(AffineHttpError.invalidState(reason: "failed to create response"))
|
||||
return
|
||||
}
|
||||
|
||||
let jsonEncoder = JSONEncoder()
|
||||
|
||||
webSocketTask.send(.string(stringBody), completionHandler: {
|
||||
error in
|
||||
urlSchemeTask.stopped?.withLock({
|
||||
if $0 {
|
||||
return
|
||||
}
|
||||
if error != nil {
|
||||
let json = try! jsonEncoder.encode(["error": error!.localizedDescription])
|
||||
urlSchemeTask.didReceive(response)
|
||||
urlSchemeTask.didReceive(json)
|
||||
} else {
|
||||
urlSchemeTask.didReceive(response)
|
||||
urlSchemeTask.didReceive(try! jsonEncoder.encode(["uuid": uuid.uuidString.data(using: .utf8)!]))
|
||||
urlSchemeTask.didFinish()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
||||
urlSchemeTask.stopped?.withLock({
|
||||
$0 = false
|
||||
})
|
||||
urlSchemeTask.wsTask?.cancel(with: .abnormalClosure, reason: "Closed".data(using: .utf8))
|
||||
}
|
||||
}
|
||||
|
||||
private extension WKURLSchemeTask {
|
||||
var stopped: Mutex<Bool>? {
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &stoppedKey) as? Mutex<Bool> ?? nil
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &stoppedKey, newValue, .OBJC_ASSOCIATION_ASSIGN)
|
||||
}
|
||||
}
|
||||
var wsTask: URLSessionWebSocketTask? {
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &wsTaskKey) as? URLSessionWebSocketTask
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &stoppedKey, newValue, .OBJC_ASSOCIATION_ASSIGN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var stoppedKey = malloc(1)
|
||||
private var wsTaskKey = malloc(1)
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Mutex.swift
|
||||
// App
|
||||
//
|
||||
// Created by EYHN on 2025/1/11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class Mutex<Wrapped>: @unchecked Sendable {
|
||||
private let lock = NSLock.init()
|
||||
private var wrapped: Wrapped
|
||||
|
||||
init(_ wrapped: Wrapped) {
|
||||
self.wrapped = wrapped
|
||||
}
|
||||
|
||||
func withLock<R>(_ body: @Sendable (inout Wrapped) throws -> R) rethrows -> R {
|
||||
self.lock.lock()
|
||||
defer { self.lock.unlock() }
|
||||
return try body(&wrapped)
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ public class NbStorePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
CAPPluginMethod(name: "getPeerPulledRemoteClocks", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getPeerPulledRemoteClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setPeerPulledRemoteClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getPeerPushedClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getPeerPushedClocks", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "setPeerPushedClock", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "clearClocks", returnType: CAPPluginReturnPromise),
|
||||
@@ -334,11 +335,14 @@ public class NbStorePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
let peer = try call.getStringEnsure("peer")
|
||||
let docId = try call.getStringEnsure("docId")
|
||||
|
||||
let clock = try await docStoragePool.getPeerRemoteClock(universalId: id, peer: peer, docId: docId)
|
||||
call.resolve([
|
||||
"docId": clock.docId,
|
||||
"timestamp": clock.timestamp,
|
||||
])
|
||||
if let clock = try await docStoragePool.getPeerRemoteClock(universalId: id, peer: peer, docId: docId) {
|
||||
call.resolve([
|
||||
"docId": clock.docId,
|
||||
"timestamp": clock.timestamp,
|
||||
])
|
||||
} else {
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
} catch {
|
||||
call.reject("Failed to get peer remote clock, \(error)", nil, error)
|
||||
@@ -391,11 +395,14 @@ public class NbStorePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
let peer = try call.getStringEnsure("peer")
|
||||
let docId = try call.getStringEnsure("docId")
|
||||
|
||||
let clock = try await docStoragePool.getPeerPulledRemoteClock(universalId: id, peer: peer, docId: docId)
|
||||
call.resolve([
|
||||
"docId": clock.docId,
|
||||
"timestamp": clock.timestamp,
|
||||
])
|
||||
if let clock = try await docStoragePool.getPeerPulledRemoteClock(universalId: id, peer: peer, docId: docId) {
|
||||
call.resolve([
|
||||
"docId": clock.docId,
|
||||
"timestamp": clock.timestamp,
|
||||
])
|
||||
} else {
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
} catch {
|
||||
call.reject("Failed to get peer pulled remote clock, \(error)", nil, error)
|
||||
@@ -424,6 +431,26 @@ public class NbStorePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getPeerPushedClock(_ call: CAPPluginCall) {
|
||||
Task {
|
||||
do {
|
||||
let id = try call.getStringEnsure("id")
|
||||
let peer = try call.getStringEnsure("peer")
|
||||
let docId = try call.getStringEnsure("docId")
|
||||
if let clock = try await docStoragePool.getPeerPushedClock(universalId: id, peer: peer, docId: docId) {
|
||||
call.resolve([
|
||||
"docId": clock.docId,
|
||||
"timestamp": clock.timestamp,
|
||||
])
|
||||
} else {
|
||||
call.resolve()
|
||||
}
|
||||
} catch {
|
||||
call.reject("Failed to get peer pushed clock, \(error)", nil, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getPeerPushedClocks(_ call: CAPPluginCall) {
|
||||
Task {
|
||||
do {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// SafeWKURLSchemeTask.swift
|
||||
// App
|
||||
//
|
||||
// Created by EYHN on 2025/1/11.
|
||||
//
|
||||
|
||||
import WebKit
|
||||
|
||||
class SafeWKURLSchemeTask: WKURLSchemeTask, NSObject {
|
||||
var origin: any WKURLSchemeTask
|
||||
init(origin: any WKURLSchemeTask) {
|
||||
self.origin = origin
|
||||
self.request = origin.request
|
||||
}
|
||||
|
||||
var request: URLRequest
|
||||
|
||||
func didReceive(_ response: URLResponse) {
|
||||
<#code#>
|
||||
}
|
||||
|
||||
func didReceive(_ data: Data) {
|
||||
self.origin.didReceive(<#T##response: URLResponse##URLResponse#>)
|
||||
}
|
||||
|
||||
func didFinish() {
|
||||
self.origin.didFinish()
|
||||
}
|
||||
|
||||
func didFailWithError(_ error: any Error) {
|
||||
self.origin.didFailWithError(error)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -321,6 +321,11 @@ uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_pulled_re
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_pulled_remote_clocks(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCK
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_pushed_clock(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer, RustBuffer doc_id
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCKS
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_FN_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCKS
|
||||
uint64_t uniffi_affine_mobile_native_fn_method_docstoragepool_get_peer_pushed_clocks(void*_Nonnull ptr, RustBuffer universal_id, RustBuffer peer
|
||||
@@ -759,6 +764,12 @@ uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_peer_pul
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PULLED_REMOTE_CLOCKS
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_peer_pulled_remote_clocks(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCK
|
||||
#define UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCK
|
||||
uint16_t uniffi_affine_mobile_native_checksum_method_docstoragepool_get_peer_pushed_clock(void
|
||||
|
||||
);
|
||||
#endif
|
||||
#ifndef UNIFFI_FFIDEF_UNIFFI_AFFINE_MOBILE_NATIVE_CHECKSUM_METHOD_DOCSTORAGEPOOL_GET_PEER_PUSHED_CLOCKS
|
||||
|
||||
Reference in New Issue
Block a user