Skip to content

feat: port Wire Android services & use cases - WPB-16148 #2920

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

Open
wants to merge 41 commits into
base: develop
Choose a base branch
from

Conversation

El-Fitz
Copy link
Contributor

@El-Fitz El-Fitz commented Apr 18, 2025

TaskWPB-16148 [iOS] Implement usecase for upload to WireCells

Issue

Ports and integrates the Android WireCells services & use cases interfaces & implementations to the iOS app.

Remaining

Tests for this PR will be done in a follow up ticket: https://wearezeta.atlassian.net/browse/WPB-17490

Testing

None of this code is used yet so cannot be manually tested


Checklist

  • Title contains a reference JIRA issue number like [WPB-XXX].
  • Description is filled and free of optional paragraphs.
  • Adds/updates automated tests.

@El-Fitz El-Fitz self-assigned this Apr 18, 2025
@samwyndham samwyndham marked this pull request as ready for review May 2, 2025 15:30
Copy link
Contributor

github-actions bot commented May 2, 2025

Test Results

2 788 tests   2 783 ✅  4m 57s ⏱️
  374 suites      1 💤
    4 files        4 ❌

For more details on these failures, see this check.

Results for commit 11f060d.

♻️ This comment has been updated with latest results.

@datadog-wireapp
Copy link

datadog-wireapp bot commented May 2, 2025

Datadog Report

Branch report: feat/wire-cells-upgrade-service
Commit report: c35a2ea
Test service: wire-ios-mono

❌ 4 Failed (0 Known Flaky), 2783 Passed, 1 Skipped, 4m 36.22s Total Time

