Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ad76cee
introduces API v14 to fetch cells internal feature config
jullianm Dec 23, 2025
20afa1e
add wire cells enabled checked conditions, fix API response model
jullianm Dec 29, 2025
1383b77
fix UTs
jullianm Dec 29, 2025
0019555
lint and format
jullianm Dec 29, 2025
f9b7d96
add cells URL resolver in APIs
jullianm Dec 30, 2025
1963601
lint and format
jullianm Dec 30, 2025
c1c327f
update mock
jullianm Dec 30, 2025
3f877eb
fix UT compilation issues
jullianm Dec 30, 2025
d99e2fa
remove async from cells URL resolver, reintroduce previous code with …
jullianm Jan 5, 2026
4295906
remove default values from cells internal feature config
jullianm Jan 5, 2026
ebff363
Merge branch 'develop' into feat/get-cells-backend-url-from-feature-c…
jullianm Jan 5, 2026
89c0de8
lint and format
jullianm Jan 6, 2026
a64f731
Merge branch 'feat/get-cells-backend-url-from-feature-config' of ssh:…
jullianm Jan 6, 2026
e1ccdce
Merge branch 'develop' into feat/get-cells-backend-url-from-feature-c…
jullianm Jan 6, 2026
e498a42
generate mock
jullianm Jan 6, 2026
be74cd7
Merge branch 'feat/get-cells-backend-url-from-feature-config' of ssh:…
jullianm Jan 6, 2026
a256c8a
Merge branch 'develop' into feat/get-cells-backend-url-from-feature-c…
jullianm Jan 6, 2026
638f4c7
Merge branch 'develop' into feat/get-cells-backend-url-from-feature-c…
jullianm Jan 6, 2026
3da604e
Merge branch 'develop' into feat/get-cells-backend-url-from-feature-c…
jullianm Jan 6, 2026
97c54fc
lint and format
jullianm Jan 6, 2026
a30628e
fix UT
jullianm Jan 6, 2026
b7f200b
Merge branch 'develop' into feat/get-cells-backend-url-from-feature-c…
jullianm Jan 6, 2026
a99bb6b
Merge branch 'develop' into feat/get-cells-backend-url-from-feature-c…
jullianm Jan 6, 2026
647d5b8
Merge branch 'develop' into feat/get-cells-backend-url-from-feature-c…
jullianm Jan 6, 2026
d8fb6ef
lint and format
jullianm Jan 6, 2026
cd8b467
Merge branch 'feat/get-cells-backend-url-from-feature-config' of ssh:…
jullianm Jan 6, 2026
29d6530
fix UT compilation issues
jullianm Jan 6, 2026
6aa6337
fix UT compilation issue
jullianm Jan 7, 2026
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 @@ -124,6 +124,8 @@ public extension WireNetwork.APIVersion {
self = .v12
case .v13:
self = .v13
case .v14:
self = .v14
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,11 @@ extension WireNetwork.ChannelsPermision {
}
}
}

