FusionAds-iOS/FusionAds/Classes/fusion/engine/StrategyConfig.swift

300 lines
9.5 KiB
Swift

// StrategyConfig.swift
// Defines configuration structures for ad strategies
// Corresponds to StrategyConfig.kt in Android implementation
import Foundation
// MARK: - Strategy Types
public enum InterstitialStrategy: Int {
case `default` = 0
case mab = 1
}
public enum RewardedStrategy: Int {
case `default` = 0
case mab = 1
}
public enum BannerStrategy: Int {
case `default` = 0
}
protocol StrategyConfig: Decodable {}
// MARK: - Default Config Classes
public struct DefaultInterstitialConfig: Codable, StrategyConfig {
public let adPlatform: String
public let adUnitId: String
public let adAmazonSlotId: String?
public init(adPlatform: String, adUnitId: String, adAmazonSlotId: String? = nil) {
self.adPlatform = adPlatform
self.adUnitId = adUnitId
self.adAmazonSlotId = adAmazonSlotId
}
private enum CodingKeys : String, CodingKey {
case adPlatform = "ad_platform",
adUnitId = "ad_unit_id",
adAmazonSlotId = "ad_amz_slot_id"
}
}
public struct DefaultRewardedConfig: Codable, StrategyConfig {
public let adPlatform: String
public let adUnitId: String
public let adAmazonSlotId: String?
public init(adPlatform: String, adUnitId: String, adAmazonSlotId: String? = nil) {
self.adPlatform = adPlatform
self.adUnitId = adUnitId
self.adAmazonSlotId = adAmazonSlotId
}
private enum CodingKeys : String, CodingKey {
case adPlatform = "ad_platform",
adUnitId = "ad_unit_id",
adAmazonSlotId = "ad_amz_slot_id"
}
}
public struct DefaultBannerConfig: Codable, StrategyConfig {
public let adPlatform: String
public let adUnitId: String
public let adAmazonSlotId: String?
public init(adPlatform: String, adUnitId: String, adAmazonSlotId: String? = nil) {
self.adPlatform = adPlatform
self.adUnitId = adUnitId
self.adAmazonSlotId = adAmazonSlotId
}
private enum CodingKeys : String, CodingKey {
case adPlatform = "ad_platform",
adUnitId = "ad_unit_id",
adAmazonSlotId = "ad_amz_slot_id"
}
}
public struct DefaultMRecConfig: Codable, StrategyConfig {
public let adPlatform: String
public let adUnitId: String
public let adAmazonSlotId: String?
public init(adPlatform: String, adUnitId: String, adAmazonSlotId: String? = nil) {
self.adPlatform = adPlatform
self.adUnitId = adUnitId
self.adAmazonSlotId = adAmazonSlotId
}
private enum CodingKeys : String, CodingKey {
case adPlatform = "ad_platform",
adUnitId = "ad_unit_id",
adAmazonSlotId = "ad_amz_slot_id"
}
}
public struct MabRewardedConfig: Codable, StrategyConfig {
public let aggregatorConfigs: [AggregatorConfig]
public let showTimeoutInSecond: Double?
init(aggregatorConfigs: [AggregatorConfig], showTimeoutInSecond: Double?) {
self.aggregatorConfigs = aggregatorConfigs
self.showTimeoutInSecond = showTimeoutInSecond
}
private enum CodingKeys : String, CodingKey {
case aggregatorConfigs = "aggregator_configs",
showTimeoutInSecond = "show_timeout_second"
}
}
public struct MabInterstitialConfig: Codable, StrategyConfig {
public let aggregatorConfigs: [AggregatorConfig]
public let showTimeoutInSecond: Double?
init(aggregatorConfigs: [AggregatorConfig], showTimeoutInSecond: Double?) {
self.aggregatorConfigs = aggregatorConfigs
self.showTimeoutInSecond = showTimeoutInSecond
}
private enum CodingKeys : String, CodingKey {
case aggregatorConfigs = "aggregator_configs",
showTimeoutInSecond = "show_timeout_second"
}
}
public struct AggregatorConfig: Codable {
public let aggregatorId: String
public let adPlatform: String
public let raiseRate: Double
public let selfRaiseRate: Double?
public let cacheExpireInSecond: Double
public let priority: Int
public let adUnitIds: [AdUnitSpec]
public let loadTimeoutInSecond: Double?
init(aggregatorId: String, adPlatform: String, raiseRate: Double, selfRaiseRate: Double?, cacheExpireInSecond: Double, priority: Int, adUnitIds: [AdUnitSpec], loadTimeoutInSecond: Double?) {
self.aggregatorId = aggregatorId
self.adPlatform = adPlatform
self.raiseRate = raiseRate
self.selfRaiseRate = selfRaiseRate
self.cacheExpireInSecond = cacheExpireInSecond
self.priority = priority
self.adUnitIds = adUnitIds
self.loadTimeoutInSecond = loadTimeoutInSecond
}
private enum CodingKeys : String, CodingKey {
case aggregatorId = "aggregator_id",
adPlatform = "ad_platform",
raiseRate = "raise_rate",
selfRaiseRate = "self_raise_rate",
cacheExpireInSecond = "cache_expire_second",
priority = "priority",
adUnitIds = "ad_unit_ids",
loadTimeoutInSecond = "load_timeout_second"
}
}
public struct AdUnitSpec: Codable {
public let adUnitId: String
public let adAmazonSlotId: String?
public let floorEcpm: Double
public var floor: Double {
return floorEcpm / 1000
}
init(adUnitId: String, adAmazonSlotId: String?, floorEcpm: Double = 0.0) {
self.adUnitId = adUnitId
self.adAmazonSlotId = adAmazonSlotId
self.floorEcpm = floorEcpm
}
private enum CodingKeys : String, CodingKey {
case adUnitId = "ad_unit_id",
adAmazonSlotId = "ad_amz_slot_id",
floorEcpm = "floor_ecpm"
}
}
// MARK: - AdEngineConfig
public struct AdEngineConfig: Codable {
public let strategy: Int
public let faUnitId: String
public let config: [String: Any]
public init(strategy: Int, faUnitId: String, config: [String: Any]) {
self.strategy = strategy
self.faUnitId = faUnitId
self.config = config
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(strategy, forKey: .strategy)
try container.encode(faUnitId, forKey: .faUnitId)
try container.encode(JSONCodable(config), forKey: .config)
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
strategy = try container.decode(Int.self, forKey: .strategy)
faUnitId = try container.decode(String?.self, forKey: .faUnitId) ?? "default"
config = try container.decode(JSONCodable.self, forKey: .config).value as! Dictionary
}
private enum CodingKeys: String, CodingKey {
case strategy = "strategy",
config = "config",
faUnitId = "fa_unit_id"
}
}
private struct JSONCodable: Codable {
let value: Any
init(_ value: Any) {
self.value = value
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
self.value = NSNull()
} else if let bool = try? container.decode(Bool.self) {
self.value = bool
} else if let int = try? container.decode(Int.self) {
self.value = int
} else if let uint = try? container.decode(UInt.self) {
self.value = uint
} else if let double = try? container.decode(Double.self) {
self.value = double
} else if let string = try? container.decode(String.self) {
self.value = string
} else if let array = try? container.decode([JSONCodable].self) {
self.value = array.map { $0.value }
} else if let dictionary = try? container.decode([String: JSONCodable].self) {
self.value = dictionary.mapValues { $0.value }
} else {
throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "AnyCodable cannot decode value"
)
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self.value {
case is NSNull:
try container.encodeNil()
case let bool as Bool:
try container.encode(bool)
case let int as Int:
try container.encode(int)
case let uint as UInt:
try container.encode(uint)
case let double as Double:
try container.encode(double)
case let string as String:
try container.encode(string)
case let array as [Any]:
try container.encode(array.map { JSONCodable($0) })
case let dictionary as [String: Any]:
try container.encode(dictionary.mapValues { JSONCodable($0) })
default:
let context = EncodingError.Context(
codingPath: container.codingPath,
debugDescription: "AnyCodable cannot encode value \(self.value)"
)
throw EncodingError.invalidValue(self.value, context)
}
}
}
extension StrategyConfig
{
init<Key: Hashable>(_ dict: [Key: Any]) throws
{
do {
let data = try JSONSerialization.data(withJSONObject: dict, options: [])
self = try JSONDecoder().decode(Self.self, from: data)
} catch {
Logger.e(tag: "StrategyConfig", message: "strategy config deserialize to \(Self.self) fail, data is \(dict)")
throw error;
}
}
}