passepartout-apple/PassepartoutLibrary/Sources/PassepartoutProviders/Repositories/ServerMapper.swift

190 lines
6.0 KiB
Swift
Raw Normal View History

2022-04-12 13:09:14 +00:00
//
// ServerMapper.swift
// Passepartout
//
// Created by Davide De Rosa on 3/14/22.
2023-03-17 15:56:19 +00:00
// Copyright (c) 2023 Davide De Rosa. All rights reserved.
2022-04-12 13:09:14 +00:00
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import Foundation
import CoreData
2022-06-23 21:31:01 +00:00
import PassepartoutCore
2022-04-12 13:09:14 +00:00
import PassepartoutServices
import PassepartoutUtils
struct ServerMapper: DTOMapper, ModelMapper {
private let context: NSManagedObjectContext
2023-03-17 20:55:47 +00:00
2022-04-12 13:09:14 +00:00
init(_ context: NSManagedObjectContext) {
self.context = context
}
func toDTO(_ ws: WSProviderServer) -> CDInfrastructureServer {
let server = CDInfrastructureServer(context: context)
server.apiId = ws.id
server.countryCode = ws.countryCode
server.extraCountryCodes = ws.encodedExtraCountryCodes
server.area = ws.area
if let serverIndex = ws.serverIndex {
server.serverIndex = Int16(serverIndex)
} else {
server.serverIndex = 0
}
server.tags = ws.encodedTags
server.hostname = ws.hostname
if let addrs = ws.numericAddresses {
server.ipAddresses = ws.encodedIPAddresses
// strip hostname if found in IP addresses
if let hostname = server.hostname, let numericHostname = Utils.ipv4(fromString: hostname), addrs.contains(numericHostname) {
server.hostname = nil
}
}
return server
}
2023-03-17 20:55:47 +00:00
2022-04-12 13:09:14 +00:00
static func toModel(_ dto: CDInfrastructureServer) -> ProviderServer? {
guard let uniqueId = dto.uniqueId,
let apiId = dto.apiId,
let categoryDTO = dto.category,
let categoryName = categoryDTO.name,
let infrastructureDTO = categoryDTO.infrastructure,
let providerDTO = infrastructureDTO.provider,
let providerMetadata = ProviderMapper.toModel(providerDTO),
let countryCode = dto.countryCode else {
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
return nil
}
guard let presetDTOs = categoryDTO.presets?.allObjects as? [CDInfrastructurePreset], !presetDTOs.isEmpty else {
Utils.assertCoreDataDecodingFailed(
#file, #function, #line,
"Category '\(categoryName)' of server \(apiId) has no presets"
)
return nil
}
let supportedPresetIds = presetDTOs
.sorted()
.compactMap(\.id)
return ProviderServer(
providerMetadata: providerMetadata,
id: uniqueId,
apiId: apiId,
categoryName: categoryName,
countryCode: countryCode,
extraCountryCodes: dto.decodedExtraCountryCodes,
localizedName: dto.localizedName,
2022-04-12 13:09:14 +00:00
serverIndex: dto.serverIndex != 0 ? Int(dto.serverIndex) : nil,
tags: dto.decodedTags,
2022-04-12 13:09:14 +00:00
hostname: dto.hostname,
ipAddresses: dto.decodedIPAddresses,
presetIds: supportedPresetIds
)
}
2023-03-17 20:55:47 +00:00
2022-04-12 13:09:14 +00:00
static func toModelWithPresets(_ dto: CDInfrastructureServer) -> ProviderServer? {
2022-06-23 21:31:01 +00:00
guard let server = toModel(dto),
2022-04-12 13:09:14 +00:00
let categoryDTO = dto.category,
let categoryName = categoryDTO.name else {
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
return nil
}
guard let presetDTOs = dto.category?.presets?.allObjects as? [CDInfrastructurePreset], !presetDTOs.isEmpty else {
Utils.assertCoreDataDecodingFailed(
#file, #function, #line,
"Category '\(categoryName)' has no presets"
)
return nil
}
2022-06-23 21:31:01 +00:00
let presets = presetDTOs
2022-04-12 13:09:14 +00:00
.sorted()
.compactMap(PresetMapper.toModel)
2023-03-17 20:55:47 +00:00
2022-06-23 21:31:01 +00:00
return server.withPresets(presets)
2022-04-12 13:09:14 +00:00
}
}
private extension WSProviderServer {
var encodedExtraCountryCodes: String? {
2022-09-04 18:09:31 +00:00
extraCountryCodes?.joined(separator: ",")
2022-04-12 13:09:14 +00:00
}
2023-03-17 20:55:47 +00:00
2022-04-12 13:09:14 +00:00
var encodedTags: String? {
2022-09-04 18:09:31 +00:00
tags?.joined(separator: ",")
2022-04-12 13:09:14 +00:00
}
var encodedIPAddresses: String? {
guard let addrs = numericAddresses, !addrs.isEmpty else {
return nil
}
return numericAddresses?
.map(Utils.string(fromIPv4:))
.joined(separator: ",")
}
}
private extension CDInfrastructureServer {
var decodedExtraCountryCodes: [String]? {
2022-09-04 18:09:31 +00:00
extraCountryCodes?.components(separatedBy: ",")
2022-04-12 13:09:14 +00:00
}
2023-03-17 20:55:47 +00:00
2022-04-12 13:09:14 +00:00
var decodedTags: [String]? {
2022-09-04 18:09:31 +00:00
tags?.components(separatedBy: ",")
2022-04-12 13:09:14 +00:00
}
2023-03-17 20:55:47 +00:00
2022-04-12 13:09:14 +00:00
var decodedIPAddresses: [String] {
2022-09-04 18:09:31 +00:00
ipAddresses?.components(separatedBy: ",") ?? []
2022-04-12 13:09:14 +00:00
}
}
private extension CDInfrastructureServer {
var localizedName: String? {
2022-04-12 13:09:14 +00:00
var comps: [String] = []
if let extraCountryCodes = decodedExtraCountryCodes {
comps.append(contentsOf: extraCountryCodes.map {
$0.localizedAsCountryCode
})
}
if let area = area {
comps.append(area.capitalized)
}
guard !comps.isEmpty else {
return nil
}
return comps.joined(separator: " ")
2022-04-12 13:09:14 +00:00
}
}
extension CDInfrastructurePreset: Comparable {
public static func <(lhs: CDInfrastructurePreset, rhs: CDInfrastructurePreset) -> Bool {
guard let lname = lhs.name, let rname = rhs.name else {
fatalError("CDPreset has no name?")
}
return lname.lowercased() < rname.lowercased()
}
}