|
1 | | -import SuggestionModel |
2 | 1 | import Foundation |
| 2 | +import SuggestionModel |
3 | 3 |
|
4 | 4 | @objc(XPCServiceProtocol) |
5 | 5 | public protocol XPCServiceProtocol { |
@@ -55,5 +55,96 @@ public protocol XPCServiceProtocol { |
55 | 55 | func getXPCServiceVersion(withReply reply: @escaping (String, String) -> Void) |
56 | 56 | func getXPCServiceAccessibilityPermission(withReply reply: @escaping (Bool) -> Void) |
57 | 57 | func postNotification(name: String, withReply reply: @escaping () -> Void) |
58 | | - func performAction(name: String, arguments: String, withReply reply: @escaping (String) -> Void) |
| 58 | + func send(endpoint: String, requestBody: Data, reply: @escaping (Data?, Error?) -> Void) |
| 59 | +} |
| 60 | + |
| 61 | +public struct NoResponse: Codable { |
| 62 | + public static let none = NoResponse() |
| 63 | +} |
| 64 | + |
| 65 | +public protocol ExtensionServiceRequestType: Codable { |
| 66 | + associatedtype ResponseBody: Codable |
| 67 | + static var endpoint: String { get } |
| 68 | +} |
| 69 | + |
| 70 | +public enum ExtensionServiceRequests { |
| 71 | + public struct OpenExtensionManager: ExtensionServiceRequestType { |
| 72 | + public typealias ResponseBody = NoResponse |
| 73 | + public static let endpoint = "OpenExtensionManager" |
| 74 | + |
| 75 | + public init() {} |
| 76 | + } |
| 77 | + |
| 78 | + public struct GetExtensionSuggestionServices: ExtensionServiceRequestType { |
| 79 | + public struct ServiceInfo: Codable { |
| 80 | + public var bundleIdentifier: String |
| 81 | + public var name: String |
| 82 | + } |
| 83 | + |
| 84 | + public typealias ResponseBody = [ServiceInfo] |
| 85 | + public static let endpoint = "GetExtensionSuggestionServices" |
| 86 | + |
| 87 | + public init() {} |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +public struct XPCRequestHandlerHitError: Error, LocalizedError { |
| 92 | + public var errorDescription: String? { |
| 93 | + "This is not an actual error, it just indicates a request handler was hit, and no more check is needed." |
| 94 | + } |
| 95 | + |
| 96 | + public init() {} |
59 | 97 | } |
| 98 | + |
| 99 | +public struct XPCRequestNotHandledError: Error, LocalizedError { |
| 100 | + public var errorDescription: String? { |
| 101 | + "The request was not handled by the XPC server." |
| 102 | + } |
| 103 | + |
| 104 | + public init() {} |
| 105 | +} |
| 106 | + |
| 107 | +extension ExtensionServiceRequestType { |
| 108 | + /// A helper method to handle requests. |
| 109 | + static func _handle<Request: Codable, Response: Codable>( |
| 110 | + endpoint: String, |
| 111 | + requestBody data: Data, |
| 112 | + reply: @escaping (Data?, Error?) -> Void, |
| 113 | + handler: @escaping (Request) async throws -> Response |
| 114 | + ) throws { |
| 115 | + guard endpoint == Self.endpoint else { |
| 116 | + return |
| 117 | + } |
| 118 | + do { |
| 119 | + let requestBody = try JSONDecoder().decode(Request.self, from: data) |
| 120 | + Task { |
| 121 | + do { |
| 122 | + let responseBody = try await handler(requestBody) |
| 123 | + let responseBodyData = try JSONEncoder().encode(responseBody) |
| 124 | + reply(responseBodyData, nil) |
| 125 | + } catch { |
| 126 | + reply(nil, error) |
| 127 | + } |
| 128 | + } |
| 129 | + } catch { |
| 130 | + reply(nil, error) |
| 131 | + } |
| 132 | + throw XPCRequestHandlerHitError() |
| 133 | + } |
| 134 | + |
| 135 | + public static func handle( |
| 136 | + endpoint: String, |
| 137 | + requestBody data: Data, |
| 138 | + reply: @escaping (Data?, Error?) -> Void, |
| 139 | + handler: @escaping (Self) async throws -> Self.ResponseBody |
| 140 | + ) throws { |
| 141 | + try _handle( |
| 142 | + endpoint: endpoint, |
| 143 | + requestBody: data, |
| 144 | + reply: reply |
| 145 | + ) { (request: Self) async throws -> Self.ResponseBody in |
| 146 | + try await handler(request) |
| 147 | + } |
| 148 | + } |
| 149 | +} |
| 150 | + |
0 commit comments