From 07c8fe44574ffd8579eac06c915289616c812e54 Mon Sep 17 00:00:00 2001 From: Goncalo-FradeIOHK Date: Sun, 11 Dec 2022 14:12:22 +0000 Subject: [PATCH] feat(agent): implement send messages Fixes ATL-2708 --- Castor/Tests/PeerDIDCreationTests.swift | 3 +- Core/Sources/Helpers/First+AsyncAwait.swift | 14 + ...synAwait.swift => Future+AsyncAwait.swift} | 0 Domain/Sources/BBs/Pluto.swift | 6 +- Domain/Sources/Models/Message.swift | 10 +- .../Helpers/DIDCommMessage+DomainParse.swift | 2 +- Mercury/Sources/Helpers/Session.swift | 5 +- .../Domain/Providers/MessageProvider.swift | 2 + .../Sources/Domain/Stores/MessageStore.swift | 4 +- Pluto/Sources/Helpers/Message+Codable.swift | 7 +- .../DAO/CDMessageDAO+MessageProvider.swift | 18 ++ .../DAO/CDMessageDAO+MessageStore.swift | 25 +- .../Models/CDMessage+CoreDataProperties.swift | 1 + Pluto/Sources/PlutoImpl+Public.swift | 14 +- .../PrismPluto.xcdatamodel/contents | 1 + Pluto/Tests/CDMessagesDAOTests.swift | 10 +- .../ConnectionsManager.swift | 39 ++- .../ConnectionsManager/DIDCommProtocol.swift | 2 + PrismAgent/Sources/PrismAgent.swift | 1 - .../Connection/DIDCommConnectionRunner.swift | 5 +- .../Protocols/Pickup/PickupRunner.swift | 16 +- .../Protocols/Pickup/PrickupReceived.swift | 27 ++ .../Sources/Protocols/ProtocolTypes.swift | 1 + .../Helper/DIDCommConnection+Testing.swift | 5 + PrismAgent/Tests/PickupRunnerTests.swift | 2 +- .../project.pbxproj | 248 +++++++++++++++++- .../FuncionalitiesList.swift | 1 + .../AtalaPrismWalletDemo/Info.plist | 5 + .../SetupPrismAgent/SetupPrismAgentView.swift | 22 +- .../SetupPrismAgentViewModel.swift | 23 +- 30 files changed, 465 insertions(+), 54 deletions(-) create mode 100644 Core/Sources/Helpers/First+AsyncAwait.swift rename Core/Sources/Helpers/{Future+AsynAwait.swift => Future+AsyncAwait.swift} (100%) create mode 100644 PrismAgent/Sources/Protocols/Pickup/PrickupReceived.swift diff --git a/Castor/Tests/PeerDIDCreationTests.swift b/Castor/Tests/PeerDIDCreationTests.swift index fce39b91..355383a2 100644 --- a/Castor/Tests/PeerDIDCreationTests.swift +++ b/Castor/Tests/PeerDIDCreationTests.swift @@ -62,12 +62,11 @@ final class PeerDIDCreationTests: XCTestCase { let mypeerDID = DID( schema: "did", method: "peer", - methodId: "2.Ez6LScuRnbZAJaVthcL5RELq75EBK2sBmBxsSs98LKNeriHQJ.Vz6MkpeaW7DeptJW7pi2qNXTdCXeQV4EYpZnAouH1LrfHj6uf.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9rOHMtZGV2LmF0YWxhcHJpc20uaW8vcHJpc20tYWdlbnQvZGlkY29tbSIsInIiOltdLCJhIjpbImRpZGNvbW0vdjIiXX0" + methodId: "2.Ez6LSfuJvTtcmcFrjNYYSAuD32tMZWQUD2HYDfXrJqy3ui6MQ.Vz6MkoPyvuxAecSezqmL4ERE7eW2XPbiUEHRH9aqay6LA8Eqr.SeyJ0IjoiZG0iLCJzIjoiaHR0cDovL2hvc3QuZG9ja2VyLmludGVybmFsOjgwL2RpZGNvbW0vIiwiciI6W10sImEiOlsiZGlkY29tbS92MiJdfQ" ) let apollo = ApolloImpl() let castor = CastorImpl(apollo: apollo) let document = try await castor.resolveDID(did: mypeerDID) - print() } } diff --git a/Core/Sources/Helpers/First+AsyncAwait.swift b/Core/Sources/Helpers/First+AsyncAwait.swift new file mode 100644 index 00000000..30f815d0 --- /dev/null +++ b/Core/Sources/Helpers/First+AsyncAwait.swift @@ -0,0 +1,14 @@ +import Combine + +extension Publishers { + struct MissingOutputError: Error {} +} + +public extension Publishers.First where Failure == Error { + func await() async throws -> Output { + for try await output in values { + return output + } + throw Publishers.MissingOutputError() + } +} diff --git a/Core/Sources/Helpers/Future+AsynAwait.swift b/Core/Sources/Helpers/Future+AsyncAwait.swift similarity index 100% rename from Core/Sources/Helpers/Future+AsynAwait.swift rename to Core/Sources/Helpers/Future+AsyncAwait.swift diff --git a/Domain/Sources/BBs/Pluto.swift b/Domain/Sources/BBs/Pluto.swift index 3c853192..c683c3c1 100644 --- a/Domain/Sources/BBs/Pluto.swift +++ b/Domain/Sources/BBs/Pluto.swift @@ -9,8 +9,8 @@ public protocol Pluto { ) -> AnyPublisher func storePeerDID(did: DID, privateKeys: [PrivateKey]) -> AnyPublisher func storeDIDPair(holder: DID, other: DID, name: String) -> AnyPublisher - func storeMessage(message: Message) -> AnyPublisher - func storeMessages(messages: [Message]) -> AnyPublisher + func storeMessage(message: Message, direction: Message.Direction) -> AnyPublisher + func storeMessages(messages: [(Message, Message.Direction)]) -> AnyPublisher func storeMediator(peer: DID, routingDID: DID, mediatorDID: DID) -> AnyPublisher func storeCredential(credential: VerifiableCredential) -> AnyPublisher @@ -31,6 +31,8 @@ public protocol Pluto { func getAllMessages() -> AnyPublisher<[Message], Error> func getAllMessages(did: DID) -> AnyPublisher<[Message], Error> + func getAllMessagesSent() -> AnyPublisher<[Message], Error> + func getAllMessagesReceived() -> AnyPublisher<[Message], Error> func getAllMessagesSentTo(did: DID) -> AnyPublisher<[Message], Error> func getAllMessagesReceivedFrom(did: DID) -> AnyPublisher<[Message], Error> func getAllMessagesOfType(type: String, relatedWithDID: DID?) -> AnyPublisher<[Message], Error> diff --git a/Domain/Sources/Models/Message.swift b/Domain/Sources/Models/Message.swift index 02f65cf9..7442c76b 100644 --- a/Domain/Sources/Models/Message.swift +++ b/Domain/Sources/Models/Message.swift @@ -1,6 +1,11 @@ import Foundation public struct Message { + public enum Direction: String { + case sent + case received + } + public let id: String public let piuri: String public let from: DID? @@ -14,6 +19,7 @@ public struct Message { public let thid: String? public let pthid: String? public let ack: [String] + public let direction: Direction public init( id: String = UUID().uuidString, @@ -28,7 +34,8 @@ public struct Message { attachments: [AttachmentDescriptor] = [], thid: String? = nil, pthid: String? = nil, - ack: [String] = [] + ack: [String] = [], + direction: Direction = .received ) { self.id = id self.piuri = piuri @@ -43,5 +50,6 @@ public struct Message { self.thid = thid self.pthid = pthid self.ack = ack + self.direction = direction } } diff --git a/Mercury/Sources/Helpers/DIDCommMessage+DomainParse.swift b/Mercury/Sources/Helpers/DIDCommMessage+DomainParse.swift index e580e3e8..36b06987 100644 --- a/Mercury/Sources/Helpers/DIDCommMessage+DomainParse.swift +++ b/Mercury/Sources/Helpers/DIDCommMessage+DomainParse.swift @@ -101,7 +101,7 @@ extension DIDCommxSwift.AttachmentData { case let .links(value): return AttachmentLinkData(links: value.links, hash: value.hash) case let .json(value): - guard let jsonData = Data(fromBase64URL: value.json) else { + guard let jsonData = value.json.data(using: .utf8) else { throw MercuryError.unknownAttachmentDataError } return AttachmentJsonData(data: jsonData) diff --git a/Mercury/Sources/Helpers/Session.swift b/Mercury/Sources/Helpers/Session.swift index 8781a69a..3e1bb769 100644 --- a/Mercury/Sources/Helpers/Session.swift +++ b/Mercury/Sources/Helpers/Session.swift @@ -21,7 +21,7 @@ struct SessionManager { headers: [String: String] = [:], parameters: [String: String] = [:] ) async throws -> Data? { - try await call(request: try makeRequest(url: url, method: .post, body: body, parameters: parameters)) + try await call(request: try makeRequest(url: url, method: .post, body: body, headers: headers, parameters: parameters)) } private func call(request: URLRequest) async throws -> Data? { @@ -45,7 +45,8 @@ struct SessionManager { headers: [String: String] = [:], parameters: [String: String] ) throws -> URLRequest { - var composition = URLComponents(url: url, resolvingAgainstBaseURL: true) + let urlParsed = URL(string: url.absoluteString.replacingOccurrences(of: "http://host.docker.internal:8080", with: "http://localhost:8080"))! + var composition = URLComponents(url: urlParsed, resolvingAgainstBaseURL: true) if !parameters.isEmpty { composition?.queryItems = parameters.map { URLQueryItem(name: $0, value: $1) } } diff --git a/Pluto/Sources/Domain/Providers/MessageProvider.swift b/Pluto/Sources/Domain/Providers/MessageProvider.swift index f1aeafee..982e1833 100644 --- a/Pluto/Sources/Domain/Providers/MessageProvider.swift +++ b/Pluto/Sources/Domain/Providers/MessageProvider.swift @@ -5,6 +5,8 @@ import Foundation protocol MessageProvider { func getAll() -> AnyPublisher<[Message], Error> func getAllFor(did: DID) -> AnyPublisher<[Message], Error> + func getAllSent() -> AnyPublisher<[Message], Error> + func getAllReceived() -> AnyPublisher<[Message], Error> func getAllSentTo(did: DID) -> AnyPublisher<[Message], Error> func getAllReceivedFrom(did: DID) -> AnyPublisher<[Message], Error> func getAllOfType(type: String, relatedWithDID: DID?) -> AnyPublisher<[Message], Error> diff --git a/Pluto/Sources/Domain/Stores/MessageStore.swift b/Pluto/Sources/Domain/Stores/MessageStore.swift index a964461e..8c6b2e0c 100644 --- a/Pluto/Sources/Domain/Stores/MessageStore.swift +++ b/Pluto/Sources/Domain/Stores/MessageStore.swift @@ -3,8 +3,8 @@ import Domain import Foundation protocol MessageStore { - func addMessages(messages: [Message]) -> AnyPublisher - func addMessage(msg: Message) -> AnyPublisher + func addMessages(messages: [(Message, Message.Direction)]) -> AnyPublisher + func addMessage(msg: Message, direction: Message.Direction) -> AnyPublisher func removeMessage(id: String) -> AnyPublisher func removeAll() -> AnyPublisher } diff --git a/Pluto/Sources/Helpers/Message+Codable.swift b/Pluto/Sources/Helpers/Message+Codable.swift index f83db594..39a1bfdb 100644 --- a/Pluto/Sources/Helpers/Message+Codable.swift +++ b/Pluto/Sources/Helpers/Message+Codable.swift @@ -16,6 +16,7 @@ struct CodableMessage: Codable { case pthid case ack case body + case direction } let message: Message @@ -30,6 +31,7 @@ struct CodableMessage: Codable { try container.encode(message.expiresTimePlus, forKey: .expiresTimePlus) try container.encode(message.attachments, forKey: .attachments) try container.encode(message.ack, forKey: .ack) + try container.encode(message.direction.rawValue, forKey: .direction) try message.from.map { try container.encode(CodableDID(did: $0), forKey: .from) } try message.to.map { try container.encode(CodableDID(did: $0), forKey: .to) } try message.fromPrior.map { try container.encode($0, forKey: .fromPrior) } @@ -56,6 +58,8 @@ struct CodableMessage: Codable { let fromPrior = try? container.decode(String.self, forKey: .fromPrior) let thid = try? container.decode(String.self, forKey: .thid) let pthid = try? container.decode(String.self, forKey: .pthid) + let directionRaw = try? container.decode(String.self, forKey: .direction) + let direction = directionRaw.flatMap { Message.Direction(rawValue: $0) } self.init(message: .init( id: id, @@ -70,7 +74,8 @@ struct CodableMessage: Codable { attachments: attachments, thid: thid, pthid: pthid, - ack: ack + ack: ack, + direction: direction ?? .sent )) } } diff --git a/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageProvider.swift b/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageProvider.swift index 3015b946..bc44fdd8 100644 --- a/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageProvider.swift +++ b/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageProvider.swift @@ -18,6 +18,24 @@ extension CDMessageDAO: MessageProvider { .eraseToAnyPublisher() } + func getAllSent() -> AnyPublisher<[Message], Error> { + fetchController( + predicate: NSPredicate(format: "(direction == %@)", "sent"), + context: readContext + ) + .tryMap { try $0.map { try $0.toDomain() } } + .eraseToAnyPublisher() + } + + func getAllReceived() -> AnyPublisher<[Message], Error> { + fetchController( + predicate: NSPredicate(format: "(direction == %@)", "received"), + context: readContext + ) + .tryMap { try $0.map { try $0.toDomain() } } + .eraseToAnyPublisher() + } + func getAllSentTo(did: DID) -> AnyPublisher<[Message], Error> { fetchController( predicate: NSPredicate(format: "to == %@", did.string), diff --git a/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageStore.swift b/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageStore.swift index dd0b3b5f..f4bb9ebb 100644 --- a/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageStore.swift +++ b/Pluto/Sources/PersistentStorage/DAO/CDMessageDAO+MessageStore.swift @@ -3,28 +3,22 @@ import CoreData import Domain extension CDMessageDAO: MessageStore { - func addMessages(messages: [Message]) -> AnyPublisher { + func addMessages(messages: [(Message, Message.Direction)]) -> AnyPublisher { messages .publisher - .flatMap { self.addMessage(msg: $0) } + .flatMap { self.addMessage(msg: $0.0, direction: $0.1) } .eraseToAnyPublisher() } - func addMessage(msg: Message) -> AnyPublisher { - guard - let fromDID = msg.from, - let toDID = msg.to - else { - return Fail(error: PlutoError.messageMissingFromOrToDIDError).eraseToAnyPublisher() - } + func addMessage(msg: Message, direction: Message.Direction) -> AnyPublisher { return pairDAO .fetchController( predicate: NSPredicate( format: "(holderDID.did == %@) OR (holderDID.did == %@) OR (did == %@) OR (did == %@)", - fromDID.string, - toDID.string, - fromDID.string, - toDID.string + msg.from?.string ?? "", + msg.to?.string ?? "", + msg.from?.string ?? "", + msg.to?.string ?? "" ), context: writeContext ) @@ -35,7 +29,7 @@ extension CDMessageDAO: MessageStore { msg.id, context: writeContext ) { cdobj, _ in - try cdobj.fromDomain(msg: msg, pair: pair) + try cdobj.fromDomain(msg: msg, direction: direction, pair: pair) } } .map { _ in } @@ -52,7 +46,7 @@ extension CDMessageDAO: MessageStore { } private extension CDMessage { - func fromDomain(msg: Message, pair: CDDIDPair?) throws { + func fromDomain(msg: Message, direction: Message.Direction, pair: CDDIDPair?) throws { self.messageId = msg.id self.from = msg.from?.string self.to = msg.to?.string @@ -60,5 +54,6 @@ private extension CDMessage { self.dataJson = try JSONEncoder().encode(CodableMessage(message: msg)) self.createdTime = msg.createdTime self.pair = pair + self.direction = direction.rawValue } } diff --git a/Pluto/Sources/PersistentStorage/Models/CDMessage+CoreDataProperties.swift b/Pluto/Sources/PersistentStorage/Models/CDMessage+CoreDataProperties.swift index e61d3cd6..e5e2bd63 100644 --- a/Pluto/Sources/PersistentStorage/Models/CDMessage+CoreDataProperties.swift +++ b/Pluto/Sources/PersistentStorage/Models/CDMessage+CoreDataProperties.swift @@ -13,6 +13,7 @@ extension CDMessage { @NSManaged var from: String? @NSManaged var to: String? @NSManaged var thid: String? + @NSManaged var direction: String? @NSManaged var pair: CDDIDPair? } diff --git a/Pluto/Sources/PlutoImpl+Public.swift b/Pluto/Sources/PlutoImpl+Public.swift index 8582706e..66fa63b9 100644 --- a/Pluto/Sources/PlutoImpl+Public.swift +++ b/Pluto/Sources/PlutoImpl+Public.swift @@ -14,11 +14,11 @@ extension PlutoImpl: Pluto { pairDIDDao.addDIDPair(holder: holder, other: other, name: name) } - public func storeMessage(message: Message) -> AnyPublisher { - messageDao.addMessage(msg: message) + public func storeMessage(message: Message, direction: Message.Direction) -> AnyPublisher { + messageDao.addMessage(msg: message, direction: direction) } - public func storeMessages(messages: [Message]) -> AnyPublisher { + public func storeMessages(messages: [(Message, Message.Direction)]) -> AnyPublisher { messageDao.addMessages(messages: messages) } @@ -90,6 +90,14 @@ extension PlutoImpl: Pluto { messageDao.getAllFor(did: did) } + public func getAllMessagesSent() -> AnyPublisher<[Message], Error> { + messageDao.getAllSent() + } + + public func getAllMessagesReceived() -> AnyPublisher<[Message], Error> { + messageDao.getAllReceived() + } + public func getAllMessagesSentTo(did: DID) -> AnyPublisher<[Message], Error> { messageDao.getAllSentTo(did: did) } diff --git a/Pluto/Sources/Resources/PrismPluto.xcdatamodeld/PrismPluto.xcdatamodel/contents b/Pluto/Sources/Resources/PrismPluto.xcdatamodeld/PrismPluto.xcdatamodel/contents index 264bceb8..591bc86f 100644 --- a/Pluto/Sources/Resources/PrismPluto.xcdatamodeld/PrismPluto.xcdatamodel/contents +++ b/Pluto/Sources/Resources/PrismPluto.xcdatamodeld/PrismPluto.xcdatamodel/contents @@ -27,6 +27,7 @@ + diff --git a/Pluto/Tests/CDMessagesDAOTests.swift b/Pluto/Tests/CDMessagesDAOTests.swift index 3dc657e1..ea345e8c 100644 --- a/Pluto/Tests/CDMessagesDAOTests.swift +++ b/Pluto/Tests/CDMessagesDAOTests.swift @@ -51,7 +51,7 @@ final class CDMessagesDAOTests: XCTestCase { ) } .flatMap { - dao.addMessage(msg: testMessage) + dao.addMessage(msg: testMessage, direction: .received) } .flatMap { dao.getMessage(id: testMessage.id).first() @@ -98,10 +98,10 @@ final class CDMessagesDAOTests: XCTestCase { ) } .flatMap { - dao.addMessage(msg: testMessage) + dao.addMessage(msg: testMessage, direction: .received) } .flatMap { - dao.addMessage(msg: testMessage) + dao.addMessage(msg: testMessage, direction: .received) } .flatMap { dao.getAll().first() @@ -167,10 +167,10 @@ final class CDMessagesDAOTests: XCTestCase { ) } .flatMap { - dao.addMessage(msg: testMessage1) + dao.addMessage(msg: testMessage1, direction: .received) } .flatMap { - dao.addMessage(msg: testMessage2) + dao.addMessage(msg: testMessage2, direction: .received) } .flatMap { dao.getAllFor(did: testHolderDID2).first() diff --git a/PrismAgent/Sources/ConnectionsManager/ConnectionsManager.swift b/PrismAgent/Sources/ConnectionsManager/ConnectionsManager.swift index 64e5d8ee..eb8c22c5 100644 --- a/PrismAgent/Sources/ConnectionsManager/ConnectionsManager.swift +++ b/PrismAgent/Sources/ConnectionsManager/ConnectionsManager.swift @@ -137,6 +137,17 @@ class ConnectionsManagerImpl: ConnectionsManager { } extension ConnectionsManagerImpl: DIDCommConnection { + func sendMessage(_ message: Message) async throws -> Message? { + let mercury = self.mercury + return try await pluto + .storeMessage(message: message, direction: .sent) + .flatMap { + Future { try await mercury.sendMessageParseMessage(msg: message) } + } + .first() + .await() + } + func awaitMessages() async throws -> [Message] { let stream: AnyPublisher<[Message], Error> = try awaitMessages() @@ -164,9 +175,12 @@ extension ConnectionsManagerImpl: DIDCommConnection { } .flatMap { messages in pluto - .storeMessages(messages: messages) + .storeMessages(messages: messages.map { ($0.message, .received) }) .map { messages } } + .flatMap { messages in + pickupReceivedMessages(messages: messages, mediator: mediator, mercury: mercury) + } .eraseToAnyPublisher() } @@ -227,3 +241,26 @@ extension ConnectionsManagerImpl: DIDCommConnection { .eraseToAnyPublisher() } } + +private func pickupReceivedMessages( + messages: [(Message, String)], + mediator: ConnectionsManagerImpl.Mediator, + mercury: Mercury +) -> AnyPublisher<[Message], Error> { + if messages.count > 0 { + return Future { + let message = try PickUpReceived( + from: mediator.peerDID, + to: mediator.mediatorDID, + body: .init(messageIdList: messages.map { $0.1 }) + ).makeMessage() + return try await mercury.sendMessage(msg: message) + } + .map { _ in messages.map { $0.0 } } + .eraseToAnyPublisher() + } else { + return Just(messages.map { $0.0 }) + .tryMap { $0 } + .eraseToAnyPublisher() + } +} diff --git a/PrismAgent/Sources/ConnectionsManager/DIDCommProtocol.swift b/PrismAgent/Sources/ConnectionsManager/DIDCommProtocol.swift index 1ed89b99..51628ffc 100644 --- a/PrismAgent/Sources/ConnectionsManager/DIDCommProtocol.swift +++ b/PrismAgent/Sources/ConnectionsManager/DIDCommProtocol.swift @@ -4,6 +4,8 @@ import Foundation protocol DIDCommConnection { func awaitMessages() async throws -> [Message] func awaitMessageResponse(id: String) async throws -> Message? + @discardableResult + func sendMessage(_ message: Message) async throws -> Message? } protocol ConnectionsManager { diff --git a/PrismAgent/Sources/PrismAgent.swift b/PrismAgent/Sources/PrismAgent.swift index 6795dd67..5d063a22 100644 --- a/PrismAgent/Sources/PrismAgent.swift +++ b/PrismAgent/Sources/PrismAgent.swift @@ -198,7 +198,6 @@ public class PrismAgent { updateMediator: true ) let pair = try await DIDCommConnectionRunner( - mercury: mercury, invitationMessage: invitation, ownDID: ownDID, connection: connectionManager diff --git a/PrismAgent/Sources/Protocols/Connection/DIDCommConnectionRunner.swift b/PrismAgent/Sources/Protocols/Connection/DIDCommConnectionRunner.swift index fbbbad45..7b4624c2 100644 --- a/PrismAgent/Sources/Protocols/Connection/DIDCommConnectionRunner.swift +++ b/PrismAgent/Sources/Protocols/Connection/DIDCommConnectionRunner.swift @@ -2,19 +2,16 @@ import Domain import Foundation class DIDCommConnectionRunner { - private let mercury: Mercury private let invitationMessage: OutOfBandInvitation private let ownDID: DID private let connection: DIDCommConnection private var request: HandshakeRequest? init( - mercury: Mercury, invitationMessage: OutOfBandInvitation, ownDID: DID, connection: DIDCommConnection ) { - self.mercury = mercury self.invitationMessage = invitationMessage self.ownDID = ownDID self.connection = connection @@ -22,7 +19,7 @@ class DIDCommConnectionRunner { func run() async throws -> DIDPair { let request = try HandshakeRequest(inviteMessage: invitationMessage, from: ownDID) - try await mercury.sendMessage(msg: try request.makeMessage()) + try await connection.sendMessage(try request.makeMessage()) guard let message = try await connection.awaitMessageResponse(id: request.id), message.piuri == ProtocolTypes.didcommconnectionResponse.rawValue diff --git a/PrismAgent/Sources/Protocols/Pickup/PickupRunner.swift b/PrismAgent/Sources/Protocols/Pickup/PickupRunner.swift index 19c663d3..6903fc59 100644 --- a/PrismAgent/Sources/Protocols/Pickup/PickupRunner.swift +++ b/PrismAgent/Sources/Protocols/Pickup/PickupRunner.swift @@ -22,13 +22,19 @@ class PickupRunner { self.mercury = mercury } - func run() async throws -> [Message] { + func run() async throws -> [(message: Message, attachmentId: String)] { switch message { case let .delivery(message): - return try await message.attachments.compactMap { - ($0.data as? AttachmentBase64)?.base64 - }.asyncMap { - try await mercury.unpackMessage(msg: $0) + return try await message.attachments.compactMap { attachment in + switch attachment.data { + case let json as AttachmentJsonData: + return String(data: json.data, encoding: .utf8).map { ($0, attachment.id) } + default: + return nil + } + } + .asyncMap { messageString, id in + (try await mercury.unpackMessage(msg: messageString), id) } case .status: return [] diff --git a/PrismAgent/Sources/Protocols/Pickup/PrickupReceived.swift b/PrismAgent/Sources/Protocols/Pickup/PrickupReceived.swift new file mode 100644 index 00000000..e3962557 --- /dev/null +++ b/PrismAgent/Sources/Protocols/Pickup/PrickupReceived.swift @@ -0,0 +1,27 @@ +import Core +import Domain +import Foundation + +struct PickUpReceived { + struct Body: Codable { + let messageIdList: [String] + + init(messageIdList: [String] = []) { + self.messageIdList = messageIdList + } + } + + let from: DID + let to: DID + let body: Body + + func makeMessage() throws -> Message { + let body = try JSONEncoder.didComm().encode(body) + return Message( + piuri: ProtocolTypes.pickupReceived.rawValue, + from: from, + to: to, + body: body + ) + } +} diff --git a/PrismAgent/Sources/Protocols/ProtocolTypes.swift b/PrismAgent/Sources/Protocols/ProtocolTypes.swift index 37a6f9c1..edd9eeb7 100644 --- a/PrismAgent/Sources/Protocols/ProtocolTypes.swift +++ b/PrismAgent/Sources/Protocols/ProtocolTypes.swift @@ -20,4 +20,5 @@ enum ProtocolTypes: String { case pickupRequest = "https://didcomm.org/messagepickup/3.0/delivery-request" case pickupDelivery = "https://didcomm.org/messagepickup/3.0/delivery" case pickupStatus = "https://didcomm.org/messagepickup/3.0/status" + case pickupReceived = "https://didcomm.org/messagepickup/3.0/messages-received" } diff --git a/PrismAgent/Tests/Helper/DIDCommConnection+Testing.swift b/PrismAgent/Tests/Helper/DIDCommConnection+Testing.swift index 589bddc6..0f0ddd7f 100644 --- a/PrismAgent/Tests/Helper/DIDCommConnection+Testing.swift +++ b/PrismAgent/Tests/Helper/DIDCommConnection+Testing.swift @@ -4,6 +4,11 @@ import Domain class ConnectionStub: DIDCommConnection, ConnectionsManager { var awaitMessagesResponse: [Message]! var awaitMessageResponse: Message? + var sendMessageResponse: Message? + + func sendMessage(_ message: Message) async throws -> Message? { + sendMessageResponse + } func awaitMessages() async throws -> [Message] { awaitMessagesResponse diff --git a/PrismAgent/Tests/PickupRunnerTests.swift b/PrismAgent/Tests/PickupRunnerTests.swift index cd45af1e..115faea4 100644 --- a/PrismAgent/Tests/PickupRunnerTests.swift +++ b/PrismAgent/Tests/PickupRunnerTests.swift @@ -31,7 +31,7 @@ final class PickupRunnerTests: XCTestCase { let runner = try PickupRunner(message: message, mercury: mercury) let parsedMessages = try await runner.run() - XCTAssertEqual(parsedMessages, messagesExamples) + XCTAssertEqual(parsedMessages.map { $0.message }, messagesExamples) } func testWhenReceiveNotDeliveryMessageThenThrowError() async throws { diff --git a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo.xcodeproj/project.pbxproj b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo.xcodeproj/project.pbxproj index 9df5c9e2..38786ffd 100644 --- a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo.xcodeproj/project.pbxproj +++ b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + EE0E1FB129473B10003CD7D5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EE0E1FAC29473B10003CD7D5 /* Assets.xcassets */; }; + EE0E1FB229473B10003CD7D5 /* SteradianBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = EE0E1FAE29473B10003CD7D5 /* SteradianBold.otf */; }; + EE0E1FB329473B10003CD7D5 /* SteradianMedium.otf in Resources */ = {isa = PBXBuildFile; fileRef = EE0E1FAF29473B10003CD7D5 /* SteradianMedium.otf */; }; + EE0E1FB429473B10003CD7D5 /* SteradianRegular.otf in Resources */ = {isa = PBXBuildFile; fileRef = EE0E1FB029473B10003CD7D5 /* SteradianRegular.otf */; }; EE3813502938D5B100A3A710 /* Apollo in Frameworks */ = {isa = PBXBuildFile; productRef = EE38134F2938D5B100A3A710 /* Apollo */; }; EE3813522938D5B100A3A710 /* Authenticate in Frameworks */ = {isa = PBXBuildFile; productRef = EE3813512938D5B100A3A710 /* Authenticate */; }; EE3813542938D5B100A3A710 /* Builders in Frameworks */ = {isa = PBXBuildFile; productRef = EE3813532938D5B100A3A710 /* Builders */; }; @@ -16,11 +20,43 @@ EE38135C2938D5B100A3A710 /* Pluto in Frameworks */ = {isa = PBXBuildFile; productRef = EE38135B2938D5B100A3A710 /* Pluto */; }; EE38135E2938D5B100A3A710 /* Pollux in Frameworks */ = {isa = PBXBuildFile; productRef = EE38135D2938D5B100A3A710 /* Pollux */; }; EE3813602938D5B100A3A710 /* PrismAgent in Frameworks */ = {isa = PBXBuildFile; productRef = EE38135F2938D5B100A3A710 /* PrismAgent */; }; + EE6C38D229462516006CD2D3 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38D129462516006CD2D3 /* MainView.swift */; }; + EE6C38D429462522006CD2D3 /* MainViewRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38D329462522006CD2D3 /* MainViewRouter.swift */; }; + EE6C38D7294625B3006CD2D3 /* ProfileHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38D6294625B3006CD2D3 /* ProfileHeaderView.swift */; }; + EE6C38DA29462659006CD2D3 /* SpecificRoundedRect.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38D929462659006CD2D3 /* SpecificRoundedRect.swift */; }; + EE6C38DC294626E1006CD2D3 /* String+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38DB294626E1006CD2D3 /* String+extensions.swift */; }; + EE6C38E3294627B2006CD2D3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EE6C38E2294627B2006CD2D3 /* Localizable.strings */; }; + EE6C38E529462822006CD2D3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = EE6C38E429462822006CD2D3 /* Localizable.stringsdict */; }; + EE6C38E829462A6F006CD2D3 /* DashboardTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38E729462A6F006CD2D3 /* DashboardTabViewController.swift */; }; + EE6C38EA29467A36006CD2D3 /* DashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38E929467A36006CD2D3 /* DashboardView.swift */; }; + EE6C38EC29467A7A006CD2D3 /* ClearFullCoverModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38EB29467A7A006CD2D3 /* ClearFullCoverModifier.swift */; }; + EE6C38EE29467A9D006CD2D3 /* DisablePreferenceKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38ED29467A9D006CD2D3 /* DisablePreferenceKey.swift */; }; + EE6C38F029468196006CD2D3 /* DIContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C38EF29468196006CD2D3 /* DIContainer.swift */; }; + EE6C39012946827B006CD2D3 /* ComponentContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C39002946827B006CD2D3 /* ComponentContainer.swift */; }; + EE6C390329468288006CD2D3 /* Builder.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C390229468288006CD2D3 /* Builder.swift */; }; + EE6C390529468309006CD2D3 /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C390429468309006CD2D3 /* LazyView.swift */; }; + EE6C39072946834F006CD2D3 /* RootPresentationMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C39062946834F006CD2D3 /* RootPresentationMode.swift */; }; + EE6C3909294683C4006CD2D3 /* DashboardRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C3908294683C4006CD2D3 /* DashboardRouter.swift */; }; + EE6C390B294683D5006CD2D3 /* DashboardBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C390A294683D5006CD2D3 /* DashboardBuilder.swift */; }; + EE6C39152946851D006CD2D3 /* QRScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C390F2946851D006CD2D3 /* QRScannerView.swift */; }; + EE6C39162946851D006CD2D3 /* CameraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C39102946851D006CD2D3 /* CameraViewController.swift */; }; + EE6C39172946851D006CD2D3 /* QRCodeScannerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C39112946851D006CD2D3 /* QRCodeScannerBuilder.swift */; }; + EE6C39182946851D006CD2D3 /* QRCodeScannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C39122946851D006CD2D3 /* QRCodeScannerView.swift */; }; + EE6C39192946851D006CD2D3 /* QRCodeScannerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C39132946851D006CD2D3 /* QRCodeScannerRouter.swift */; }; + EE6C391A2946851D006CD2D3 /* QRCodeScannerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C39142946851D006CD2D3 /* QRCodeScannerViewModel.swift */; }; + EE6C393129468533006CD2D3 /* ActivityListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C392229468533006CD2D3 /* ActivityListView.swift */; }; + EE6C393429468533006CD2D3 /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C392529468533006CD2D3 /* HomeViewModel.swift */; }; + EE6C393529468533006CD2D3 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C392629468533006CD2D3 /* HomeView.swift */; }; + EE6C393729468533006CD2D3 /* HomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C392829468533006CD2D3 /* HomeRouter.swift */; }; + EE6C393829468533006CD2D3 /* HomeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C392929468533006CD2D3 /* HomeBuilder.swift */; }; + EE6C393929468533006CD2D3 /* HomeState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C392A29468533006CD2D3 /* HomeState.swift */; }; + EE6C393C29468614006CD2D3 /* EmptyNavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C393B29468614006CD2D3 /* EmptyNavigationLink.swift */; }; + EE6C393E2946901D006CD2D3 /* DashboardViewModelImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C393D2946901D006CD2D3 /* DashboardViewModelImpl.swift */; }; + EE6C39402946931E006CD2D3 /* Array+Zipped.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE6C393F2946931E006CD2D3 /* Array+Zipped.swift */; }; EEB7D32229420180006E076D /* SetupPrismAgentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEB7D32129420180006E076D /* SetupPrismAgentView.swift */; }; EEB7D3242942018C006E076D /* SetupPrismAgentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEB7D3232942018C006E076D /* SetupPrismAgentViewModel.swift */; }; EEE61FBA2937CA280053AE52 /* AtalaPrismWalletDemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE61FB92937CA280053AE52 /* AtalaPrismWalletDemoApp.swift */; }; EEE61FBC2937CA280053AE52 /* FuncionalitiesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE61FBB2937CA280053AE52 /* FuncionalitiesList.swift */; }; - EEE61FBE2937CA2A0053AE52 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EEE61FBD2937CA2A0053AE52 /* Assets.xcassets */; }; EEE61FC12937CA2A0053AE52 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EEE61FC02937CA2A0053AE52 /* Preview Assets.xcassets */; }; EEE61FDD2937CD7A0053AE52 /* SeedFuncionalitiesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE61FDC2937CD7A0053AE52 /* SeedFuncionalitiesView.swift */; }; EEE61FE02937CEAA0053AE52 /* SeedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE61FDF2937CEAA0053AE52 /* SeedViewModel.swift */; }; @@ -34,13 +70,49 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + EE0E1FAC29473B10003CD7D5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + EE0E1FAE29473B10003CD7D5 /* SteradianBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = SteradianBold.otf; sourceTree = ""; }; + EE0E1FAF29473B10003CD7D5 /* SteradianMedium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = SteradianMedium.otf; sourceTree = ""; }; + EE0E1FB029473B10003CD7D5 /* SteradianRegular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = SteradianRegular.otf; sourceTree = ""; }; EE38134E2938D55D00A3A710 /* atala-prism-swift-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "atala-prism-swift-sdk"; path = ../..; sourceTree = ""; }; + EE6C38D129462516006CD2D3 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; + EE6C38D329462522006CD2D3 /* MainViewRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewRouter.swift; sourceTree = ""; }; + EE6C38D6294625B3006CD2D3 /* ProfileHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ProfileHeaderView.swift; path = ../../Profile/ProfileHeaderView.swift; sourceTree = ""; }; + EE6C38D929462659006CD2D3 /* SpecificRoundedRect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpecificRoundedRect.swift; sourceTree = ""; }; + EE6C38DB294626E1006CD2D3 /* String+extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+extensions.swift"; sourceTree = ""; }; + EE6C38E2294627B2006CD2D3 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; }; + EE6C38E429462822006CD2D3 /* Localizable.stringsdict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.stringsdict; path = Localizable.stringsdict; sourceTree = ""; }; + EE6C38E729462A6F006CD2D3 /* DashboardTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardTabViewController.swift; sourceTree = ""; }; + EE6C38E929467A36006CD2D3 /* DashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardView.swift; sourceTree = ""; }; + EE6C38EB29467A7A006CD2D3 /* ClearFullCoverModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearFullCoverModifier.swift; sourceTree = ""; }; + EE6C38ED29467A9D006CD2D3 /* DisablePreferenceKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisablePreferenceKey.swift; sourceTree = ""; }; + EE6C38EF29468196006CD2D3 /* DIContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DIContainer.swift; sourceTree = ""; }; + EE6C39002946827B006CD2D3 /* ComponentContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComponentContainer.swift; sourceTree = ""; }; + EE6C390229468288006CD2D3 /* Builder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Builder.swift; sourceTree = ""; }; + EE6C390429468309006CD2D3 /* LazyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = ""; }; + EE6C39062946834F006CD2D3 /* RootPresentationMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootPresentationMode.swift; sourceTree = ""; }; + EE6C3908294683C4006CD2D3 /* DashboardRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardRouter.swift; sourceTree = ""; }; + EE6C390A294683D5006CD2D3 /* DashboardBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardBuilder.swift; sourceTree = ""; }; + EE6C390F2946851D006CD2D3 /* QRScannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRScannerView.swift; sourceTree = ""; }; + EE6C39102946851D006CD2D3 /* CameraViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraViewController.swift; sourceTree = ""; }; + EE6C39112946851D006CD2D3 /* QRCodeScannerBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeScannerBuilder.swift; sourceTree = ""; }; + EE6C39122946851D006CD2D3 /* QRCodeScannerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeScannerView.swift; sourceTree = ""; }; + EE6C39132946851D006CD2D3 /* QRCodeScannerRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeScannerRouter.swift; sourceTree = ""; }; + EE6C39142946851D006CD2D3 /* QRCodeScannerViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeScannerViewModel.swift; sourceTree = ""; }; + EE6C392229468533006CD2D3 /* ActivityListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityListView.swift; sourceTree = ""; }; + EE6C392529468533006CD2D3 /* HomeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = ""; }; + EE6C392629468533006CD2D3 /* HomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; + EE6C392829468533006CD2D3 /* HomeRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeRouter.swift; sourceTree = ""; }; + EE6C392929468533006CD2D3 /* HomeBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeBuilder.swift; sourceTree = ""; }; + EE6C392A29468533006CD2D3 /* HomeState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeState.swift; sourceTree = ""; }; + EE6C393B29468614006CD2D3 /* EmptyNavigationLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyNavigationLink.swift; sourceTree = ""; }; + EE6C393D2946901D006CD2D3 /* DashboardViewModelImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardViewModelImpl.swift; sourceTree = ""; }; + EE6C393F2946931E006CD2D3 /* Array+Zipped.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Zipped.swift"; sourceTree = ""; }; EEB7D32129420180006E076D /* SetupPrismAgentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPrismAgentView.swift; sourceTree = ""; }; EEB7D3232942018C006E076D /* SetupPrismAgentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPrismAgentViewModel.swift; sourceTree = ""; }; EEE61FB62937CA280053AE52 /* AtalaPrismWalletDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AtalaPrismWalletDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; EEE61FB92937CA280053AE52 /* AtalaPrismWalletDemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtalaPrismWalletDemoApp.swift; sourceTree = ""; }; EEE61FBB2937CA280053AE52 /* FuncionalitiesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FuncionalitiesList.swift; sourceTree = ""; }; - EEE61FBD2937CA2A0053AE52 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; EEE61FC02937CA2A0053AE52 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; EEE61FDC2937CD7A0053AE52 /* SeedFuncionalitiesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedFuncionalitiesView.swift; sourceTree = ""; }; EEE61FDF2937CEAA0053AE52 /* SeedViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedViewModel.swift; sourceTree = ""; }; @@ -74,6 +146,25 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + EE0E1FAB29473B10003CD7D5 /* assets */ = { + isa = PBXGroup; + children = ( + EE0E1FAC29473B10003CD7D5 /* Assets.xcassets */, + EE0E1FAD29473B10003CD7D5 /* fonts */, + ); + path = assets; + sourceTree = ""; + }; + EE0E1FAD29473B10003CD7D5 /* fonts */ = { + isa = PBXGroup; + children = ( + EE0E1FAE29473B10003CD7D5 /* SteradianBold.otf */, + EE0E1FAF29473B10003CD7D5 /* SteradianMedium.otf */, + EE0E1FB029473B10003CD7D5 /* SteradianRegular.otf */, + ); + path = fonts; + sourceTree = ""; + }; EE38134D2938D55D00A3A710 /* Packages */ = { isa = PBXGroup; children = ( @@ -82,6 +173,110 @@ name = Packages; sourceTree = ""; }; + EE6C38CA29462474006CD2D3 /* WalletDemo */ = { + isa = PBXGroup; + children = ( + EE6C391B29468533006CD2D3 /* Home */, + EE6C390D2946851D006CD2D3 /* QRCodeScanner */, + EE6C38E629462A60006CD2D3 /* Dashboard */, + EE6C38D82946264C006CD2D3 /* UIHelper */, + EE6C38D52946259E006CD2D3 /* Profile */, + EE6C38D0294624FD006CD2D3 /* Main */, + ); + path = WalletDemo; + sourceTree = ""; + }; + EE6C38D0294624FD006CD2D3 /* Main */ = { + isa = PBXGroup; + children = ( + EE6C38D129462516006CD2D3 /* MainView.swift */, + EE6C38D329462522006CD2D3 /* MainViewRouter.swift */, + ); + path = Main; + sourceTree = ""; + }; + EE6C38D52946259E006CD2D3 /* Profile */ = { + isa = PBXGroup; + children = ( + ); + path = Profile; + sourceTree = ""; + }; + EE6C38D82946264C006CD2D3 /* UIHelper */ = { + isa = PBXGroup; + children = ( + EE6C38D929462659006CD2D3 /* SpecificRoundedRect.swift */, + EE6C38EB29467A7A006CD2D3 /* ClearFullCoverModifier.swift */, + EE6C38ED29467A9D006CD2D3 /* DisablePreferenceKey.swift */, + ); + path = UIHelper; + sourceTree = ""; + }; + EE6C38DD2946276F006CD2D3 /* Resources */ = { + isa = PBXGroup; + children = ( + EE0E1FAB29473B10003CD7D5 /* assets */, + EE6C38E2294627B2006CD2D3 /* Localizable.strings */, + EE6C38E429462822006CD2D3 /* Localizable.stringsdict */, + ); + path = Resources; + sourceTree = ""; + }; + EE6C38E629462A60006CD2D3 /* Dashboard */ = { + isa = PBXGroup; + children = ( + EE6C38E729462A6F006CD2D3 /* DashboardTabViewController.swift */, + EE6C38E929467A36006CD2D3 /* DashboardView.swift */, + EE6C3908294683C4006CD2D3 /* DashboardRouter.swift */, + EE6C390A294683D5006CD2D3 /* DashboardBuilder.swift */, + EE6C393D2946901D006CD2D3 /* DashboardViewModelImpl.swift */, + ); + path = Dashboard; + sourceTree = ""; + }; + EE6C390D2946851D006CD2D3 /* QRCodeScanner */ = { + isa = PBXGroup; + children = ( + EE6C390E2946851D006CD2D3 /* UI */, + EE6C39112946851D006CD2D3 /* QRCodeScannerBuilder.swift */, + EE6C39122946851D006CD2D3 /* QRCodeScannerView.swift */, + EE6C39132946851D006CD2D3 /* QRCodeScannerRouter.swift */, + EE6C39142946851D006CD2D3 /* QRCodeScannerViewModel.swift */, + ); + path = QRCodeScanner; + sourceTree = ""; + }; + EE6C390E2946851D006CD2D3 /* UI */ = { + isa = PBXGroup; + children = ( + EE6C390F2946851D006CD2D3 /* QRScannerView.swift */, + EE6C39102946851D006CD2D3 /* CameraViewController.swift */, + ); + path = UI; + sourceTree = ""; + }; + EE6C391B29468533006CD2D3 /* Home */ = { + isa = PBXGroup; + children = ( + EE6C391C29468533006CD2D3 /* UI */, + EE6C392529468533006CD2D3 /* HomeViewModel.swift */, + EE6C392629468533006CD2D3 /* HomeView.swift */, + EE6C392829468533006CD2D3 /* HomeRouter.swift */, + EE6C392929468533006CD2D3 /* HomeBuilder.swift */, + EE6C392A29468533006CD2D3 /* HomeState.swift */, + ); + path = Home; + sourceTree = ""; + }; + EE6C391C29468533006CD2D3 /* UI */ = { + isa = PBXGroup; + children = ( + EE6C38D6294625B3006CD2D3 /* ProfileHeaderView.swift */, + EE6C392229468533006CD2D3 /* ActivityListView.swift */, + ); + path = UI; + sourceTree = ""; + }; EEB7D32029420155006E076D /* SetupPrismAgent */ = { isa = PBXGroup; children = ( @@ -112,12 +307,12 @@ EEE61FB82937CA280053AE52 /* AtalaPrismWalletDemo */ = { isa = PBXGroup; children = ( + EE6C38DD2946276F006CD2D3 /* Resources */, EEE620312937FF2C0053AE52 /* Info.plist */, EEE620112937F1C30053AE52 /* Helper */, EEE61FDE2937CE970053AE52 /* Modules */, EEE61FB92937CA280053AE52 /* AtalaPrismWalletDemoApp.swift */, EEE61FBB2937CA280053AE52 /* FuncionalitiesList.swift */, - EEE61FBD2937CA2A0053AE52 /* Assets.xcassets */, EEE61FBF2937CA2A0053AE52 /* Preview Content */, ); path = AtalaPrismWalletDemo; @@ -134,6 +329,7 @@ EEE61FDE2937CE970053AE52 /* Modules */ = { isa = PBXGroup; children = ( + EE6C38CA29462474006CD2D3 /* WalletDemo */, EEB7D32029420155006E076D /* SetupPrismAgent */, EEE6202C2937FD4B0053AE52 /* AuthenticateWallet */, EEE620142937F2C80053AE52 /* SigningVerification */, @@ -172,6 +368,14 @@ isa = PBXGroup; children = ( EEE620122937F1D40053AE52 /* PrintObjects.swift */, + EE6C38DB294626E1006CD2D3 /* String+extensions.swift */, + EE6C38EF29468196006CD2D3 /* DIContainer.swift */, + EE6C39002946827B006CD2D3 /* ComponentContainer.swift */, + EE6C390229468288006CD2D3 /* Builder.swift */, + EE6C390429468309006CD2D3 /* LazyView.swift */, + EE6C39062946834F006CD2D3 /* RootPresentationMode.swift */, + EE6C393B29468614006CD2D3 /* EmptyNavigationLink.swift */, + EE6C393F2946931E006CD2D3 /* Array+Zipped.swift */, ); path = Helper; sourceTree = ""; @@ -265,8 +469,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + EE0E1FB329473B10003CD7D5 /* SteradianMedium.otf in Resources */, + EE0E1FB429473B10003CD7D5 /* SteradianRegular.otf in Resources */, EEE61FC12937CA2A0053AE52 /* Preview Assets.xcassets in Resources */, - EEE61FBE2937CA2A0053AE52 /* Assets.xcassets in Resources */, + EE0E1FB229473B10003CD7D5 /* SteradianBold.otf in Resources */, + EE6C38E529462822006CD2D3 /* Localizable.stringsdict in Resources */, + EE0E1FB129473B10003CD7D5 /* Assets.xcassets in Resources */, + EE6C38E3294627B2006CD2D3 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -279,17 +488,48 @@ files = ( EEB7D3242942018C006E076D /* SetupPrismAgentViewModel.swift in Sources */, EEE620132937F1D40053AE52 /* PrintObjects.swift in Sources */, + EE6C393E2946901D006CD2D3 /* DashboardViewModelImpl.swift in Sources */, EEE620302937FDE50053AE52 /* AuthenticateWalletViewModel.swift in Sources */, + EE6C390529468309006CD2D3 /* LazyView.swift in Sources */, + EE6C39172946851D006CD2D3 /* QRCodeScannerBuilder.swift in Sources */, + EE6C39152946851D006CD2D3 /* QRScannerView.swift in Sources */, EEE61FE02937CEAA0053AE52 /* SeedViewModel.swift in Sources */, + EE6C393929468533006CD2D3 /* HomeState.swift in Sources */, + EE6C38DC294626E1006CD2D3 /* String+extensions.swift in Sources */, EEE61FE82937D7EE0053AE52 /* DIDFuncionalitiesView.swift in Sources */, EEE61FBC2937CA280053AE52 /* FuncionalitiesList.swift in Sources */, + EE6C3909294683C4006CD2D3 /* DashboardRouter.swift in Sources */, EEE61FDD2937CD7A0053AE52 /* SeedFuncionalitiesView.swift in Sources */, + EE6C38EE29467A9D006CD2D3 /* DisablePreferenceKey.swift in Sources */, + EE6C38E829462A6F006CD2D3 /* DashboardTabViewController.swift in Sources */, + EE6C393529468533006CD2D3 /* HomeView.swift in Sources */, + EE6C38EC29467A7A006CD2D3 /* ClearFullCoverModifier.swift in Sources */, + EE6C38D429462522006CD2D3 /* MainViewRouter.swift in Sources */, + EE6C39162946851D006CD2D3 /* CameraViewController.swift in Sources */, + EE6C393C29468614006CD2D3 /* EmptyNavigationLink.swift in Sources */, + EE6C39012946827B006CD2D3 /* ComponentContainer.swift in Sources */, + EE6C393729468533006CD2D3 /* HomeRouter.swift in Sources */, EEE61FE42937D5560053AE52 /* DIDFuncionalitiesViewModel.swift in Sources */, + EE6C38D7294625B3006CD2D3 /* ProfileHeaderView.swift in Sources */, + EE6C38D229462516006CD2D3 /* MainView.swift in Sources */, EEE6202F2937FDE50053AE52 /* AuthenticateWalletView.swift in Sources */, EEE620182937F6870053AE52 /* SigningVerificationView.swift in Sources */, + EE6C391A2946851D006CD2D3 /* QRCodeScannerViewModel.swift in Sources */, EEE61FBA2937CA280053AE52 /* AtalaPrismWalletDemoApp.swift in Sources */, + EE6C390B294683D5006CD2D3 /* DashboardBuilder.swift in Sources */, + EE6C39402946931E006CD2D3 /* Array+Zipped.swift in Sources */, + EE6C39192946851D006CD2D3 /* QRCodeScannerRouter.swift in Sources */, + EE6C393129468533006CD2D3 /* ActivityListView.swift in Sources */, + EE6C390329468288006CD2D3 /* Builder.swift in Sources */, + EE6C39182946851D006CD2D3 /* QRCodeScannerView.swift in Sources */, + EE6C38EA29467A36006CD2D3 /* DashboardView.swift in Sources */, + EE6C38DA29462659006CD2D3 /* SpecificRoundedRect.swift in Sources */, + EE6C393429468533006CD2D3 /* HomeViewModel.swift in Sources */, EEB7D32229420180006E076D /* SetupPrismAgentView.swift in Sources */, + EE6C38F029468196006CD2D3 /* DIContainer.swift in Sources */, + EE6C393829468533006CD2D3 /* HomeBuilder.swift in Sources */, EEE620162937F3110053AE52 /* SigningVerificationViewModel.swift in Sources */, + EE6C39072946834F006CD2D3 /* RootPresentationMode.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/FuncionalitiesList.swift b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/FuncionalitiesList.swift index 173c13f7..1524a6b5 100644 --- a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/FuncionalitiesList.swift +++ b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/FuncionalitiesList.swift @@ -11,6 +11,7 @@ struct FuncionalitiesList: View { ) NavigationLink("Setup Prism Agent", destination: SetupPrismAgentView(viewModel: SetupPrismAgentViewModelImpl()) ) + NavigationLink("Wallet Demo", destination: MainView(router: MainViewRouterImpl())) } } } diff --git a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Info.plist b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Info.plist index db53a6f5..14242ae0 100644 --- a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Info.plist +++ b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Info.plist @@ -15,5 +15,10 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + diff --git a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/SetupPrismAgent/SetupPrismAgentView.swift b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/SetupPrismAgent/SetupPrismAgentView.swift index 16f8e226..1d16fdb1 100644 --- a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/SetupPrismAgent/SetupPrismAgentView.swift +++ b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/SetupPrismAgent/SetupPrismAgentView.swift @@ -4,7 +4,9 @@ protocol SetupPrismAgentViewModel: ObservableObject { var status: String { get } var error: String? { get } func start() async throws + func parseOOBMessage() async throws func updateKeyList() async throws + func startMessageStream() async throws } struct SetupPrismAgentView: View { @@ -31,7 +33,23 @@ struct SetupPrismAgentView: View { Button("Create a connection") { Task { - try await viewModel.updateKeyList() + try await viewModel.parseOOBMessage() + } + } + .padding() + .frame(maxWidth: .infinity) + .background(Color.red) + .tint(.white) + .clipShape(Capsule(style: .continuous)) + + if let error = viewModel.error { + Text("Error").foregroundColor(.red) + Text(error) + } + + Button("Start message stream") { + Task { + try await viewModel.startMessageStream() } } .padding() @@ -58,5 +76,7 @@ private class ViewModel: SetupPrismAgentViewModel { var status: String = "" var error: String? func start() {} + func parseOOBMessage() async throws {} func updateKeyList() async throws {} + func startMessageStream() async throws {} } diff --git a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/SetupPrismAgent/SetupPrismAgentViewModel.swift b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/SetupPrismAgent/SetupPrismAgentViewModel.swift index 6e1f87c1..208fa9e6 100644 --- a/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/SetupPrismAgent/SetupPrismAgentViewModel.swift +++ b/Sample/AtalaPrismWalletDemo/AtalaPrismWalletDemo/Modules/SetupPrismAgent/SetupPrismAgentViewModel.swift @@ -1,4 +1,5 @@ import PrismAgent +import Combine import Domain import Foundation @@ -8,9 +9,10 @@ final class SetupPrismAgentViewModelImpl: ObservableObject, SetupPrismAgentViewM @Published var error: String? private let agent: PrismAgent + private var cancellables = [AnyCancellable]() init() { - let did = try! DID(string: "did:peer:2.Ez6LScc4S6tTSf5PnB7tWAna8Ee2aL7z2nRgo6aCHQwLds3m4.Vz6MktCyutFBcZcAWBnE2shqqUQDyRdnvcwqMTPqWsGHMnHyT.SeyJpZCI6Im5ldy1pZCIsInQiOiJkbSIsInMiOiJodHRwOi8vcm9vdHNpZC1tZWRpYXRvcjo4MDAwIiwiYSI6WyJkaWRjb21tL3YyIl19") + let did = try! DID(string: "did:peer:2.Ez6LSms555YhFthn1WV8ciDBpZm86hK9tp83WojJUmxPGk1hZ.Vz6MkmdBjMyB4TS5UbbQw54szm8yvMMf1ftGV2sQVYAxaeWhE.SeyJpZCI6Im5ldy1pZCIsInQiOiJkbSIsInMiOiJodHRwczovL21lZGlhdG9yLnJvb3RzaWQuY2xvdWQiLCJhIjpbImRpZGNvbW0vdjIiXX0") self.agent = PrismAgent(mediatorServiceEnpoint: did) status = agent.state.rawValue @@ -35,7 +37,7 @@ final class SetupPrismAgentViewModelImpl: ObservableObject, SetupPrismAgentViewM func updateKeyList() async throws { do { _ = try await agent.createNewPeerDID(updateMediator: true) - try await agent.awaitMessages() +// try await agent.awaitMessages() } catch { await MainActor.run { self.error = error.localizedDescription @@ -44,7 +46,7 @@ final class SetupPrismAgentViewModelImpl: ObservableObject, SetupPrismAgentViewM } func parseOOBMessage() async throws { - let url = "https://domain.com/path?_oob=eyJpZCI6ImU0ZGRlNWVkLTczMWQtNDQ2Ni1iMTVhLTJjMzBhMTFlZjU3MSIsInR5cGUiOiJodHRwczovL2RpZGNvbW0ub3JnL291dC1vZi1iYW5kLzIuMC9pbnZpdGF0aW9uIiwiZnJvbSI6ImRpZDpwZWVyOjIuRXo2TFNjdVJuYlpBSmFWdGhjTDVSRUxxNzVFQksyc0JtQnhzU3M5OExLTmVyaUhRSi5WejZNa3BlYVc3RGVwdEpXN3BpMnFOWFRkQ1hlUVY0RVlwWm5Bb3VIMUxyZkhqNnVmLlNleUowSWpvaVpHMGlMQ0p6SWpvaWFIUjBjSE02THk5ck9ITXRaR1YyTG1GMFlXeGhjSEpwYzIwdWFXOHZjSEpwYzIwdFlXZGxiblF2Wkdsa1kyOXRiU0lzSW5JaU9sdGRMQ0poSWpwYkltUnBaR052YlcwdmRqSWlYWDAiLCJib2R5Ijp7ImdvYWxfY29kZSI6ImNvbm5lY3QiLCJnb2FsIjoiRXN0YWJsaXNoIGEgdHJ1c3QgY29ubmVjdGlvbiBiZXR3ZWVuIHR3byBwZWVycyIsImFjY2VwdCI6W119fQ==" + let url = "https://domain.com/path?_oob=eyJpZCI6IjhkYzY3MTRjLTJiNmEtNGZkOS1iYzg3LWJiODhlYTk1NmFiNyIsInR5cGUiOiJodHRwczovL2RpZGNvbW0ub3JnL291dC1vZi1iYW5kLzIuMC9pbnZpdGF0aW9uIiwiZnJvbSI6ImRpZDpwZWVyOjIuRXo2TFNxQWlIZWRIRmZiZW14UnpyUjV0ZTQ2VUdzdHhkcW0yMXpFelVjd3dGaVhwcC5WejZNa2ljRWh6NHRoQlZMWVRlc3VEWkJOOTdLRTdoTHdYRVR0UWppajJrcWl3N3Q0LlNleUowSWpvaVpHMGlMQ0p6SWpvaWFIUjBjRG92TDJodmMzUXVaRzlqYTJWeUxtbHVkR1Z5Ym1Gc09qZ3dPREF2Wkdsa1kyOXRiU0lzSW5JaU9sdGRMQ0poSWpwYkltUnBaR052YlcwdmRqSWlYWDAiLCJib2R5Ijp7ImdvYWxfY29kZSI6ImNvbm5lY3QiLCJnb2FsIjoiRXN0YWJsaXNoIGEgdHJ1c3QgY29ubmVjdGlvbiBiZXR3ZWVuIHR3byBwZWVycyIsImFjY2VwdCI6W119fQ==" do { let message = try await agent.parseOOBInvitation(url: url) @@ -58,4 +60,19 @@ final class SetupPrismAgentViewModelImpl: ObservableObject, SetupPrismAgentViewM } } } + + func startMessageStream() async throws { + agent.startFetchingMessages() + agent.handleMessagesEvents().sink { + switch $0 { + case .finished: + print("Finished message retrieval") + case .failure(let error): + print(error.localizedDescription) + } + } receiveValue: { + print("Received message: \($0.id)") + } + .store(in: &cancellables) + } }