extension WireNetwork.CellsInternalFeatureConfig {
func toDomainModel() -> Feature.CellsInternal.Config {
Feature.CellsInternal.Config(
backend: .init(url: backendURL)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ public final class FeatureConfigRepository: FeatureConfigRepositoryProtocol {
)
}

public func fetchCellsInternal() async throws -> LocalFeature<Feature.CellsInternal.Config> {
try await fetchFeatureConfig(
name: .cellsInternal,
type: Feature.CellsInternal.Config.self
)
}

// MARK: - Private

private func sendFeatureState(for featureConfig: FeatureConfig) async {
Expand Down Expand Up @@ -223,6 +230,12 @@ public final class FeatureConfigRepository: FeatureConfigRepositoryProtocol {
isEnabled: cellsConfig.status == .enabled
)

case let .cellsInternal(cellsInternalConfig):
return FeatureState(
name: .cellsInternal,
isEnabled: cellsInternalConfig.status == .enabled
)

case let .unknown(featureName):
logger.warn(
"Unknown feature name: \(featureName)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ import WireDataModel

/// A feature fetched locally
public struct LocalFeature<T: Decodable> {
let status: Feature.Status
let config: T?
public let status: Feature.Status
public let config: T?
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public protocol FeatureConfigRepositoryProtocol {
func fetchMLSConfig() async throws -> LocalFeature<Feature.MLS.Config>
func fetchMLSMigrationConfig() async throws -> LocalFeature<Feature.MLSMigration.Config>
func fetchAppLock() async throws -> LocalFeature<Feature.AppLock.Config>
func fetchCellsInternal() async throws -> LocalFeature<Feature.CellsInternal.Config>

func isFeatureEnabled(
_ feature: Feature.Name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ extension FeatureConfigLocalStoreProtocol {
isEnabled: config.status == .enabled,
config: nil
)
case let .cellsInternal(config):
await storeFeature(
name: .cellsInternal,
isEnabled: config.status == .enabled,
config: config.toDomainModel()
)
case let .unknown(name):
WireLogger.featureConfigs.warn("encountered unknown feature config '\(name)' when storing, skipping")
return
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// Wire
// Copyright (C) 2025 Wire Swiss GmbH
// Copyright (C) 2026 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// Wire
// Copyright (C) 2025 Wire Swiss GmbH
// Copyright (C) 2026 Wire Swiss GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ struct StorableFeatureConfigUpdateEvent: Equatable, Codable, Sendable {
)
)
)
case let .cellsInternal(config):
.cellsInternal(
StorableCellsInternalFeatureConfig(
status: StorableFeatureConfigStatus(config.status),
backendURL: config.backendURL
)
)
case let .unknown(featureName):
.unknown(featureName: featureName)
}
Expand Down Expand Up @@ -265,6 +272,13 @@ struct StorableFeatureConfigUpdateEvent: Equatable, Codable, Sendable {
.cells(
.init(status: config.status.toAPIModel())
)
case let .cellsInternal(config):
.cellsInternal(
.init(
status: config.status.toAPIModel(),
backendURL: config.backendURL
)
)
case let .unknown(featureName):
.unknown(featureName: featureName)
}
Expand Down Expand Up @@ -297,6 +311,7 @@ enum StorableFeatureConfig: Equatable, Codable, Sendable {
case allowedGlobalOperations(StorableAllowedGlobalOperationsFeatureConfig)
case consumableNotifications(StorableBasicFeatureConfig)
case cells(StorableBasicFeatureConfig)
case cellsInternal(StorableCellsInternalFeatureConfig)
case unknown(featureName: String)

}
Expand Down Expand Up @@ -437,3 +452,8 @@ struct StorableChannelsFeatureConfig: Codable, Equatable, Sendable {
let allowedToOpenChannels: Permission

}

struct StorableCellsInternalFeatureConfig: Codable, Equatable, Sendable {
let status: StorableFeatureConfigStatus
let backendURL: URL
}
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ final class FeatureConfigRepositoryTests: XCTestCase {
),
.cells(
.init(status: .enabled)
),
.cellsInternal(
.init(
status: .enabled,
backendURL: URL(string: "https://wire.com")!
)
)
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public import WireMessagingUI

public struct WireMessagingFactory {

public typealias CellsURLResolver = @Sendable () throws -> URL

private let nodesAPI: NodesAPI
private let uploadManager: WireCellsNodeUploadManager
private let draftsRepository: DraftsRepository
Expand All @@ -44,29 +46,15 @@ public struct WireMessagingFactory {

@MainActor
public init(
serverURL: URL,
cellsURLResolver: @escaping CellsURLResolver,
accessToken: any AccessTokenProvider,
fileCache: any FileCache,
contextProvider: any ManagedObjectContextProvider,
isFoldersEnabled: Bool,
isCollaboraEnabled: Bool
) {
// TODO: [WPB-18798] Remove serverURL temporary override when there exists a method to obtain the correct URL.
let serverURL = switch serverURL.host {
case "prod-nginz-https.wire.com": // Production
URL(string: "https://cells-beta.wire.com")!
case "staging-nginz-https.zinfra.io": // Staging
URL(string: "https://cells.staging.zinfra.io")!
case "nginz-https.fulu.wire.link": // Fulu
URL(string: "https://cells.fulu.wire.link")!
case "nginz-https.imai.wire.link": // Imai
URL(string: "https://cells.imai.wire.link")!
default:
serverURL
}

self.nodeCache = WireCellsNodeCache()
self.nodesAPI = NodesAPI(serverURL: serverURL, accessToken: accessToken)
self.nodesAPI = NodesAPI(serverURLResolver: cellsURLResolver, accessToken: accessToken)
self.uploadManager = WireCellsNodeUploadManager(nodesAPI: nodesAPI)
self.draftsRepository = DraftsRepository(uploadManager: uploadManager, nodesAPI: nodesAPI)
self.fileCache = fileCache
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import AWSClientRuntime
package import AWSS3
package import Foundation
import Smithy
import SmithyHTTPAPI
import SmithyIdentity
import SmithyStreams
import WireLogging
Expand Down Expand Up @@ -62,11 +63,17 @@ final class AWSClient: Sendable {
private let s3: any S3ClientProtocol
private let makeStream: @Sendable (FileStream) -> ObservableStream

convenience init(serverURL: URL, accessToken: any AccessTokenProvider) {
convenience init(
serverURLResolver: @escaping @Sendable () throws -> URL,
accessToken: any AccessTokenProvider
) {
let config = try! S3Client.S3ClientConfiguration(
awsCredentialIdentityResolver: CredentialIdentityResolver(accessTokenProvider: accessToken),
region: Constants.region,
endpoint: serverURL.absoluteString
endpointResolver: AWSEndpointResolver(
serverURLResolver: serverURLResolver,
bucket: Constants.bucket
)
)
self.init(s3: S3Client(config: config))
}
Expand Down Expand Up @@ -275,6 +282,24 @@ private extension WireCellsNodeNetworkModel {
}
}

private struct AWSEndpointResolver: EndpointResolver {
let serverURLResolver: @Sendable () throws -> URL
let bucket: String

init(
serverURLResolver: @escaping @Sendable () throws -> URL,
bucket: String
) {
self.serverURLResolver = serverURLResolver
self.bucket = bucket
}

func resolve(params: AWSS3.EndpointParams) throws -> SmithyHTTPAPI.Endpoint {
let serverURL = try serverURLResolver().appendingPathComponent("/\(bucket)")
return try SmithyHTTPAPI.Endpoint(urlString: serverURL.absoluteString)
}
}

private struct CredentialIdentityResolver: AWSCredentialIdentityResolver {

let accessTokenProvider: any AccessTokenProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ package final actor NodesAPI: NodesAPIProtocol, WireCellsNodesRepositoryProtocol
private let restAPI: RestAPI
private let fileManager: FileManager

package init(serverURL: URL, accessToken: any AccessTokenProvider) {
package init(
serverURLResolver: @escaping @Sendable () throws -> URL,
accessToken: any AccessTokenProvider
) {
self.init(
awsClient: AWSClient(serverURL: serverURL, accessToken: accessToken),
awsClient: AWSClient(
serverURLResolver: serverURLResolver,
accessToken: accessToken
),
restAPI: RestAPI(
serverURL: serverURL.appendingPathComponent("/v2"),
serverURLResolver: serverURLResolver,
accessToken: accessToken
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,14 @@ final class RestAPI: Sendable {
static let renameBackgroundActionName = "move"
}

private let serverURL: URL
private let serverURLResolver: @Sendable () throws -> URL
private let accessTokenProvider: any AccessTokenProvider

init(serverURL: URL, accessToken: any AccessTokenProvider) {
self.serverURL = serverURL
init(
serverURLResolver: @escaping @Sendable () throws -> URL,
accessToken: any AccessTokenProvider
) {
self.serverURLResolver = serverURLResolver
self.accessTokenProvider = accessToken
}

Expand Down Expand Up @@ -348,7 +351,7 @@ final class RestAPI: Sendable {

private func makeConfiguration() async throws -> CellsSDKAPIConfiguration {
let config = CellsSDKAPIConfiguration()
config.basePath = serverURL.absoluteString
config.basePath = try serverURLResolver().appendingPathComponent("/v2").absoluteString
config.customHeaders = ["Authorization": "Bearer \(try await accessTokenProvider.accessToken().token)"]
config.interceptor = LoggingIntercepter()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ package final actor WireCellsNodeUploadManager: WireCellsNodeUploadManagerProtoc
) async -> AsyncStream<WireCellsUploadStatus> {
let (stream, continuation) = AsyncStream.makeStream(of: WireCellsUploadStatus.self)
let task = Task { [nodesAPI] in
let upload = await nodesAPI.uploadFile(path: assetPath, node: node, versionID: versionID)

do {
let upload = try await nodesAPI.uploadFile(path: assetPath, node: node, versionID: versionID)

for try await progress in upload {
await self.updateUploadProgress(
nodeID: node.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ package protocol NodesAPIProtocol: Sendable {
onProgressUpdate: @escaping @Sendable (UInt64) -> Void
) async throws

func uploadFile(path: URL, node: WireCellsNode, versionID: UUID) async -> AsyncThrowingStream<Int, any Error>
func uploadFile(path: URL, node: WireCellsNode, versionID: UUID) async throws -> AsyncThrowingStream<Int, any Error>

func deleteVersion(nodeID: UUID, versionID: UUID) async throws

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class NodesAPITests {
makeStream: { ObservableStream($0, bufferingPolicy: .unbounded) }
),
restAPI: RestAPI(
serverURL: URL(string: "example.com")!,
serverURLResolver: { URL(string: "example.com")! },
accessToken: MockAccessTokenProvider()
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public struct AccountsAPIBuilder {
AccountsAPIV12(apiService: apiService)
case .v13:
AccountsAPIV13(apiService: apiService)
case .v14:
AccountsAPIV14(apiService: apiService)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
// along with this program. If not, see http://www.gnu.org/licenses/.
//

final class AccountsAPIV13: AccountsAPIV12 {
class AccountsAPIV13: AccountsAPIV12 {
override var apiVersion: APIVersion { .v13 }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Wire
// Copyright (C) 2026 Wire Swiss GmbH
//
// This program 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.
//
// This program 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 this program. If not, see http://www.gnu.org/licenses/.
//

final class AccountsAPIV14: AccountsAPIV13 {
override var apiVersion: APIVersion { .v14 }
}
Loading
Loading