Skip to content

Commit ec10b0e

Browse files
committed
Tie rust and Swift side together
1 parent a6f24fb commit ec10b0e

File tree

15 files changed

+152
-37
lines changed

15 files changed

+152
-37
lines changed

ios/MullvadMockData/MullvadREST/APIProxy+Stubs.swift

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ struct APIProxyStub: APIQuerying {
1919
AnyCancellable()
2020
}
2121

22+
func mullvadApiGetRelayList(
23+
retryStrategy: REST.RetryStrategy,
24+
etag: String?,
25+
completionHandler: @escaping ProxyCompletionHandler<REST.ServerRelaysCacheResponse>)
26+
-> Cancellable {
27+
AnyCancellable()
28+
}
29+
2230
func getAddressList(
2331
retryStrategy: REST.RetryStrategy,
2432
completionHandler: @escaping ProxyCompletionHandler<[AnyIPEndpoint]>

ios/MullvadREST/ApiHandlers/RESTAPIProxy.swift

+55-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ public protocol APIQuerying: Sendable {
1818
completionHandler: @escaping @Sendable ProxyCompletionHandler<[AnyIPEndpoint]>
1919
) -> Cancellable
2020

21+
func mullvadApiGetRelayList(
22+
retryStrategy: REST.RetryStrategy,
23+
etag: String?,
24+
completionHandler: @escaping @Sendable ProxyCompletionHandler<REST.ServerRelaysCacheResponse>
25+
) -> Cancellable
26+
2127
func getAddressList(
2228
retryStrategy: REST.RetryStrategy,
2329
completionHandler: @escaping @Sendable ProxyCompletionHandler<[AnyIPEndpoint]>
@@ -71,10 +77,56 @@ extension REST {
7177
with: responseDecoder
7278
)
7379

80+
return createNetworkOperation(
81+
request: .getAddressList(retryStrategy),
82+
responseHandler: responseHandler,
83+
completionHandler: completionHandler
84+
)
85+
}
86+
87+
public func mullvadApiGetRelayList(
88+
retryStrategy: REST.RetryStrategy,
89+
etag: String?,
90+
completionHandler: @escaping @Sendable ProxyCompletionHandler<REST.ServerRelaysCacheResponse>
91+
) -> Cancellable {
92+
if var etag {
93+
// Enforce weak validator to account for some backend caching quirks.
94+
if etag.starts(with: "\"") {
95+
etag.insert(contentsOf: "W/", at: etag.startIndex)
96+
}
97+
}
98+
99+
let responseHandler = rustCustomResponseHandler { [weak self] (data, responseEtag) in
100+
// Discarding result since we're only interested in knowing that it's parseable.
101+
let canDecodeResponse = (try? self?.responseDecoder.decode(REST.ServerRelaysResponse.self, from: data)) != nil
102+
103+
return if canDecodeResponse {
104+
if let responseEtag, responseEtag == etag {
105+
REST.ServerRelaysCacheResponse.notModified
106+
} else {
107+
REST.ServerRelaysCacheResponse.newContent(responseEtag, data)
108+
}
109+
} else {
110+
nil
111+
}
112+
}
113+
114+
return createNetworkOperation(
115+
request: .getRelayList(retryStrategy, etag: etag),
116+
responseHandler: responseHandler,
117+
completionHandler: completionHandler
118+
)
119+
}
120+
121+
private func createNetworkOperation<Success: Decodable>(
122+
request: APIRequest,
123+
responseHandler: RustResponseHandler<Success>,
124+
completionHandler: @escaping @Sendable ProxyCompletionHandler<Success>
125+
) -> MullvadApiNetworkOperation<Success> {
74126
let networkOperation = MullvadApiNetworkOperation(
75-
name: "get-api-addrs",
127+
name: request.name,
76128
dispatchQueue: dispatchQueue,
77-
request: .getAddressList(retryStrategy),
129+
request: request,
78130
transportProvider: configuration.apiTransportProvider,
79131
responseDecoder: responseDecoder,
80132
responseHandler: responseHandler,
@@ -314,7 +366,7 @@ extension REST {
314366

315367
// MARK: - Response types
316368

317-
public enum ServerRelaysCacheResponse: Sendable {
369+
public enum ServerRelaysCacheResponse: Sendable, Decodable {
318370
case notModified
319371
case newContent(_ etag: String?, _ rawData: Data)
320372
}

ios/MullvadREST/ApiHandlers/RESTResponseHandler.swift

+22-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ protocol RESTResponseHandler<Success> {
1919
protocol RESTRustResponseHandler<Success> {
2020
associatedtype Success
2121

22-
func handleResponse(_ body: Data?) -> REST.ResponseHandlerResult<Success>
22+
func handleResponse(_ resonse: ProxyAPIResponse) -> REST.ResponseHandlerResult<Success>
2323
}
2424

2525
extension REST {
@@ -76,16 +76,16 @@ extension REST {
7676
}
7777

7878
final class RustResponseHandler<Success>: RESTRustResponseHandler {
79-
typealias HandlerBlock = (Data?) -> REST.ResponseHandlerResult<Success>
79+
typealias HandlerBlock = (ProxyAPIResponse) -> REST.ResponseHandlerResult<Success>
8080

8181
private let handlerBlock: HandlerBlock
8282

8383
init(_ block: @escaping HandlerBlock) {
8484
handlerBlock = block
8585
}
8686

87-
func handleResponse(_ body: Data?) -> REST.ResponseHandlerResult<Success> {
88-
handlerBlock(body)
87+
func handleResponse(_ response: ProxyAPIResponse) -> REST.ResponseHandlerResult<Success> {
88+
handlerBlock(response)
8989
}
9090
}
9191

@@ -96,8 +96,8 @@ extension REST {
9696
decoding type: T.Type,
9797
with decoder: JSONDecoder
9898
) -> RustResponseHandler<T> {
99-
RustResponseHandler { data in
100-
guard let data else {
99+
RustResponseHandler { (response: ProxyAPIResponse) in
100+
guard let data = response.data else {
101101
return .unhandledResponse(nil)
102102
}
103103

@@ -109,6 +109,22 @@ extension REST {
109109
}
110110
}
111111

112+
static func rustCustomResponseHandler<T: Decodable>(
113+
conversion: @escaping (_ data: Data, _ etag: String?) -> T?
114+
) -> RustResponseHandler<T> {
115+
RustResponseHandler { (response: ProxyAPIResponse) in
116+
guard let data = response.data else {
117+
return .unhandledResponse(nil)
118+
}
119+
120+
return if let convertedResponse = conversion(data, response.etag) {
121+
.decoding { convertedResponse }
122+
} else {
123+
.unhandledResponse(nil)
124+
}
125+
}
126+
}
127+
112128
/// Response handler for reponses where the body is empty.
113129
static func rustEmptyResponseHandler() -> RustResponseHandler<Void> {
114130
RustResponseHandler { _ in

ios/MullvadREST/APIRequest/APIRequest.swift ios/MullvadREST/MullvadAPI/APIRequest/APIRequest.swift

+15-3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,21 @@
88

99
public enum APIRequest: Codable, Sendable {
1010
case getAddressList(_ retryStrategy: REST.RetryStrategy)
11+
case getRelayList(_ retryStrategy: REST.RetryStrategy, etag: String?)
12+
13+
var name: String {
14+
switch self {
15+
case .getAddressList:
16+
"get-address-list"
17+
case .getRelayList:
18+
"get-relay-lisy"
19+
}
20+
}
1121

1222
var retryStrategy: REST.RetryStrategy {
1323
switch self {
14-
case let .getAddressList(strategy):
15-
return strategy
24+
case .getAddressList(let strategy), .getRelayList(let strategy, _):
25+
strategy
1626
}
1727
}
1828
}
@@ -30,9 +40,11 @@ public struct ProxyAPIRequest: Codable, Sendable {
3040
public struct ProxyAPIResponse: Codable, Sendable {
3141
public let data: Data?
3242
public let error: APIError?
43+
public let etag: String?
3344

34-
public init(data: Data?, error: APIError?) {
45+
public init(data: Data?, error: APIError?, etag: String? = nil) {
3546
self.data = data
3647
self.error = error
48+
self.etag = etag
3749
}
3850
}

ios/MullvadREST/ApiHandlers/MullvadApiNetworkOperation.swift ios/MullvadREST/MullvadAPI/MullvadApiNetworkOperation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ extension REST {
7878
return
7979
}
8080

81-
let decodedResponse = responseHandler.handleResponse(response.data)
81+
let decodedResponse = responseHandler.handleResponse(response)
8282

8383
switch decodedResponse {
8484
case let .success(value):

ios/MullvadREST/ApiHandlers/MullvadApiRequestFactory.swift ios/MullvadREST/MullvadAPI/MullvadApiRequestFactory.swift

+11-3
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,27 @@ public struct MullvadApiRequestFactory: Sendable {
1818

1919
public func makeRequest(_ request: APIRequest) -> REST.MullvadApiRequestHandler {
2020
{ completion in
21-
let pointerClass = MullvadApiCompletion { apiResponse in
21+
let completionPointer = MullvadApiCompletion { apiResponse in
2222
try? completion?(apiResponse)
2323
}
2424

25-
let rawPointer = Unmanaged.passRetained(pointerClass).toOpaque()
25+
let rawCompletionPointer = Unmanaged.passRetained(completionPointer).toOpaque()
2626

2727
return switch request {
2828
case let .getAddressList(retryStrategy):
2929
MullvadApiCancellable(handle: mullvad_api_get_addresses(
3030
apiContext.context,
31-
rawPointer,
31+
rawCompletionPointer,
3232
retryStrategy.toRustStrategy()
3333
))
34+
35+
case let .getRelayList(retryStrategy, etag: etag):
36+
MullvadApiCancellable(handle: mullvad_api_get_relays(
37+
apiContext.context,
38+
rawCompletionPointer,
39+
retryStrategy.toRustStrategy(),
40+
etag
41+
))
3442
}
3543
}
3644
}

ios/MullvadREST/Transport/APITransport.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ public final class APITransport: APITransportProtocol {
4444

4545
completion(ProxyAPIResponse(
4646
data: response.body,
47-
error: error
47+
error: error,
48+
etag: response.etag
4849
))
4950
}
5051
}

ios/MullvadRustRuntime/MullvadApiResponse.swift

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ public class MullvadApiResponse {
2525
return Data(UnsafeBufferPointer(start: body, count: Int(response.body_size)))
2626
}
2727

28+
public var etag: String? {
29+
return if response.etag == nil {
30+
nil
31+
} else {
32+
String(cString: response.etag)
33+
}
34+
}
35+
2836
public var errorDescription: String? {
2937
return if response.error_description == nil {
3038
nil

ios/MullvadRustRuntime/include/mullvad_rust_runtime.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ typedef struct EncryptedDnsProxyState EncryptedDnsProxyState;
2424

2525
typedef struct ExchangeCancelToken ExchangeCancelToken;
2626

27-
typedef struct Option______u8 Option______u8;
28-
2927
typedef struct RequestCancelHandle RequestCancelHandle;
3028

3129
typedef struct RetryStrategy RetryStrategy;
@@ -119,7 +117,7 @@ struct SwiftCancelHandle mullvad_api_get_addresses(struct SwiftApiContext api_co
119117
struct SwiftCancelHandle mullvad_api_get_relays(struct SwiftApiContext api_context,
120118
void *completion_cookie,
121119
struct SwiftRetryStrategy retry_strategy,
122-
struct Option______u8 etag);
120+
const uint8_t *etag);
123121

124122
/**
125123
* Called by the Swift side to signal that a Mullvad API call should be cancelled.

ios/MullvadVPN.xcodeproj/project.pbxproj

+11-3
Original file line numberDiff line numberDiff line change
@@ -2677,8 +2677,8 @@
26772677
06799ABD28F98E1D00ACD94E /* MullvadREST */ = {
26782678
isa = PBXGroup;
26792679
children = (
2680+
7A2C0E872D82E450003D8048 /* MullvadAPI */,
26802681
F06045F02B2324DA00B2D37A /* ApiHandlers */,
2681-
7A2E7B6B2D6C9E45009EF2C3 /* APIRequest */,
26822682
062B45A228FD4C0F00746E77 /* Assets */,
26832683
7AD63A422CDA661B00445268 /* Extensions */,
26842684
582FFA82290A84E700895745 /* Info.plist */,
@@ -4156,6 +4156,16 @@
41564156
path = Alert;
41574157
sourceTree = "<group>";
41584158
};
4159+
7A2C0E872D82E450003D8048 /* MullvadAPI */ = {
4160+
isa = PBXGroup;
4161+
children = (
4162+
7A2E7B6B2D6C9E45009EF2C3 /* APIRequest */,
4163+
7AB9312D2D4A5D0A005FCEBA /* MullvadApiNetworkOperation.swift */,
4164+
7A99D36E2D5606F900891FF7 /* MullvadApiRequestFactory.swift */,
4165+
);
4166+
path = MullvadAPI;
4167+
sourceTree = "<group>";
4168+
};
41594169
7A2E7B6B2D6C9E45009EF2C3 /* APIRequest */ = {
41604170
isa = PBXGroup;
41614171
children = (
@@ -4535,7 +4545,6 @@
45354545
06AC114128F8413A0037AF9A /* AddressCache.swift */,
45364546
A935594B2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift */,
45374547
06FAE67128F83CA40033DD93 /* HTTP.swift */,
4538-
7AB9312D2D4A5D0A005FCEBA /* MullvadApiNetworkOperation.swift */,
45394548
06FAE67228F83CA40033DD93 /* RESTAccessTokenManager.swift */,
45404549
06FAE66828F83CA30033DD93 /* RESTAccountsProxy.swift */,
45414550
06FAE67328F83CA40033DD93 /* RESTAPIProxy.swift */,
@@ -4554,7 +4563,6 @@
45544563
06FAE66628F83CA30033DD93 /* RESTResponseHandler.swift */,
45554564
06FAE67528F83CA40033DD93 /* RESTTaskIdentifier.swift */,
45564565
06FAE66528F83CA30033DD93 /* RESTURLSession.swift */,
4557-
7A99D36E2D5606F900891FF7 /* MullvadApiRequestFactory.swift */,
45584566
06FAE67728F83CA40033DD93 /* ServerRelaysResponse.swift */,
45594567
06FAE66B28F83CA30033DD93 /* SSLPinningURLSessionDelegate.swift */,
45604568
);

ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift

+7-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ protocol RelayCacheTrackerProtocol: Sendable {
2626

2727
final class RelayCacheTracker: RelayCacheTrackerProtocol, @unchecked Sendable {
2828
/// Relay update interval.
29-
static let relayUpdateInterval: Duration = .hours(1)
29+
static let relayUpdateInterval: Duration = .seconds(30)
3030

3131
/// Tracker log.
3232
nonisolated(unsafe) private let logger = Logger(label: "RelayCacheTracker")
@@ -174,9 +174,14 @@ final class RelayCacheTracker: RelayCacheTrackerProtocol, @unchecked Sendable {
174174
return AnyCancellable()
175175
}
176176

177-
return self.apiProxy.getRelays(etag: cachedRelays?.etag, retryStrategy: .noRetry) { result in
177+
return self.apiProxy.getRelays(etag: "hello", retryStrategy: .noRetry) { result in
178+
print(result)
178179
finish(self.handleResponse(result: result))
179180
}
181+
182+
// return self.apiProxy.mullvadApiGetRelayList(retryStrategy: .noRetry, etag: cachedRelays.etag) { result in
183+
// finish(self.handleResponse(result: result))
184+
// }
180185
}
181186

182187
operation.addObserver(

mullvad-api/src/relay_list.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
33
use crate::rest;
44

5-
use hyper::{body::Incoming, header, Error, StatusCode};
5+
use hyper::{body::Incoming, header, StatusCode};
66
use mullvad_types::{location, relay_list};
77
use talpid_types::net::wireguard;
88

99
use std::{
1010
collections::BTreeMap,
11-
future::Future,
1211
net::{IpAddr, Ipv4Addr, Ipv6Addr},
1312
ops::RangeInclusive,
1413
time::Duration,

0 commit comments

Comments
 (0)