diff options
| author | sajacl <sajaclvishkai@gmail.com> | 2022-10-21 13:27:05 +0200 |
|---|---|---|
| committer | sajacl <sajaclvishkai@gmail.com> | 2022-10-21 15:16:32 +0200 |
| commit | 8ad5803493f26eefaa4d2e72980919e3b7233cd7 (patch) | |
| tree | f543cabaa48d6e942b79500d0129d9606484f713 | |
| parent | d3ef8d298dbd3ceee5bc2dfbe0c25d610e664c5f (diff) | |
| download | mullvadvpn-8ad5803493f26eefaa4d2e72980919e3b7233cd7.tar.xz mullvadvpn-8ad5803493f26eefaa4d2e72980919e3b7233cd7.zip | |
Move RelayCache.IO and CachedRelays into new RelayCache.framework
Moved RelayCache.IO and CachedRelays into new RelayCache.framework
Moved prebuild script to build phase script.
Renamed script, renamed/moved RelayCache.IO to RelayCache.
Renamed RelayCache.Tracker to RelayCacheTracker.
Set APPLICATION_EXTENSION_API_ONLY to true for RelayCache framework.
Updated gitignore.
Removed relays.json from git.
Removed relays.json from RelayCache framework
Removed RelayCache/FetchResult, moved/renamed code into RelayCacheTracker file.
Renamed CachedRelaysFetchResult to RelaysFetchResult.
Changed access level for RelaysFetchResult and NoCachedRelaysError.
18 files changed, 535 insertions, 330 deletions
diff --git a/ios/.gitignore b/ios/.gitignore index 061879af51..bb4d979639 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -3,7 +3,7 @@ # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Generated assets -Assets/relays.json +RelayCache/Assets/relays.json MullvadREST/Assets/api-ip-address.json ## Build generated diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 7acd1abd75..0d86521498 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -18,6 +18,13 @@ 063F026628FFE11C001FA09F /* RESTCreateApplePaymentResponse+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06FAE67828F83CA50033DD93 /* RESTCreateApplePaymentResponse+Localization.swift */; }; 063F026729002768001FA09F /* Cancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06AC113628F83FD70037AF9A /* Cancellable.swift */; }; 063F026A29002E44001FA09F /* IPv4Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58561C98239A5D1500BD6B5E /* IPv4Endpoint.swift */; }; + 063F02762902B63F001FA09F /* RelayCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 063F02752902B63F001FA09F /* RelayCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 063F02792902B63F001FA09F /* RelayCache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 063F02732902B63F001FA09F /* RelayCache.framework */; }; + 063F027A2902B63F001FA09F /* RelayCache.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 063F02732902B63F001FA09F /* RelayCache.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 063F027E2902B6EB001FA09F /* RelayCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820675A26E6576800655B05 /* RelayCache.swift */; }; + 063F027F2902B6EB001FA09F /* CachedRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA87626B024A600B8C587 /* CachedRelays.swift */; }; + 063F028A2902B7B2001FA09F /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = 063F02892902B7B2001FA09F /* WireGuardKitTypes */; }; + 063F028F2902BD8C001FA09F /* relays.json in Resources */ = {isa = PBXBuildFile; fileRef = 58F3C0A524A50155003E76BE /* relays.json */; }; 06799ACE28F98E1D00ACD94E /* MullvadREST.h in Headers */ = {isa = PBXBuildFile; fileRef = 06799ABE28F98E1D00ACD94E /* MullvadREST.h */; settings = {ATTRIBUTES = (Public, ); }; }; 06799AD128F98E1D00ACD94E /* MullvadREST.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */; }; 06799AD228F98E1D00ACD94E /* MullvadREST.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -88,9 +95,6 @@ 5819C2142726CC8D00D6EC38 /* DataSourceSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5819C2132726CC8D00D6EC38 /* DataSourceSnapshotTests.swift */; }; 5819C2152726CC9400D6EC38 /* DataSourceSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587EB66F27143B6500123C75 /* DataSourceSnapshot.swift */; }; 5819C2172729595500D6EC38 /* SettingsAddDNSEntryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5819C2162729595500D6EC38 /* SettingsAddDNSEntryCell.swift */; }; - 5820675826E652AF00655B05 /* RelayCacheIO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA87C26B0254000B8C587 /* RelayCacheIO.swift */; }; - 5820675B26E6576800655B05 /* RelayCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820675A26E6576800655B05 /* RelayCache.swift */; }; - 5820675C26E6576800655B05 /* RelayCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820675A26E6576800655B05 /* RelayCache.swift */; }; 5820676426E771DB00655B05 /* TunnelManagerErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820676326E771DB00655B05 /* TunnelManagerErrors.swift */; }; 5820EDA9288FE064006BF4E4 /* DeviceManagementInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820EDA8288FE064006BF4E4 /* DeviceManagementInteractor.swift */; }; 5820EDAB288FF0D2006BF4E4 /* DeviceRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5820EDAA288FF0D2006BF4E4 /* DeviceRowView.swift */; }; @@ -133,9 +137,6 @@ 585B4B8726D9098900555C4C /* TunnelStatusNotificationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A94AE326CFD945001CB97C /* TunnelStatusNotificationProvider.swift */; }; 585C6F4C28F80745005196BE /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = 585C6F4B28F80745005196BE /* Logging */; }; 585CA70F25F8C44600B47C62 /* UIMetrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585CA70E25F8C44600B47C62 /* UIMetrics.swift */; }; - 585DA87726B024A600B8C587 /* CachedRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA87626B024A600B8C587 /* CachedRelays.swift */; }; - 585DA87826B024A900B8C587 /* CachedRelays.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA87626B024A600B8C587 /* CachedRelays.swift */; }; - 585DA87D26B0254000B8C587 /* RelayCacheIO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA87C26B0254000B8C587 /* RelayCacheIO.swift */; }; 585DA89326B0323E00B8C587 /* TunnelProviderMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA89226B0323E00B8C587 /* TunnelProviderMessage.swift */; }; 585DA89426B0323E00B8C587 /* TunnelProviderMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA89226B0323E00B8C587 /* TunnelProviderMessage.swift */; }; 585DA89926B0329200B8C587 /* PacketTunnelStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 585DA89826B0329200B8C587 /* PacketTunnelStatus.swift */; }; @@ -284,8 +285,6 @@ 58F2E148276A307400A79513 /* MapConnectionStatusOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2E147276A307400A79513 /* MapConnectionStatusOperation.swift */; }; 58F2E14C276A61C000A79513 /* RotateKeyOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2E14B276A61C000A79513 /* RotateKeyOperation.swift */; }; 58F3C0A4249CB069003E76BE /* HeaderBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F3C0A3249CB069003E76BE /* HeaderBarView.swift */; }; - 58F3C0A624A50157003E76BE /* relays.json in Resources */ = {isa = PBXBuildFile; fileRef = 58F3C0A524A50155003E76BE /* relays.json */; }; - 58F3C0A724A50C02003E76BE /* relays.json in Resources */ = {isa = PBXBuildFile; fileRef = 58F3C0A524A50155003E76BE /* relays.json */; }; 58F7CA882692E34000FC59FD /* WireguardKeysContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */; }; 58F8AC0E25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */; }; 58FB865526E8BF3100F188BC /* AppStorePaymentManagerError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FB865426E8BF3100F188BC /* AppStorePaymentManagerError.swift */; }; @@ -329,6 +328,27 @@ remoteGlobalIDString = 581943F028F8014500B0CB5E; remoteInfo = MullvadTypes; }; + 063F02772902B63F001FA09F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 58CE5E58224146200008646E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 063F02722902B63F001FA09F; + remoteInfo = RelayCache; + }; + 063F02812902B6F8001FA09F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 58CE5E58224146200008646E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 06799ABB28F98E1D00ACD94E; + remoteInfo = MullvadREST; + }; + 063F028B2902B83C001FA09F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 58CE5E58224146200008646E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 063F02722902B63F001FA09F; + remoteInfo = RelayCache; + }; 06799ACF28F98E1D00ACD94E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 58CE5E58224146200008646E /* Project object */; @@ -409,6 +429,7 @@ dstSubfolderSpec = 10; files = ( 06799AD228F98E1D00ACD94E /* MullvadREST.framework in Embed Frameworks */, + 063F027A2902B63F001FA09F /* RelayCache.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -458,6 +479,8 @@ 062B45C128FE97FF00746E77 /* api-ip-address.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "api-ip-address.json"; sourceTree = "<group>"; }; 063687AF28EB083800BE7161 /* ProxyURLRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyURLRequest.swift; sourceTree = "<group>"; }; 063687B928EB234F00BE7161 /* PacketTunnelTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelTransport.swift; sourceTree = "<group>"; }; + 063F02732902B63F001FA09F /* RelayCache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RelayCache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 063F02752902B63F001FA09F /* RelayCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RelayCache.h; sourceTree = "<group>"; }; 06799AB428F98CE700ACD94E /* le_root_cert.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = le_root_cert.cer; sourceTree = "<group>"; }; 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MullvadREST.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 06799ABE28F98E1D00ACD94E /* MullvadREST.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MullvadREST.h; sourceTree = "<group>"; }; @@ -569,7 +592,6 @@ 5857F24624C882D700CF6F47 /* SelectLocationNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectLocationNavigationController.swift; sourceTree = "<group>"; }; 585CA70E25F8C44600B47C62 /* UIMetrics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIMetrics.swift; sourceTree = "<group>"; }; 585DA87626B024A600B8C587 /* CachedRelays.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedRelays.swift; sourceTree = "<group>"; }; - 585DA87C26B0254000B8C587 /* RelayCacheIO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayCacheIO.swift; sourceTree = "<group>"; }; 585DA89226B0323E00B8C587 /* TunnelProviderMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelProviderMessage.swift; sourceTree = "<group>"; }; 585DA89826B0329200B8C587 /* PacketTunnelStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelStatus.swift; sourceTree = "<group>"; }; 585E820227F3285E00939F0E /* SendAppStoreReceiptOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendAppStoreReceiptOperation.swift; sourceTree = "<group>"; }; @@ -727,6 +749,14 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 063F02702902B63F001FA09F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 063F028A2902B7B2001FA09F /* WireGuardKitTypes in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 06799AB928F98E1D00ACD94E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -782,6 +812,7 @@ 06799AD128F98E1D00ACD94E /* MullvadREST.framework in Frameworks */, 58AC829528F803A200181C40 /* libMullvadTypes.a in Frameworks */, 5818139F28E09BD8002817DE /* libOperations.a in Frameworks */, + 063F02792902B63F001FA09F /* RelayCache.framework in Frameworks */, 5807483B27DB8A980020ECBF /* WireGuardKitTypes in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -822,6 +853,25 @@ path = Assets; sourceTree = "<group>"; }; + 063F02742902B63F001FA09F /* RelayCache */ = { + isa = PBXGroup; + children = ( + 063F028E2902BD0F001FA09F /* Assets */, + 063F02752902B63F001FA09F /* RelayCache.h */, + 585DA87626B024A600B8C587 /* CachedRelays.swift */, + 5820675A26E6576800655B05 /* RelayCache.swift */, + ); + path = RelayCache; + sourceTree = "<group>"; + }; + 063F028E2902BD0F001FA09F /* Assets */ = { + isa = PBXGroup; + children = ( + 58F3C0A524A50155003E76BE /* relays.json */, + ); + path = Assets; + sourceTree = "<group>"; + }; 06799ABD28F98E1D00ACD94E /* MullvadREST */ = { isa = PBXGroup; children = ( @@ -961,9 +1011,6 @@ 585DA87526B0249A00B8C587 /* RelayCache */ = { isa = PBXGroup; children = ( - 585DA87626B024A600B8C587 /* CachedRelays.swift */, - 5820675A26E6576800655B05 /* RelayCache.swift */, - 585DA87C26B0254000B8C587 /* RelayCacheIO.swift */, 58FB865926EA214400F188BC /* RelayCacheObserver.swift */, 58BFA5C522A7C97F00A6173D /* RelayCacheTracker.swift */, ); @@ -1036,6 +1083,7 @@ children = ( 58F3C0A824A50C0E003E76BE /* Assets */, 58ECD29023F178FD004298B6 /* Configurations */, + 063F02742902B63F001FA09F /* RelayCache */, 0E15C74FDCF763609B367486 /* Frameworks */, 582CFEE1269448160072883A /* Localizations */, 589A454A28DDF59B00565204 /* Shared */, @@ -1064,6 +1112,7 @@ 581943D628F800C900B0CB5E /* libMullvadLogging.a */, 581943F128F8014500B0CB5E /* libMullvadTypes.a */, 06799ABC28F98E1D00ACD94E /* MullvadREST.framework */, + 063F02732902B63F001FA09F /* RelayCache.framework */, ); name = Products; sourceTree = "<group>"; @@ -1277,7 +1326,6 @@ isa = PBXGroup; children = ( 587DCCEE287D84A500CE821E /* countries.geo.json */, - 58F3C0A524A50155003E76BE /* relays.json */, ); path = Assets; sourceTree = "<group>"; @@ -1285,6 +1333,14 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 063F026E2902B63F001FA09F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 063F02762902B63F001FA09F /* RelayCache.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 06799AB728F98E1D00ACD94E /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -1313,6 +1369,29 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ + 063F02722902B63F001FA09F /* RelayCache */ = { + isa = PBXNativeTarget; + buildConfigurationList = 063F027D2902B63F001FA09F /* Build configuration list for PBXNativeTarget "RelayCache" */; + buildPhases = ( + 063F028D2902BC8E001FA09F /* Run prebuild script */, + 063F026E2902B63F001FA09F /* Headers */, + 063F026F2902B63F001FA09F /* Sources */, + 063F02702902B63F001FA09F /* Frameworks */, + 063F02712902B63F001FA09F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 063F02822902B6F8001FA09F /* PBXTargetDependency */, + ); + name = RelayCache; + packageProductDependencies = ( + 063F02892902B7B2001FA09F /* WireGuardKitTypes */, + ); + productName = RelayCache; + productReference = 063F02732902B63F001FA09F /* RelayCache.framework */; + productType = "com.apple.product-type.framework"; + }; 06799ABB28F98E1D00ACD94E /* MullvadREST */ = { isa = PBXNativeTarget; buildConfigurationList = 06799AD328F98E1D00ACD94E /* Build configuration list for PBXNativeTarget "MullvadREST" */; @@ -1432,6 +1511,7 @@ 06799AD028F98E1D00ACD94E /* PBXTargetDependency */, 58E5126E28DDF09F00B0BCDE /* PBXTargetDependency */, 58CE5E80224146470008646E /* PBXTargetDependency */, + 063F02782902B63F001FA09F /* PBXTargetDependency */, ); name = MullvadVPN; packageProductDependencies = ( @@ -1453,6 +1533,7 @@ buildRules = ( ); dependencies = ( + 063F028C2902B83C001FA09F /* PBXTargetDependency */, 062B45A628FD4FD500746E77 /* PBXTargetDependency */, 58FBDAA222A52A6800EB69A3 /* PBXTargetDependency */, 06D9846528F9A049003AABE9 /* PBXTargetDependency */, @@ -1511,6 +1592,9 @@ LastUpgradeCheck = 1400; ORGANIZATIONNAME = "Mullvad VPN AB"; TargetAttributes = { + 063F02722902B63F001FA09F = { + CreatedOnToolsVersion = 14.0.1; + }; 06799ABB28F98E1D00ACD94E = { CreatedOnToolsVersion = 14.0.1; }; @@ -1587,11 +1671,20 @@ 581943D528F800C900B0CB5E /* MullvadLogging */, 581943F028F8014500B0CB5E /* MullvadTypes */, 06799ABB28F98E1D00ACD94E /* MullvadREST */, + 063F02722902B63F001FA09F /* RelayCache */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 063F02712902B63F001FA09F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 063F028F2902BD8C001FA09F /* relays.json in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 06799ABA28F98E1D00ACD94E /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1619,7 +1712,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 58F3C0A624A50157003E76BE /* relays.json in Resources */, 58727283265D173C00F315B2 /* LaunchScreen.storyboard in Resources */, 587DCCEF287D84A500CE821E /* countries.geo.json in Resources */, 58CE5E6B224146210008646E /* Assets.xcassets in Resources */, @@ -1631,7 +1723,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 58F3C0A724A50C02003E76BE /* relays.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1645,6 +1736,25 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 063F028D2902BC8E001FA09F /* Run prebuild script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Run prebuild script"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "exec > $PROJECT_DIR/relays-prebuild.log 2>&1\n\n$PROJECT_DIR/relays-prebuild.sh\n"; + }; 588E4EB028FEF1CA008046E3 /* Run prebuild script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -1667,6 +1777,15 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 063F026F2902B63F001FA09F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 063F027E2902B6EB001FA09F /* RelayCache.swift in Sources */, + 063F027F2902B6EB001FA09F /* CachedRelays.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 06799AB828F98E1D00ACD94E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1781,12 +1900,10 @@ 5857F24724C882D700CF6F47 /* SelectLocationNavigationController.swift in Sources */, 5846227126E229F20035F7C2 /* AppStoreSubscription.swift in Sources */, 58421030282D8A3C00F24E46 /* UpdateAccountDataOperation.swift in Sources */, - 5820675B26E6576800655B05 /* RelayCache.swift in Sources */, 58FF2C03281BDE02009EF542 /* SettingsManager.swift in Sources */, 587EB672271451E300123C75 /* PreferencesViewModel.swift in Sources */, 586A950C290125EE007BAF2B /* AlertPresenter.swift in Sources */, 584D26C6270C8741004EA533 /* SettingsDNSTextCell.swift in Sources */, - 585DA87D26B0254000B8C587 /* RelayCacheIO.swift in Sources */, 58F2E148276A307400A79513 /* MapConnectionStatusOperation.swift in Sources */, 58BA693123EADA6A009DC256 /* SimulatorTunnelProvider.swift in Sources */, 587C575326D2615F005EF767 /* PacketTunnelOptions.swift in Sources */, @@ -1909,7 +2026,6 @@ 063687BA28EB234F00BE7161 /* PacketTunnelTransport.swift in Sources */, 58293FB725138B88005D0BB5 /* CustomNavigationController.swift in Sources */, 587425C12299833500CA2045 /* RootContainerViewController.swift in Sources */, - 585DA87726B024A600B8C587 /* CachedRelays.swift in Sources */, 5896AE84246D5889005B36CB /* CustomDateComponentsFormatting.swift in Sources */, 587AD7C623421D7000E93A53 /* TunnelSettingsV1.swift in Sources */, 58E20771274672CA00DE5D77 /* LaunchViewController.swift in Sources */, @@ -1931,7 +2047,6 @@ buildActionMask = 2147483647; files = ( 587C575426D2615F005EF767 /* PacketTunnelOptions.swift in Sources */, - 5820675826E652AF00655B05 /* RelayCacheIO.swift in Sources */, 5806767C27048E9B00C858CB /* PacketTunnelProvider.swift in Sources */, 585DA89426B0323E00B8C587 /* TunnelProviderMessage.swift in Sources */, 587AD7C723421D8600E93A53 /* TunnelSettingsV1.swift in Sources */, @@ -1939,7 +2054,6 @@ 58CE38C828992C9200A6D6E5 /* TunnelMonitorDelegate.swift in Sources */, 58FC040A27B3EE03001C21F0 /* TunnelMonitor.swift in Sources */, 5838318B27C40A3900000571 /* Pinger.swift in Sources */, - 5820675C26E6576800655B05 /* RelayCache.swift in Sources */, 585DA89A26B0329200B8C587 /* PacketTunnelStatus.swift in Sources */, 58E0729D28814AAE008902F8 /* PacketTunnelConfiguration.swift in Sources */, 58E0729F28814ACC008902F8 /* WireGuardLogLevel+Logging.swift in Sources */, @@ -1947,7 +2061,6 @@ 5840250522B11AB700E4CFEC /* MullvadEndpoint.swift in Sources */, 58906DE02445C7A5002F0673 /* NEProviderStopReason+Debug.swift in Sources */, 580F8B872819795C002E0998 /* DNSSettings.swift in Sources */, - 585DA87826B024A900B8C587 /* CachedRelays.swift in Sources */, 58E072A128814B0E008902F8 /* MullvadEndpoint+WgEndpoint.swift in Sources */, 584E96BD240FD4DA00D3334F /* Location.swift in Sources */, 06AC116228F94C450037AF9A /* ApplicationConfiguration.swift in Sources */, @@ -2015,6 +2128,21 @@ target = 581943F028F8014500B0CB5E /* MullvadTypes */; targetProxy = 063F0268290027F8001FA09F /* PBXContainerItemProxy */; }; + 063F02782902B63F001FA09F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 063F02722902B63F001FA09F /* RelayCache */; + targetProxy = 063F02772902B63F001FA09F /* PBXContainerItemProxy */; + }; + 063F02822902B6F8001FA09F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 06799ABB28F98E1D00ACD94E /* MullvadREST */; + targetProxy = 063F02812902B6F8001FA09F /* PBXContainerItemProxy */; + }; + 063F028C2902B83C001FA09F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 063F02722902B63F001FA09F /* RelayCache */; + targetProxy = 063F028B2902B83C001FA09F /* PBXContainerItemProxy */; + }; 06799AD028F98E1D00ACD94E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 06799ABB28F98E1D00ACD94E /* MullvadREST */; @@ -2079,6 +2207,72 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 063F027B2902B63F001FA09F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Mullvad VPN AB. All rights reserved."; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.mullvad.RelayCache; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 063F027C2902B63F001FA09F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Mullvad VPN AB. All rights reserved."; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.mullvad.RelayCache; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; 06799AD428F98E1D00ACD94E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2580,6 +2774,7 @@ GCC_OPTIMIZATION_LEVEL = 0; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; + PATH = "${PATH}:/opt/homebrew/opt/go@1.19/bin"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -2591,6 +2786,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; + PATH = "${PATH}:/opt/homebrew/opt/go@1.19/bin"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -2598,6 +2794,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 063F027D2902B63F001FA09F /* Build configuration list for PBXNativeTarget "RelayCache" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 063F027B2902B63F001FA09F /* Debug */, + 063F027C2902B63F001FA09F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 06799AD328F98E1D00ACD94E /* Build configuration list for PBXNativeTarget "MullvadREST" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -2729,6 +2934,11 @@ package = 585834F624D2BC1F00A8AF56 /* XCRemoteSwiftPackageReference "swift-log" */; productName = Logging; }; + 063F02892902B7B2001FA09F /* WireGuardKitTypes */ = { + isa = XCSwiftPackageProductDependency; + package = 58BA79192578F092006FAEA0 /* XCRemoteSwiftPackageReference "wireguard-apple" */; + productName = WireGuardKitTypes; + }; 06D9844B28F990AB003AABE9 /* WireGuardKitTypes */ = { isa = XCSwiftPackageProductDependency; package = 58BA79192578F092006FAEA0 /* XCRemoteSwiftPackageReference "wireguard-apple" */; diff --git a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme index 0a251cac49..5f4b4b5a25 100644 --- a/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme +++ b/ios/MullvadVPN.xcodeproj/xcshareddata/xcschemes/MullvadVPN.xcscheme @@ -1,28 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme LastUpgradeVersion = "1400" - version = "1.7"> + version = "1.3"> <BuildAction parallelizeBuildables = "YES" buildImplicitDependencies = "YES"> - <PreActions> - <ExecutionAction - ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction"> - <ActionContent - title = "Run Script" - scriptText = "exec > $PROJECT_DIR/prebuild.log 2>&1 $PROJECT_DIR/prebuild.sh "> - <EnvironmentBuildable> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "58CE5E5F224146200008646E" - BuildableName = "MullvadVPN.app" - BlueprintName = "MullvadVPN" - ReferencedContainer = "container:MullvadVPN.xcodeproj"> - </BuildableReference> - </EnvironmentBuildable> - </ActionContent> - </ExecutionAction> - </PreActions> <BuildActionEntries> <BuildActionEntry buildForTesting = "YES" diff --git a/ios/MullvadVPN/AppDelegate.swift b/ios/MullvadVPN/AppDelegate.swift index 7ce348123c..acff5835fe 100644 --- a/ios/MullvadVPN/AppDelegate.swift +++ b/ios/MullvadVPN/AppDelegate.swift @@ -11,6 +11,7 @@ import Intents import MullvadLogging import MullvadREST import Operations +import RelayCache import StoreKit import UIKit import UserNotifications @@ -129,7 +130,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { forTaskWithIdentifier: ApplicationConfiguration.appRefreshTaskIdentifier, using: nil ) { task in - let handle = RelayCache.Tracker.shared.updateRelays { completion in + let handle = RelayCacheTracker.shared.updateRelays { completion in task.setTaskCompleted(success: completion.isSuccess) } @@ -201,7 +202,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private func scheduleAppRefreshTask() { do { - let date = RelayCache.Tracker.shared.getNextUpdateDate() + let date = RelayCacheTracker.shared.getNextUpdateDate() let request = BGAppRefreshTaskRequest( identifier: ApplicationConfiguration.appRefreshTaskIdentifier diff --git a/ios/MullvadVPN/RelayCache/CachedRelays.swift b/ios/MullvadVPN/RelayCache/CachedRelays.swift deleted file mode 100644 index 22bfaa1fdd..0000000000 --- a/ios/MullvadVPN/RelayCache/CachedRelays.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// CachedRelays.swift -// CachedRelays -// -// Created by pronebird on 27/07/2021. -// Copyright © 2021 Mullvad VPN AB. All rights reserved. -// - -import Foundation -import MullvadREST - -extension RelayCache { - /// A struct that represents the relay cache on disk - struct CachedRelays: Codable { - /// E-tag returned by server - var etag: String? - - /// The relay list stored within the cache entry - var relays: REST.ServerRelaysResponse - - /// The date when this cache was last updated - var updatedAt: Date - } -} diff --git a/ios/MullvadVPN/RelayCache/RelayCache.swift b/ios/MullvadVPN/RelayCache/RelayCache.swift deleted file mode 100644 index 6ad72e205a..0000000000 --- a/ios/MullvadVPN/RelayCache/RelayCache.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// RelayCache.swift -// RelayCache -// -// Created by pronebird on 06/09/2021. -// Copyright © 2021 Mullvad VPN AB. All rights reserved. -// - -import Foundation - -enum RelayCache {} diff --git a/ios/MullvadVPN/RelayCache/RelayCacheObserver.swift b/ios/MullvadVPN/RelayCache/RelayCacheObserver.swift index 879157bf60..4b109340f0 100644 --- a/ios/MullvadVPN/RelayCache/RelayCacheObserver.swift +++ b/ios/MullvadVPN/RelayCache/RelayCacheObserver.swift @@ -7,10 +7,11 @@ // import Foundation +import RelayCache protocol RelayCacheObserver: AnyObject { func relayCache( - _ relayCache: RelayCache.Tracker, - didUpdateCachedRelays cachedRelays: RelayCache.CachedRelays + _ relayCache: RelayCacheTracker, + didUpdateCachedRelays cachedRelays: CachedRelays ) } diff --git a/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift b/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift index 2f9d0eea1d..b003ae6868 100644 --- a/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift +++ b/ios/MullvadVPN/RelayCache/RelayCacheTracker.swift @@ -11,291 +11,290 @@ import MullvadLogging import MullvadREST import MullvadTypes import Operations +import RelayCache import UIKit -extension RelayCache { - /// Type describing the result of an attempt to fetch the new relay list from server. - enum FetchResult: CustomStringConvertible { - /// Request to update relays was throttled. - case throttled +class RelayCacheTracker { + /// Relay update interval (in seconds). + static let relayUpdateInterval: TimeInterval = 60 * 60 - /// Refreshed relays but the same content was found on remote. - case sameContent + /// Tracker log. + private let logger = Logger(label: "RelayCacheTracker") - /// Refreshed relays with new content. - case newContent + /// The cache location used by the class instance. + private let cacheFileURL: URL - var description: String { - switch self { - case .throttled: - return "throttled" - case .sameContent: - return "same content" - case .newContent: - return "new content" - } - } - } - - struct NoCachedRelaysError: LocalizedError { - var errorDescription: String? { - return "Relay cache is empty." - } - } - - class Tracker { - /// Relay update interval (in seconds). - static let relayUpdateInterval: TimeInterval = 60 * 60 - - /// Tracker log. - private let logger = Logger(label: "RelayCacheTracker") + /// The location of prebundled `relays.json`. + private let prebundledRelaysFileURL: URL - /// The cache location used by the class instance. - private let cacheFileURL: URL + /// Lock used for synchronization. + private let nslock = NSLock() - /// The location of prebundled `relays.json`. - private let prebundledRelaysFileURL: URL + /// Internal operation queue. + private let operationQueue: OperationQueue = { + let operationQueue = AsyncOperationQueue() + operationQueue.maxConcurrentOperationCount = 1 + return operationQueue + }() - /// Lock used for synchronization. - private let nslock = NSLock() + /// A timer source used for periodic updates. + private var timerSource: DispatchSourceTimer? - /// Internal operation queue. - private let operationQueue: OperationQueue = { - let operationQueue = AsyncOperationQueue() - operationQueue.maxConcurrentOperationCount = 1 - return operationQueue - }() + /// A flag that indicates whether periodic updates are running. + private var isPeriodicUpdatesEnabled = false - /// A timer source used for periodic updates. - private var timerSource: DispatchSourceTimer? + /// API proxy. + private let apiProxy = REST.ProxyFactory.shared.createAPIProxy() - /// A flag that indicates whether periodic updates are running. - private var isPeriodicUpdatesEnabled = false + /// Observers. + private let observerList = ObserverList<RelayCacheObserver>() - /// API proxy. - private let apiProxy = REST.ProxyFactory.shared.createAPIProxy() + /// Memory cache. + private var cachedRelays: CachedRelays? - /// Observers. - private let observerList = ObserverList<RelayCacheObserver>() + /// A shared instance of `RelayCache` + static let shared: RelayCacheTracker = { + let cacheFileURL = RelayCache + .defaultCacheFileURL( + forSecurityApplicationGroupIdentifier: ApplicationConfiguration + .securityGroupIdentifier + )! + let prebundledRelaysFileURL = RelayCache.preBundledRelaysFileURL! - /// Memory cache. - private var cachedRelays: CachedRelays? + return RelayCacheTracker( + cacheFileURL: cacheFileURL, + prebundledRelaysFileURL: prebundledRelaysFileURL + ) + }() - /// A shared instance of `RelayCache` - static let shared: RelayCache.Tracker = { - let cacheFileURL = RelayCache.IO - .defaultCacheFileURL( - forSecurityApplicationGroupIdentifier: ApplicationConfiguration - .securityGroupIdentifier - )! - let prebundledRelaysFileURL = RelayCache.IO.preBundledRelaysFileURL! + private init(cacheFileURL: URL, prebundledRelaysFileURL: URL) { + self.cacheFileURL = cacheFileURL + self.prebundledRelaysFileURL = prebundledRelaysFileURL - return Tracker( + do { + cachedRelays = try RelayCache.readWithFallback( cacheFileURL: cacheFileURL, - prebundledRelaysFileURL: prebundledRelaysFileURL + preBundledRelaysFileURL: prebundledRelaysFileURL + ) + } catch { + logger.error( + error: error, + message: "Failed to read the relay cache during initialization." ) - }() - - private init(cacheFileURL: URL, prebundledRelaysFileURL: URL) { - self.cacheFileURL = cacheFileURL - self.prebundledRelaysFileURL = prebundledRelaysFileURL - - do { - cachedRelays = try RelayCache.IO.readWithFallback( - cacheFileURL: cacheFileURL, - preBundledRelaysFileURL: prebundledRelaysFileURL - ) - } catch { - logger.error( - error: error, - message: "Failed to read the relay cache during initialization." - ) - _ = updateRelays(completionHandler: nil) - } + _ = updateRelays(completionHandler: nil) } + } - func startPeriodicUpdates() { - nslock.lock() - defer { nslock.unlock() } - - guard !isPeriodicUpdatesEnabled else { return } - - logger.debug("Start periodic relay updates.") + func startPeriodicUpdates() { + nslock.lock() + defer { nslock.unlock() } - isPeriodicUpdatesEnabled = true + guard !isPeriodicUpdatesEnabled else { return } - let nextUpdate = _getNextUpdateDate() + logger.debug("Start periodic relay updates.") - scheduleRepeatingTimer(startTime: .now() + nextUpdate.timeIntervalSinceNow) - } + isPeriodicUpdatesEnabled = true - func stopPeriodicUpdates() { - nslock.lock() - defer { nslock.unlock() } + let nextUpdate = _getNextUpdateDate() - guard isPeriodicUpdatesEnabled else { return } + scheduleRepeatingTimer(startTime: .now() + nextUpdate.timeIntervalSinceNow) + } - logger.debug("Stop periodic relay updates.") + func stopPeriodicUpdates() { + nslock.lock() + defer { nslock.unlock() } - isPeriodicUpdatesEnabled = false + guard isPeriodicUpdatesEnabled else { return } - timerSource?.cancel() - timerSource = nil - } + logger.debug("Stop periodic relay updates.") - func updateRelays( - completionHandler: ( - (OperationCompletion<RelayCache.FetchResult, Error>) -> Void - )? = nil - ) -> Cancellable { - let operation = ResultBlockOperation<RelayCache.FetchResult, Error>( - dispatchQueue: nil - ) { operation in - let cachedRelays = try? self.getCachedRelays() + isPeriodicUpdatesEnabled = false - if self.getNextUpdateDate() > Date() { - operation.finish(completion: .success(.throttled)) - return - } + timerSource?.cancel() + timerSource = nil + } - let task = self.apiProxy.getRelays( - etag: cachedRelays?.etag, - retryStrategy: .noRetry - ) { completion in - operation.finish( - completion: self.handleResponse(completion: completion) - ) - } + func updateRelays( + completionHandler: ( + (OperationCompletion<RelaysFetchResult, Error>) -> Void + )? = nil + ) -> Cancellable { + let operation = ResultBlockOperation<RelaysFetchResult, Error>( + dispatchQueue: nil + ) { operation in + let cachedRelays = try? self.getCachedRelays() - operation.addCancellationBlock { - task.cancel() - } + if self.getNextUpdateDate() > Date() { + operation.finish(completion: .success(.throttled)) + return } - operation.addObserver( - BackgroundObserver( - application: .shared, - name: "Update relays", - cancelUponExpiration: true + let task = self.apiProxy.getRelays( + etag: cachedRelays?.etag, + retryStrategy: .noRetry + ) { completion in + operation.finish( + completion: self.handleResponse(completion: completion) ) - ) + } - operation.completionQueue = .main - operation.completionHandler = completionHandler + operation.addCancellationBlock { + task.cancel() + } + } - operationQueue.addOperation(operation) + operation.addObserver( + BackgroundObserver( + application: .shared, + name: "Update relays", + cancelUponExpiration: true + ) + ) - return operation - } + operation.completionQueue = .main + operation.completionHandler = completionHandler - func getCachedRelays() throws -> CachedRelays { - nslock.lock() - defer { nslock.unlock() } + operationQueue.addOperation(operation) - if let cachedRelays = cachedRelays { - return cachedRelays - } else { - throw NoCachedRelaysError() - } - } + return operation + } - func getNextUpdateDate() -> Date { - nslock.lock() - defer { nslock.unlock() } + func getCachedRelays() throws -> CachedRelays { + nslock.lock() + defer { nslock.unlock() } - return _getNextUpdateDate() + if let cachedRelays = cachedRelays { + return cachedRelays + } else { + throw NoCachedRelaysError() } + } - // MARK: - Observation + func getNextUpdateDate() -> Date { + nslock.lock() + defer { nslock.unlock() } - func addObserver(_ observer: RelayCacheObserver) { - observerList.append(observer) - } + return _getNextUpdateDate() + } - func removeObserver(_ observer: RelayCacheObserver) { - observerList.remove(observer) - } + // MARK: - Observation - // MARK: - Private + func addObserver(_ observer: RelayCacheObserver) { + observerList.append(observer) + } - private func _getNextUpdateDate() -> Date { - let now = Date() + func removeObserver(_ observer: RelayCacheObserver) { + observerList.remove(observer) + } - guard let cachedRelays = cachedRelays else { - return now - } + // MARK: - Private - let nextUpdate = cachedRelays.updatedAt.addingTimeInterval(Self.relayUpdateInterval) + private func _getNextUpdateDate() -> Date { + let now = Date() - return max(nextUpdate, Date()) + guard let cachedRelays = cachedRelays else { + return now } - private func handleResponse( - completion: OperationCompletion<REST.ServerRelaysCacheResponse, REST.Error> - ) -> OperationCompletion<FetchResult, Error> { - let mappedCompletion = completion.tryMap { response -> FetchResult in - switch response { - case let .newContent(etag, relays): - try self.storeResponse(etag: etag, relays: relays) + let nextUpdate = cachedRelays.updatedAt.addingTimeInterval(Self.relayUpdateInterval) - return .newContent + return max(nextUpdate, Date()) + } - case .notModified: - return .sameContent - } - } + private func handleResponse( + completion: OperationCompletion<REST.ServerRelaysCacheResponse, REST.Error> + ) -> OperationCompletion<RelaysFetchResult, Error> { + let mappedCompletion = completion.tryMap { response -> RelaysFetchResult in + switch response { + case let .newContent(etag, relays): + try self.storeResponse(etag: etag, relays: relays) - if let error = mappedCompletion.error { - logger.error( - error: error, - message: "Failed to update relays." - ) + return .newContent + + case .notModified: + return .sameContent } + } - return mappedCompletion + if let error = mappedCompletion.error { + logger.error( + error: error, + message: "Failed to update relays." + ) } - private func storeResponse(etag: String?, relays: REST.ServerRelaysResponse) throws { - let numRelays = relays.wireguard.relays.count + return mappedCompletion + } - logger.info("Downloaded \(numRelays) relays.") + private func storeResponse(etag: String?, relays: REST.ServerRelaysResponse) throws { + let numRelays = relays.wireguard.relays.count - let newCachedRelays = RelayCache.CachedRelays( - etag: etag, - relays: relays, - updatedAt: Date() - ) + logger.info("Downloaded \(numRelays) relays.") - nslock.lock() - cachedRelays = newCachedRelays - nslock.unlock() + let newCachedRelays = CachedRelays( + etag: etag, + relays: relays, + updatedAt: Date() + ) - try RelayCache.IO.write( - cacheFileURL: cacheFileURL, - record: newCachedRelays - ) + nslock.lock() + cachedRelays = newCachedRelays + nslock.unlock() + + try RelayCache.write( + cacheFileURL: cacheFileURL, + record: newCachedRelays + ) - DispatchQueue.main.async { - self.observerList.forEach { observer in - observer.relayCache(self, didUpdateCachedRelays: newCachedRelays) - } + DispatchQueue.main.async { + self.observerList.forEach { observer in + observer.relayCache(self, didUpdateCachedRelays: newCachedRelays) } } + } - private func scheduleRepeatingTimer(startTime: DispatchWallTime) { - let timerSource = DispatchSource.makeTimerSource() - timerSource.setEventHandler { [weak self] in - _ = self?.updateRelays() - } + private func scheduleRepeatingTimer(startTime: DispatchWallTime) { + let timerSource = DispatchSource.makeTimerSource() + timerSource.setEventHandler { [weak self] in + _ = self?.updateRelays() + } - timerSource.schedule( - wallDeadline: startTime, - repeating: .seconds(Int(Self.relayUpdateInterval)) - ) - timerSource.activate() + timerSource.schedule( + wallDeadline: startTime, + repeating: .seconds(Int(Self.relayUpdateInterval)) + ) + timerSource.activate() - self.timerSource = timerSource + self.timerSource = timerSource + } +} + +/// Type describing the result of an attempt to fetch the new relay list from server. +enum RelaysFetchResult: CustomStringConvertible { + /// Request to update relays was throttled. + case throttled + + /// Refreshed relays but the same content was found on remote. + case sameContent + + /// Refreshed relays with new content. + case newContent + + var description: String { + switch self { + case .throttled: + return "throttled" + case .sameContent: + return "same content" + case .newContent: + return "new content" } } } + +struct NoCachedRelaysError: LocalizedError { + var errorDescription: String? { + return "Relay cache is empty." + } +} diff --git a/ios/MullvadVPN/SceneDelegate.swift b/ios/MullvadVPN/SceneDelegate.swift index d495ceb7a7..b77ccf42ae 100644 --- a/ios/MullvadVPN/SceneDelegate.swift +++ b/ios/MullvadVPN/SceneDelegate.swift @@ -9,6 +9,7 @@ import MullvadLogging import MullvadREST import Operations +import RelayCache import UIKit class SceneDelegate: UIResponder { @@ -86,7 +87,7 @@ class SceneDelegate: UIResponder { fatalError() } - RelayCache.Tracker.shared.addObserver(self) + RelayCacheTracker.shared.addObserver(self) NotificationManager.shared.delegate = self accountDataThrottling.requestUpdate(condition: .always) @@ -113,7 +114,7 @@ class SceneDelegate: UIResponder { ) } - RelayCache.Tracker.shared.startPeriodicUpdates() + RelayCacheTracker.shared.startPeriodicUpdates() TunnelManager.shared.startPeriodicPrivateKeyRotation() AddressCacheTracker.shared.startPeriodicUpdates() ShortcutsManager.shared.updateVoiceShortcuts() @@ -122,7 +123,7 @@ class SceneDelegate: UIResponder { } @objc private func sceneWillResignActive() { - RelayCache.Tracker.shared.stopPeriodicUpdates() + RelayCacheTracker.shared.stopPeriodicUpdates() TunnelManager.shared.stopPeriodicPrivateKeyRotation() AddressCacheTracker.shared.stopPeriodicUpdates() @@ -414,7 +415,7 @@ extension SceneDelegate { let selectLocationController = SelectLocationViewController() selectLocationController.delegate = self - if let cachedRelays = try? RelayCache.Tracker.shared.getCachedRelays() { + if let cachedRelays = try? RelayCacheTracker.shared.getCachedRelays() { selectLocationController.setCachedRelays(cachedRelays) } @@ -933,8 +934,8 @@ extension SceneDelegate: TunnelObserver { extension SceneDelegate: RelayCacheObserver { func relayCache( - _ relayCache: RelayCache.Tracker, - didUpdateCachedRelays cachedRelays: RelayCache.CachedRelays + _ relayCache: RelayCacheTracker, + didUpdateCachedRelays cachedRelays: CachedRelays ) { selectLocationViewController?.setCachedRelays(cachedRelays) } diff --git a/ios/MullvadVPN/SelectLocationViewController.swift b/ios/MullvadVPN/SelectLocationViewController.swift index 147fc3b54e..abe8d765f4 100644 --- a/ios/MullvadVPN/SelectLocationViewController.swift +++ b/ios/MullvadVPN/SelectLocationViewController.swift @@ -7,6 +7,7 @@ // import MullvadLogging +import RelayCache import UIKit protocol SelectLocationViewControllerDelegate: AnyObject { @@ -26,7 +27,7 @@ class SelectLocationViewController: UIViewController, UITableViewDelegate { private var tableHeaderFooterViewBottomConstraints: [NSLayoutConstraint] = [] private var dataSource: LocationDataSource? - private var setCachedRelaysOnViewDidLoad: RelayCache.CachedRelays? + private var setCachedRelaysOnViewDidLoad: CachedRelays? private var setRelayLocationOnViewDidLoad: RelayLocation? private var setScrollPositionOnViewDidLoad: UITableView.ScrollPosition = .none private var isViewAppeared = false @@ -229,7 +230,7 @@ class SelectLocationViewController: UIViewController, UITableViewDelegate { // MARK: - Public - func setCachedRelays(_ cachedRelays: RelayCache.CachedRelays) { + func setCachedRelays(_ cachedRelays: CachedRelays) { guard isViewLoaded else { setCachedRelaysOnViewDidLoad = cachedRelays return diff --git a/ios/MullvadVPN/SimulatorTunnelProviderHost.swift b/ios/MullvadVPN/SimulatorTunnelProviderHost.swift index ef159e7886..4bd7b19696 100644 --- a/ios/MullvadVPN/SimulatorTunnelProviderHost.swift +++ b/ios/MullvadVPN/SimulatorTunnelProviderHost.swift @@ -12,6 +12,7 @@ import Foundation import MullvadLogging import MullvadREST import enum NetworkExtension.NEProviderStopReason +import RelayCache class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { private var selectorResult: RelaySelectorResult? @@ -154,7 +155,7 @@ class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate { } private func pickRelay() throws -> RelaySelectorResult { - let cachedRelays = try RelayCache.Tracker.shared.getCachedRelays() + let cachedRelays = try RelayCacheTracker.shared.getCachedRelays() let tunnelSettings = try SettingsManager.readSettings() return try RelaySelector.evaluate( diff --git a/ios/MullvadVPN/TunnelManager/ReconnectTunnelOperation.swift b/ios/MullvadVPN/TunnelManager/ReconnectTunnelOperation.swift index 5105108acb..748a77e3a6 100644 --- a/ios/MullvadVPN/TunnelManager/ReconnectTunnelOperation.swift +++ b/ios/MullvadVPN/TunnelManager/ReconnectTunnelOperation.swift @@ -10,6 +10,7 @@ import Foundation import MullvadREST import MullvadTypes import Operations +import RelayCache class ReconnectTunnelOperation: ResultOperation<Void, Error> { private let interactor: TunnelInteractor @@ -37,7 +38,7 @@ class ReconnectTunnelOperation: ResultOperation<Void, Error> { var selectorResult: RelaySelectorResult? if selectNewRelay { - let cachedRelays = try RelayCache.Tracker.shared.getCachedRelays() + let cachedRelays = try RelayCacheTracker.shared.getCachedRelays() selectorResult = try RelaySelector.evaluate( relays: cachedRelays.relays, constraints: interactor.settings.relayConstraints diff --git a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift index 71210438e5..c2611323a0 100644 --- a/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift +++ b/ios/MullvadVPN/TunnelManager/StartTunnelOperation.swift @@ -10,6 +10,7 @@ import Foundation import MullvadLogging import NetworkExtension import Operations +import RelayCache class StartTunnelOperation: ResultOperation<Void, Error> { typealias EncodeErrorHandler = (Error) -> Void @@ -48,7 +49,7 @@ class StartTunnelOperation: ResultOperation<Void, Error> { case .disconnected, .pendingReconnect: do { - let cachedRelays = try RelayCache.Tracker.shared.getCachedRelays() + let cachedRelays = try RelayCacheTracker.shared.getCachedRelays() let selectorResult = try RelaySelector.evaluate( relays: cachedRelays.relays, constraints: interactor.settings.relayConstraints diff --git a/ios/PacketTunnel/PacketTunnelProvider.swift b/ios/PacketTunnel/PacketTunnelProvider.swift index 982b583e56..45b79f51ac 100644 --- a/ios/PacketTunnel/PacketTunnelProvider.swift +++ b/ios/PacketTunnel/PacketTunnelProvider.swift @@ -11,6 +11,7 @@ import MullvadLogging import MullvadREST import Network import NetworkExtension +import RelayCache import WireGuardKit class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { @@ -435,11 +436,11 @@ class PacketTunnelProvider: NEPacketTunnelProvider, TunnelMonitorDelegate { private class func selectRelayEndpoint(relayConstraints: RelayConstraints) throws -> RelaySelectorResult { - let cacheFileURL = RelayCache.IO.defaultCacheFileURL( + let cacheFileURL = RelayCache.defaultCacheFileURL( forSecurityApplicationGroupIdentifier: ApplicationConfiguration.securityGroupIdentifier )! - let prebundledRelaysURL = RelayCache.IO.preBundledRelaysFileURL! - let cachedRelayList = try RelayCache.IO.readWithFallback( + let prebundledRelaysURL = RelayCache.preBundledRelaysFileURL! + let cachedRelayList = try RelayCache.readWithFallback( cacheFileURL: cacheFileURL, preBundledRelaysFileURL: prebundledRelaysURL ) diff --git a/ios/RelayCache/CachedRelays.swift b/ios/RelayCache/CachedRelays.swift new file mode 100644 index 0000000000..6ff9c36091 --- /dev/null +++ b/ios/RelayCache/CachedRelays.swift @@ -0,0 +1,28 @@ +// +// CachedRelays.swift +// CachedRelays +// +// Created by pronebird on 27/07/2021. +// Copyright © 2021 Mullvad VPN AB. All rights reserved. +// + +import Foundation +import MullvadREST + +/// A struct that represents the relay cache on disk +public struct CachedRelays: Codable { + /// E-tag returned by server + public var etag: String? + + /// The relay list stored within the cache entry + public var relays: REST.ServerRelaysResponse + + /// The date when this cache was last updated + public var updatedAt: Date + + public init(etag: String? = nil, relays: REST.ServerRelaysResponse, updatedAt: Date) { + self.etag = etag + self.relays = relays + self.updatedAt = updatedAt + } +} diff --git a/ios/RelayCache/RelayCache.h b/ios/RelayCache/RelayCache.h new file mode 100644 index 0000000000..abe3d1b983 --- /dev/null +++ b/ios/RelayCache/RelayCache.h @@ -0,0 +1,19 @@ +// +// RelayCache.h +// RelayCache +// +// Created by Sajad Vishkai on 2022-10-21. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +#import <Foundation/Foundation.h> + +//! Project version number for RelayCache. +FOUNDATION_EXPORT double RelayCacheVersionNumber; + +//! Project version string for RelayCache. +FOUNDATION_EXPORT const unsigned char RelayCacheVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import <RelayCache/PublicHeader.h> + + diff --git a/ios/MullvadVPN/RelayCache/RelayCacheIO.swift b/ios/RelayCache/RelayCache.swift index d2e9e91070..64ce748128 100644 --- a/ios/MullvadVPN/RelayCache/RelayCacheIO.swift +++ b/ios/RelayCache/RelayCache.swift @@ -1,21 +1,17 @@ // -// RelayCacheIO.swift -// RelayCacheIO +// RelayCache.swift +// RelayCache // -// Created by pronebird on 27/07/2021. +// Created by pronebird on 06/09/2021. // Copyright © 2021 Mullvad VPN AB. All rights reserved. // import Foundation import MullvadREST -extension RelayCache { - enum IO {} -} - -extension RelayCache.IO { +public class RelayCache { /// The default cache file location bound by app group container. - static func defaultCacheFileURL( + public static func defaultCacheFileURL( forSecurityApplicationGroupIdentifier appGroupIdentifier: String ) -> URL? { let containerURL = FileManager.default.containerURL( @@ -26,19 +22,19 @@ extension RelayCache.IO { } /// The path to pre-bundled `relays.json` file. - static var preBundledRelaysFileURL: URL? { - return Bundle.main.url(forResource: "relays", withExtension: "json") + public static var preBundledRelaysFileURL: URL? { + return Bundle(for: Self.self).url(forResource: "relays", withExtension: "json") } /// Safely read the cache file from disk using file coordinator. - static func read(cacheFileURL: URL) throws -> RelayCache.CachedRelays { - var result: Result<RelayCache.CachedRelays, Error>? + public static func read(cacheFileURL: URL) throws -> CachedRelays { + var result: Result<CachedRelays, Error>? let fileCoordinator = NSFileCoordinator(filePresenter: nil) let accessor = { (fileURLForReading: URL) in result = Result { let data = try Data(contentsOf: fileURLForReading) - return try JSONDecoder().decode(RelayCache.CachedRelays.self, from: data) + return try JSONDecoder().decode(CachedRelays.self, from: data) } } @@ -59,8 +55,8 @@ extension RelayCache.IO { /// Safely read the cache file from disk using file coordinator and fallback to prebundled /// relays in case if the relay cache file is missing. - static func readWithFallback(cacheFileURL: URL, preBundledRelaysFileURL: URL) - throws -> RelayCache.CachedRelays + public static func readWithFallback(cacheFileURL: URL, preBundledRelaysFileURL: URL) + throws -> CachedRelays { do { return try Self.read(cacheFileURL: cacheFileURL) @@ -74,19 +70,19 @@ extension RelayCache.IO { } /// Read pre-bundled relays file from disk. - static func readPrebundledRelays(fileURL: URL) throws -> RelayCache.CachedRelays { + public static func readPrebundledRelays(fileURL: URL) throws -> CachedRelays { let data = try Data(contentsOf: fileURL) let relays = try REST.Coding.makeJSONDecoder() .decode(REST.ServerRelaysResponse.self, from: data) - return RelayCache.CachedRelays( + return CachedRelays( relays: relays, updatedAt: Date(timeIntervalSince1970: 0) ) } /// Safely write the cache file on disk using file coordinator. - static func write(cacheFileURL: URL, record: RelayCache.CachedRelays) throws { + public static func write(cacheFileURL: URL, record: CachedRelays) throws { var result: Result<Void, Error>? let fileCoordinator = NSFileCoordinator(filePresenter: nil) diff --git a/ios/prebuild.sh b/ios/relays-prebuild.sh index 22a8ae4f9d..caef0efe4a 100755 --- a/ios/prebuild.sh +++ b/ios/relays-prebuild.sh @@ -5,9 +5,7 @@ if [ -z "$PROJECT_DIR" ]; then exit 1 fi -ASSETS_DIR_PATH="$PROJECT_DIR/Assets" - -RELAYS_FILE="$ASSETS_DIR_PATH/relays.json" +RELAYS_FILE="$PROJECT_DIR/RelayCache/Assets/relays.json" if [ $CONFIGURATION == "Release" ]; then echo "Remove relays file" |