❌ Failed Tests (4)

  • testThatItReturnsAllKeysChangedWhenSnapshotDoesNotExist() - WireDataModelTests.SnapshotCenterTests - Details

    Expand for error
     SnapshotCenterTests.swift:209: XCTAssertEqual failed: ("["internalIsArchived", "lastUnreadKnockDate", "mlsGroupID", "internalEstimatedUnreadSelfReplyCount", "syncedMessageDestructionTimeout", "commitPendingProposalDate", "silencedChangedTimestamp", "groupType", "clearedTimeStamp", "lastReadServerTimeStamp", "mlsStatus", "cellName", "hasReadReceiptsEnabled", "needsToCalculateUnreadMessages", "legalHoldStatus", "accessRoleStringsV2", "lastServerTimeStamp", "modifiedKeys", "isSelfAnActiveMember", "nonTeamRoles", "userDefinedName", "language", "messageProtocol", "draftMessageData", "accessModeStrings", "localMessageDestructionTimeout", "normalizedUserDefinedName", "lastServerSyncedActiveParticipants", "migratedToMLS", "isForcedReadOnly", "archivedChangedTimestamp", "isPendingInitialFetch", "mlsVerificationStatus", "voiceChannel", "domain", "teamRemoteIdentifier_data", "primaryKey", "mutedStatus", "lastUnreadMissedCallDate", "conversationType", "draftMessageNonce", "internalEstimatedUnreadCount", "epoch", "privateChannelPermission", "teamRemoteIdentifier", "isDeletedRemotely", "needsToBeUpdatedFromBackend", "isPendingMetadataRefresh", "remoteIdentifier", "hiddenMessages", "hasUnreadUnsentMessage", "ciphersuite", "lastModifiedDate", "participantRoles", "needsToVerifyLegalHold", "securityLevel", "accessRoleString", "needsToDownloadRoles", "internalEstimatedUnreadSelfMentionCount", "remoteIdentifier_data", "labels", "wireCellsMessageAttachmentDrafts", "allMessages"]") is not equal to ("["archivedChangedTimestamp", "normalizedUserDefinedName", "voiceChannel", "internalIsArchived", "messageProtocol", "needsToDownloadRoles", "cellName", "teamRemoteIdentifier_data", "needsToCalculateUnreadMessages", "domain", "labels", "mutedStatus", "securityLevel", "lastServerTimeStamp", "hiddenMessages", "internalEstimatedUnreadSelfMentionCount", "needsToVerifyLegalHold", "lastReadServerTimeStamp", "teamRemoteIdentifier", "groupType", "lastUnreadMissedCallDate", "localMessageDestructionTimeout", "hasUnreadUnsentMessage", "draftMessageData", "lastServerSyncedActiveParticipants", "migratedToMLS", "primaryKey", "accessRoleStringsV2", "modifiedKeys", "mlsStatus", "isPendingInitialFetch", "epoch", "isDeletedRemotely", "needsToBeUpdatedFromBackend", "mlsGroupID", "lastModifiedDate", "nonTeamRoles", "isPendingMetadataRefresh", "allMessages", "hasReadReceiptsEnabled", "mlsVerificationStatus", "remoteIdentifier", "draftMessageNonce", "lastUnreadKnockDate", "language", "internalEstimatedUnreadCount", "isSelfAnActiveMember", "legalHoldStatus", "accessModeStrings", "ciphersuite", "silencedChangedTimestamp", "conversationType", "remoteIdentifier_data", "participantRoles", "privateChannelPermission", "clearedTimeStamp", "internalEstimatedUnreadSelfReplyCount", "accessRoleString", "isForcedReadOnly", "commitPendingProposalDate", "userDefinedName", "syncedMessageDestructionTimeout"]")
    
  • testThatItSnapshotsNilValues() - WireDataModelTests.SnapshotCenterTests

  • testThatItSnapshotsSetValues() - WireDataModelTests.SnapshotCenterTests - Details

    Expand for error
     SnapshotCenterTests.swift:167: XCTAssertEqual failed: ("["participantRoles": 0, "allMessages": 1, "nonTeamRoles": 0, "labels": 0, "lastServerSyncedActiveParticipants": 0, "wireCellsMessageAttachmentDrafts": 0, "hiddenMessages": 0]") is not equal to ("["nonTeamRoles": 0, "allMessages": 1, "labels": 0, "hiddenMessages": 0, "lastServerSyncedActiveParticipants": 0, "participantRoles": 0]")
    
  • testThatSpecialKeysAreNotPartOfTheLocallyModifiedKeys - WireDataModelTests.ZMConversationTests - Details

    Expand for error
     ZMConversationTests.m:285: ((conversation.keysTrackedForLocalModifications) equal to (expected)) failed: ("{(
         clearedTimeStamp,
         userDefinedName,
         archivedChangedTimestamp,
         cellName,
         lastReadServerTimeStamp,
         wireCellsMessageAttachmentDrafts,
         silencedChangedTimestamp,
         isForcedReadOnly
     )}") is not equal to ("{(
     ...
    

import XCTest

@testable @preconcurrency import WireCellsImplementation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted these tests as WireCellsService no longer exists

@samwyndham samwyndham requested review from a team, netbe, caldrian and jullianm and removed request for a team, netbe and caldrian May 5, 2025 11:47
Copy link
Contributor

@jullianm jullianm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some comments mostly about project structure since this PR is porting code from Android maybe there will be adjustments in future PRs to align to our codebase.

case failedToCreateWriteStream
}

public protocol WireCellsCellsRepository: Actor {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: shouldn't this live in WireDomain with the other repositories ? Also the naming is strange, could it be simplified to WireCellsRepository ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand our goal is to move more of these kinds of things to feature modules. I don't think there is any benefit of having this in a shared module when it will only be used by wire cells

Regarding naming, I agree it is strange but I essentially it is saying that it is the CellsRepository and belonging to the WireCells feature.

Copy link
Contributor

@samwyndham samwyndham May 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding naming, I took another look at this. In general I think Node is the better term than Cell as this is how things are referred to in the pydio API. Therefore I've renamed all the ...CellsCell... types. For example, WireCellsCellsRepositoryis nowWireCellsNodesRepository`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's as feature module, do we need prefix WireCells at all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmitrysimkin It's a good point. Perhaps everything that is not public can be without the WireCells. I will leave as is for now and rename as I work more on the feature.

case missingData(String)
}

package protocol WireCellsCellsAPI: Sendable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: this looks like an API interface, should this be moved to WireAPI ? Also the DTO returned objects is something I haven't seen in codebase yet.
Since this code is ported from Android, I'm note sure if it's just a first PR and things will change to adapt to our codebase in next PRs or is it some new code structure we adopt.

Also should it be renamed to WireCellsAPI ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. The way WireCells interacts with backend is different then the other parts of our app - in fact it doesn't talk to wires backend at all. Instead it uses:

  1. AWS SDK
  2. Cells SDK which is network client generated from the swagger specs.

Therefore I don't think WireAPI is the right place for it. Regarding DTO, Thomas basically took everything as is including naming strategies from Android. This was done for speed and the idea that if we don't understand something we can ask the Android developers. Personally I'm in favor of merging first and then adopting as needed and unifying patterns with our code base.

Regarding naming I will ask in the developer channel for opinions.

import WireCellsAPI
import WireDataModel

extension WireCellsMessageAttachmentsDraftsLocalStore: WireCellsMessageAttachmentDraftDAO {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: to be aligned with other local store stores protocol naming I guess it should be WireCellsMessageAttachmentDraftLocalStoreProtocol instead of WireCellsMessageAttachmentDraftDAO

Copy link
Contributor

@samwyndham samwyndham May 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you. But I'm in favor of merging soon and aligning terms in follow up PRs as we use these objects in practice and understanding better the DAO term. We are already using the concept of a DAO - see UpdateEventMigratorDAO but here that is the concrete implementation and the protocol is UpdateEventMigratorDAOProtocol.

So in summary, I'm in favor of aligning better with our exist codebase / future direction but would like to merge this PR quickly while spending some more time to think about these terms and probably discussing further in the architecture forum.

}

// sourcery: AutoMockable
public protocol WireCellsMessageAttachmentDraftRepository {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: should this be moved to WireDomain as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the same answer here as your point about WireCellsCellsRepository


/// Returns a pre-signed URL for the given S3 object key.
func getPreSignedUrl(objectKey: String) async throws -> String
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like another API interface, should it be moved to WireAPI (and probably renamed as well) ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned about, I don't think so because we don't actually talk to the WireAPI. See comment above. If that changes we should perhaps move this to WireAPI but otherwise it is very specific to this package so I think it is best to keep it here.

@samwyndham samwyndham requested review from jullianm and dmitrysimkin and removed request for dmitrysimkin May 7, 2025 09:05
Comment on lines +26 to +32
public var id: String {
"\(uuid.uuidString)@\(domain)"
}

public var pydioQualifiedID: String {
"\(uuid.uuidString)@\(domain)"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: sanity check, shouldpydioQualifiedID be same as id ? if so you can use reuse id for pydioQualifiedID

Comment on lines +33 to +34
// /!\ Will silently filter out nil values that could not be mapped to DTOs
nodes: nodes?.compactMap { $0.toDTO() } ?? []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: is this smth that needs to be addressed now or later?

import CellsSDK
package import Foundation

package struct WireCellsNodeDTO: Equatable, Hashable, Sendable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: why do we need DTO? Usually DTOs is not pass between layers, is it case here?

}

// sourcery: AutoMockable
public protocol WireCellsConversationDAO {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Why is it DAO? Looks like a use case?

Comment on lines +54 to +67
func addAttachment(
uuid: UUID,
versionID: String,
conversationID: WireCellsConversationID,
mimeType: String,
fileName: String,
fileSize: UInt64,
dataPath: String,
nodePath: String,
uploadStatus: WireCellsAttachmentUploadStatus,
assetWidth: UInt64?,
assetHeight: UInt64?,
assetDuration: UInt64?
) async throws(WireCellsMessageAttachmentDraftDAOError) -> WireCellsMessageAttachmentDraft
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: too many params, would be nice introduce input model

case failedToCreateWriteStream
}

public protocol WireCellsNodesRepository: Actor {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: looks like too many methods in one repo, better split them into smaller ones, wdyt @samwyndham ?

import Foundation
import WireCellsAPI

final class WireCellConversationDataSource: WireCellsNodeConversationRepository {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: naming is not consistent, e.g. we have Implementation for Client WireCellsAWSClientImplementation: WireCellsAWSClient but for repository protocol implementation we have DataSource. can we make it consistent?

Comment on lines +26 to +33
private enum Constants {
static let bucket = "io"
static let multipartChunkSize = 10 * 1024 * 1024
static let maxRegularUploadSize = 100 * 1024 * 1024
static let preSignedUrlExpiryInHours = 24
static let readAsyncChunkSize = 5 * 1024 * 1024
static let region = "us-east-1"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise : for adding constants

Copy link
Contributor

@jullianm jullianm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good overall, approving to unblock future tasks on WireCells, my assumption though is that things will be adjusted a little architecture wise as the feature moves forward

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants