Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote configuration for Data Provider Service URL overrides #540

Merged
merged 9 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"tvSiteName": "rsi-player-tvos-apple",
"voiceOverLanguageCode": "it",
"appStoreProductIdentifier": 920753497,
"serviceURL": "https://il.srf.ch",
"playURLs": "{\"rsi\":\"https://www.rsi.ch/play/\",\"rtr\":\"https://www.rtr.ch/play/\",\"rts\":\"https://www.rts.ch/play/\",\"srf\":\"https://www.srf.ch/play/\",\"swi\":\"https://play.swissinfo.ch/play/\"}",
"playServiceURL": "https://www.rsi.ch/play/",
"middlewareURL": "https://playfff.herokuapp.com",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"siteName": "rtr-player-ios-v",
"tvSiteName": "rtr-player-tvos-apple",
"appStoreProductIdentifier": 920754925,
"serviceURL": "https://il.srf.ch",
"playURLs": "{\"rsi\":\"https://www.rsi.ch/play/\",\"rtr\":\"https://www.rtr.ch/play/\",\"rts\":\"https://www.rts.ch/play/\",\"srf\":\"https://www.srf.ch/play/\",\"swi\":\"https://play.swissinfo.ch/play/\"}",
"playServiceURL": "https://www.rtr.ch/play/",
"middlewareURL": "https://playfff.herokuapp.com",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"tvSiteName": "rts-player-tvos-apple",
"voiceOverLanguageCode": "fr",
"appStoreProductIdentifier": 920754415,
"serviceURL": "https://il.srf.ch",
"playURLs": "{\"rsi\":\"https://www.rsi.ch/play/\",\"rtr\":\"https://www.rtr.ch/play/\",\"rts\":\"https://www.rts.ch/play/\",\"srf\":\"https://www.srf.ch/play/\",\"swi\":\"https://play.swissinfo.ch/play/\"}",
"playServiceURL": "https://www.rts.ch/play/",
"middlewareURL": "https://playfff.herokuapp.com",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"tvSiteName": "srf-player-tvos-apple",
"voiceOverLanguageCode": "de",
"appStoreProductIdentifier": 638194352,
"serviceURL": "https://il.srf.ch",
"playURLs": "{\"rsi\":\"https://www.rsi.ch/play/\",\"rtr\":\"https://www.rtr.ch/play/\",\"rts\":\"https://www.rts.ch/play/\",\"srf\":\"https://www.srf.ch/play/\",\"swi\":\"https://play.swissinfo.ch/play/\"}",
"playServiceURL": "https://www.srf.ch/play/",
"middlewareURL": "https://playfff.herokuapp.com",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"tvSiteName": "swi-player-tvos-apple",
"voiceOverLanguageCode": "en",
"appStoreProductIdentifier": 920785201,
"serviceURL": "https://il.srf.ch",
"playURLs": "{\"rsi\":\"https://www.rsi.ch/play/\",\"rtr\":\"https://www.rtr.ch/play/\",\"rts\":\"https://www.rts.ch/play/\",\"srf\":\"https://www.srf.ch/play/\",\"swi\":\"https://play.swissinfo.ch/play/\"}",
"playServiceURL": "https://play.swissinfo.ch/play/",
"middlewareURL": "https://playfff.herokuapp.com",
Expand Down
2 changes: 1 addition & 1 deletion Application/Sources/Application/SceneDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ - (void)handleDeepLinkAction:(DeepLinkAction *)action
if (! [serviceIdentifier isEqual:ApplicationSettingServiceIdentifier()]) {
ApplicationSettingSetServiceIdentifier(serviceIdentifier);

NSString *serviceName = [ServiceObjC nameForServiceId:serviceIdentifier];
NSString *serviceName = [ServiceObjC nameFor:serviceIdentifier];
[Banner showWith:BannerStyleInfo
message:[NSString stringWithFormat:NSLocalizedString(@"Server changed to '%@'", @"Notification message when the server URL changed due to a custom URL."), serviceName]
image:[UIImage imageNamed:@"settings"]
Expand Down
4 changes: 3 additions & 1 deletion Application/Sources/Configuration/ApplicationConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ OBJC_EXPORT NSString * const ApplicationConfigurationDidChangeNotification;

@property (nonatomic, readonly, copy) NSNumber *appStoreProductIdentifier;

@property (nonatomic, readonly, nullable) NSURL *serviceURL;
@property (nonatomic, readonly) NSURL *playServiceURL;
@property (nonatomic, readonly) NSURL *dataProviderProductionServiceURL;
@property (nonatomic, readonly) NSURL *dataProviderStageServiceURL;
@property (nonatomic, readonly) NSURL *dataProviderTestServiceURL;
@property (nonatomic, readonly) NSURL *middlewareURL;
@property (nonatomic, readonly, nullable) NSURL *identityWebserviceURL;
@property (nonatomic, readonly, nullable) NSURL *identityWebsiteURL;
Expand Down
33 changes: 28 additions & 5 deletions Application/Sources/Configuration/ApplicationConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,11 @@ @interface ApplicationConfiguration ()

@property (nonatomic, copy) NSNumber *appStoreProductIdentifier;

@property (nonatomic) NSURL *serviceURL;
@property (nonatomic) NSDictionary<NSNumber *, NSURL *> *playURLs;
@property (nonatomic) NSURL *playServiceURL;
@property (nonatomic) NSURL *dataProviderProductionServiceURL;
@property (nonatomic) NSURL *dataProviderStageServiceURL;
@property (nonatomic) NSURL *dataProviderTestServiceURL;
@property (nonatomic) NSURL *middlewareURL;
@property (nonatomic) NSURL *identityWebserviceURL;
@property (nonatomic) NSURL *identityWebsiteURL;
Expand Down Expand Up @@ -237,6 +239,21 @@ - (instancetype)init

#pragma mark Getters and setters

- (NSURL *)dataProviderProductionServiceURL
{
return _dataProviderProductionServiceURL ?: SRGIntegrationLayerProductionServiceURL();
}

- (NSURL *)dataProviderStageServiceURL
{
return _dataProviderStageServiceURL ?: SRGIntegrationLayerStagingServiceURL();
}

- (NSURL *)dataProviderTestServiceURL
{
return _dataProviderTestServiceURL ?: SRGIntegrationLayerTestServiceURL();
}

- (BOOL)isContinuousPlaybackAvailable
{
#if TARGET_OS_IOS
Expand Down Expand Up @@ -449,10 +466,16 @@ - (BOOL)synchronizeWithFirebaseConfiguration:(PlayFirebaseConfiguration *)fireba
//

self.voiceOverLanguageCode = [firebaseConfiguration stringForKey:@"voiceOverLanguageCode"];

NSString *serviceURLString = [firebaseConfiguration stringForKey:@"serviceURL"];
self.serviceURL = serviceURLString ? [NSURL URLWithString:serviceURLString] : nil;


NSString *dataProviderProductionServiceURLString = [firebaseConfiguration stringForKey:@"dataProviderProductionServiceURL"];
self.dataProviderProductionServiceURL = dataProviderProductionServiceURLString ? [NSURL URLWithString:dataProviderProductionServiceURLString] : nil;

NSString *dataProviderStageServiceURLString = [firebaseConfiguration stringForKey:@"dataProviderStageServiceURL"];
self.dataProviderStageServiceURL = dataProviderStageServiceURLString ? [NSURL URLWithString:dataProviderStageServiceURLString] : nil;

NSString *dataProviderTestServiceURLString = [firebaseConfiguration stringForKey:@"dataProviderTestServiceURL"];
self.dataProviderTestServiceURL = dataProviderTestServiceURLString ? [NSURL URLWithString:dataProviderTestServiceURLString] : nil;

NSString *identityWebserviceURLString = [firebaseConfiguration stringForKey:@"identityWebserviceURL"];
self.identityWebserviceURL = identityWebserviceURLString ? [NSURL URLWithString:identityWebserviceURLString] : nil;

Expand Down
2 changes: 1 addition & 1 deletion Application/Sources/Settings/ApplicationSettings+Common.m
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ void ApplicationSettingSetServiceIdentifier(NSString *identifier)

NSURL *ApplicationSettingServiceURL(void)
{
return [ServiceObjC urlForServiceId:ApplicationSettingServiceIdentifier()];
return [ServiceObjC urlFor:ApplicationSettingServiceIdentifier()];
}

BOOL ApplicationSettingAutoplayEnabled(void)
Expand Down
115 changes: 61 additions & 54 deletions Application/Sources/Settings/Service.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,84 +5,91 @@
//

import Foundation
import SRGDataProvider

struct Service: Identifiable, Equatable {
let id: String
let name: String
let url: URL
enum Service: String, Identifiable, CaseIterable {
case production
case stage
case test
case mmf = "play mmf"
case samProduction = "sam production"
case samStage = "sam stage"
case samTest = "sam test"

static var production = Self(
id: "production",
name: NSLocalizedString("Production", comment: "Server setting name"),
url: SRGIntegrationLayerProductionServiceURL()
)

static var stage = Self(
id: "stage",
name: NSLocalizedString("Stage", comment: "Server setting name"),
url: SRGIntegrationLayerStagingServiceURL()
)

static var test = Self(
id: "test",
name: NSLocalizedString("Test", comment: "Server setting name"),
url: SRGIntegrationLayerTestServiceURL()
)

static var mmf = Self(
id: "play mmf",
name: "Play MMF",
url: mmfUrl
)

private static var mmfUrl: URL = {
private static var mmfUrl: URL {
guard let mmfUrlString = Bundle.main.object(forInfoDictionaryKey: "PlayMMFServiceURL") as? String,
!mmfUrlString.isEmpty
else {
return URL(string: "https://play-mmf.herokuapp.com")!
}
return URL(string: mmfUrlString)!
}()
}

static var samProduction = Self(
id: "sam production",
name: "SAM \(NSLocalizedString("Production", comment: "Server setting name"))",
url: SRGIntegrationLayerProductionServiceURL().appendingPathComponent("sam")
)
var id: Self {
self
}

static var samStage = Self(
id: "sam stage",
name: "SAM \(NSLocalizedString("Stage", comment: "Server setting name"))",
url: SRGIntegrationLayerStagingServiceURL().appendingPathComponent("sam")
)
var environment: String {
rawValue
}

static var samTest = Self(
id: "sam test",
name: "SAM \(NSLocalizedString("Test", comment: "Server setting name"))",
url: SRGIntegrationLayerTestServiceURL().appendingPathComponent("sam")
)
var name: String {
switch self {
case .production:
NSLocalizedString("Production", comment: "Server setting name")
case .stage:
NSLocalizedString("Stage", comment: "Server setting name")
case .test:
NSLocalizedString("Test", comment: "Server setting name")
case .mmf:
"Play MMF"
case .samProduction:
"SAM \(NSLocalizedString("Production", comment: "Server setting name"))"
case .samStage:
"SAM \(NSLocalizedString("Stage", comment: "Server setting name"))"
case .samTest:
"SAM \(NSLocalizedString("Test", comment: "Server setting name"))"
}
}

static var services: [Self] = [production, stage, test, mmf, samProduction, samStage, samTest]
var url: URL {
switch self {
case .production:
ApplicationConfiguration().dataProviderProductionServiceURL
case .stage:
ApplicationConfiguration().dataProviderStageServiceURL
case .test:
ApplicationConfiguration().dataProviderTestServiceURL
case .mmf:
Self.mmfUrl
case .samProduction:
ApplicationConfiguration().dataProviderProductionServiceURL.appendingPathComponent("sam")
case .samStage:
ApplicationConfiguration().dataProviderStageServiceURL.appendingPathComponent("sam")
case .samTest:
ApplicationConfiguration().dataProviderTestServiceURL.appendingPathComponent("sam")
}
}

static func service(forId id: String?) -> Self {
static func service(for environment: String?) -> Self {
#if DEBUG || NIGHTLY || BETA
guard let id, let server = services.first(where: { $0.id == id }) else {
guard let environment, let service = Self(rawValue: environment) else {
return .production
}
return server
return service
#else
return .production
#endif
}
}

@objc class ServiceObjC: NSObject {
@objc static func name(forServiceId serviceId: String) -> String {
Service.service(forId: serviceId).name
@objc static var environments = Service.allCases.map(\.environment)

@objc static func name(for environment: String) -> String {
Service.service(for: environment).name
}

@objc static func url(forServiceId serviceId: String) -> URL {
ApplicationConfiguration().serviceURL ?? Service.service(forId: serviceId).url
@objc static func url(for environment: String) -> URL {
Service.service(for: environment).url
}
}
14 changes: 5 additions & 9 deletions Application/Sources/Settings/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ struct SettingsView: View {
@AppStorage(PlaySRGSettingServiceIdentifier) private var selectedServiceId: String?

private var selectedService: Service {
Service.service(forId: selectedServiceId)
Service.service(for: selectedServiceId)
}

var body: some View {
Expand Down Expand Up @@ -643,7 +643,7 @@ struct SettingsView: View {
private struct ServiceSelectionView: View {
var body: some View {
List {
ForEach(Service.services) { service in
ForEach(Service.allCases) { service in
ServiceCell(service: service)
}
}
Expand All @@ -660,7 +660,7 @@ struct SettingsView: View {
private struct ServiceCell: View {
let service: Service

@AppStorage(PlaySRGSettingServiceIdentifier) var selectedServiceId: String?
@AppStorage(PlaySRGSettingServiceIdentifier) var selectedServiceIdentifier: String?

var body: some View {
Button(action: select) {
Expand All @@ -676,15 +676,11 @@ struct SettingsView: View {
}

private func isSelected() -> Bool {
if let selectedServiceId {
service.id == selectedServiceId
} else {
service == .production
}
service == Service.service(for: selectedServiceIdentifier)
}

private func select() {
selectedServiceId = service.id
selectedServiceIdentifier = service.rawValue
}
}

Expand Down
3 changes: 2 additions & 1 deletion Scripts/check-quality.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

set -e

echo "... checking Swift code..."
echo "... checking Swift code with SwiftLint..."
if [ $# -eq 0 ]; then
swiftlint --quiet --strict
elif [[ "$1" == "only-changes" ]]; then
git diff --staged --name-only | grep ".swift$" | xargs -I FILE swiftlint lint --quiet --strict "FILE"
fi
echo "... checking Swift code with SwiftFormat..."
if [ $# -eq 0 ]; then
swiftformat --lint --quiet .
elif [[ "$1" == "only-changes" ]]; then
Expand Down
4 changes: 3 additions & 1 deletion docs/REMOTE_CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ If a remote configuration is found to be invalid (usually a mandatory parameter
* `faqURL` (optional, string): The URL of the FAQs.
* `dataProtectionURL` (optional, string): The URL of the data protection information page.
* `impressumURL` (optional, string): The URL of the impressum page. If none is provided, the corresponding menu entry will not be displayed.
* `serviceURL` (optional, string): The URL of the Content service (DataProvider). If set, it overrides the local server option available in beta builds only.
* `dataProviderProductionServiceURL (optional, string): The URL of the production DataProvider service. If omitted, the default Integration Layer production URL is used.
* `dataProviderStageServiceURL (optional, string): The URL of the stage/int DataProvider service. If omitted, the default Integration Layer stage URL is used.
* `dataProviderTestServiceURL (optional, string): The URL of the test/dev DataProvider service. If omitted, the default Integration Layer test URL is used.
* `identityWebserviceURL` (optional, string): The URL of the identity webservices.
* `identityWebsiteURL` (optional, string): The URL of the identity web portal.
* `userDataServiceURL` (optional, string): The URL of the service with which user data can be synchronized (history, preferences, playlists).
Expand Down