Skip to content

Commit

Permalink
feat(pluto): add persistence to connection data and messages
Browse files Browse the repository at this point in the history
Fixes ATL-2495
  • Loading branch information
goncalo-frade-iohk committed Dec 1, 2022
1 parent e9e5bb2 commit b2b10d3
Show file tree
Hide file tree
Showing 49 changed files with 1,545 additions and 182 deletions.
35 changes: 29 additions & 6 deletions Domain/Sources/BBs/Pluto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,38 @@ import Combine
import Foundation

public protocol Pluto {
func storeDID(
func storePrismDID(
did: DID,
keyPairIndex: Int,
alias: String?
) -> AnyPublisher<Void, Error>
func storePeerDID(did: DID, privateKey: PrivateKey) -> AnyPublisher<Void, Error>
func storeDIDPair(holder: DID, other: DID, name: String) -> AnyPublisher<Void, Error>
func storeMessage(message: Message) -> AnyPublisher<Void, Error>
func storeMediator(peer: DID, routingDID: DID, url: URL) -> AnyPublisher<Void, Error>

func getAllDIDs() -> AnyPublisher<[(did: DID, keyPairIndex: Int, alias: String?)], Error>
func getDIDInfo(did: DID) -> AnyPublisher<(did: DID, keyPairIndex: Int, alias: String?)?, Error>
func getDIDInfo(alias: String) -> AnyPublisher<[(did: DID, keyPairIndex: Int)], Error>
func getDIDKeyPairIndex(did: DID) -> AnyPublisher<Int?, Error>
func getLastKeyPairIndex() -> AnyPublisher<Int, Error>
func getAllPrismDIDs() -> AnyPublisher<[(did: DID, keyPairIndex: Int, alias: String?)], Error>
func getPrismDIDInfo(did: DID) -> AnyPublisher<(did: DID, keyPairIndex: Int, alias: String?)?, Error>
func getPrismDIDInfo(alias: String) -> AnyPublisher<[(did: DID, keyPairIndex: Int)], Error>
func getPrismDIDKeyPairIndex(did: DID) -> AnyPublisher<Int?, Error>
func getPrismLastKeyPairIndex() -> AnyPublisher<Int, Error>

func getAllPeerDIDs() -> AnyPublisher<[(did: DID, privateKey: PrivateKey)], Error>
func getPeerDIDInfo(did: DID) -> AnyPublisher<(did: DID, privateKey: PrivateKey)?, Error>
func getPeerDIDPrivateKey(did: DID) -> AnyPublisher<PrivateKey?, Error>

func getAllDidPairs() -> AnyPublisher<[(holder: DID, other: DID, name: String?)], Error>
func getPair(otherDID: DID) -> AnyPublisher<(holder: DID, other: DID, name: String?)?, Error>
func getPair(name: String) -> AnyPublisher<(holder: DID, other: DID, name: String?)?, Error>
func getPair(holderDID: DID) -> AnyPublisher<(holder: DID, other: DID, name: String?)?, Error>

func getAllMessages() -> AnyPublisher<[Message], Error>
func getAllMessages(did: DID) -> 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>
func getAllMessages(from: DID, to: DID) -> AnyPublisher<[Message], Error>
func getMessage(id: String) -> AnyPublisher<Message?, Error>

func getAllMediators() -> AnyPublisher<[(did: DID, routingDID: DID, url: URL)], Error>
}
5 changes: 5 additions & 0 deletions Domain/Sources/Models/DIDPair.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public struct DIDPair: Equatable {
public let holder: DID
public let other: DID
public let name: String?
}
7 changes: 7 additions & 0 deletions Domain/Sources/Models/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ public enum MercuryError: Error {
case noDIDReceiverSetError
case noValidServiceFoundError
}

public enum PlutoError: Error {
case invalidHolderDIDNotPersistedError
case messageMissingFromOrToDIDError
case didPairIsNotPersistedError
case holderDIDAlreadyPairingError
}
10 changes: 10 additions & 0 deletions Pluto/Sources/Domain/Providers/DIDPairProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Combine
import Domain
import Foundation

protocol DIDPairProvider {
func getAll() -> AnyPublisher<[(holder: DID, other: DID, name: String?)], Error>
func getPair(otherDID: DID) -> AnyPublisher<(holder: DID, other: DID, name: String?)?, Error>
func getPair(name: String) -> AnyPublisher<(holder: DID, other: DID, name: String?)?, Error>
func getPair(holderDID: DID) -> AnyPublisher<(holder: DID, other: DID, name: String?)?, Error>
}
9 changes: 9 additions & 0 deletions Pluto/Sources/Domain/Providers/DIDPrivateKeyProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Combine
import Domain
import Foundation

protocol DIDPrivateKeyProvider {
func getAll() -> AnyPublisher<[(did: DID, privateKey: PrivateKey)], Error>
func getDIDInfo(did: DID) -> AnyPublisher<(did: DID, privateKey: PrivateKey)?, Error>
func getPrivateKey(did: DID) -> AnyPublisher<PrivateKey?, Error>
}
7 changes: 7 additions & 0 deletions Pluto/Sources/Domain/Providers/MediatorProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Combine
import Domain
import Foundation

protocol MediatorProvider {
func getAll() -> AnyPublisher<[(did: DID, routingDID: DID, url: URL)], Error>
}
13 changes: 13 additions & 0 deletions Pluto/Sources/Domain/Providers/MessageProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Combine
import Domain
import Foundation

protocol MessageProvider {
func getAll() -> AnyPublisher<[Message], Error>
func getAllFor(did: DID) -> 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>
func getAll(from: DID, to: DID) -> AnyPublisher<[Message], Error>
func getMessage(id: String) -> AnyPublisher<Message?, Error>
}
9 changes: 9 additions & 0 deletions Pluto/Sources/Domain/Stores/DIDPairStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Combine
import Domain
import Foundation

protocol DIDPairStore {
func addDIDPair(holder: DID, other: DID, name: String) -> AnyPublisher<Void, Error>
func removeDIDPair(holder: DID, other: DID) -> AnyPublisher<Void, Error>
func removeAll() -> AnyPublisher<Void, Error>
}
9 changes: 9 additions & 0 deletions Pluto/Sources/Domain/Stores/DIDPrivateKeyStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Combine
import Domain
import Foundation

protocol DIDPrivateKeyStore {
func addDID(did: DID, privateKey: PrivateKey) -> AnyPublisher<Void, Error>
func removeDID(did: DID) -> AnyPublisher<Void, Error>
func removeAll() -> AnyPublisher<Void, Error>
}
8 changes: 8 additions & 0 deletions Pluto/Sources/Domain/Stores/MediatorStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Combine
import Domain
import Foundation

protocol MediatorStore {
func addMediator(peer: DID, routingDID: DID, url: URL) -> AnyPublisher<Void, Error>
func removeMediator(peer: DID) -> AnyPublisher<Void, Error>
}
9 changes: 9 additions & 0 deletions Pluto/Sources/Domain/Stores/MessageStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Combine
import Domain
import Foundation

protocol MessageStore {
func addMessage(msg: Message) -> AnyPublisher<Void, Error>
func removeMessage(id: String) -> AnyPublisher<Void, Error>
func removeAll() -> AnyPublisher<Void, Error>
}
73 changes: 73 additions & 0 deletions Pluto/Sources/Helpers/AttachmentDescriptor+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Domain
import Foundation

extension AttachmentDescriptor: Codable {
enum CodingKeys: String, CodingKey {
case id
case mediaType
case data
case filename
case lastmodTime
case byteCount
case description
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try mediaType.map { try container.encode($0, forKey: .mediaType) }
try filename.map { try container.encode($0, forKey: .filename) }
try lastmodTime.map { try container.encode($0, forKey: .lastmodTime) }
try byteCount.map { try container.encode($0, forKey: .byteCount) }
try description.map { try container.encode($0, forKey: .description) }

if let attachment = data as? AttachmentBase64 {
try container.encode(attachment, forKey: .data)
} else if let attachment = data as? AttachmentJws {
try container.encode(attachment, forKey: .data)
} else if let attachment = data as? AttachmentHeader {
try container.encode(attachment, forKey: .data)
} else if let attachment = data as? AttachmentJwsData {
try container.encode(attachment, forKey: .data)
} else if let attachment = data as? AttachmentJsonData {
try container.encode(attachment, forKey: .data)
} else if let attachment = data as? AttachmentLinkData {
try container.encode(attachment, forKey: .data)
} else { fatalError("Cannot do this") }
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let id = try container.decode(String.self, forKey: .id)
let mediaType = try? container.decode(String.self, forKey: .mediaType)
let filename = try? container.decode([String].self, forKey: .filename)
let lastmodTime = try? container.decode(Date.self, forKey: .lastmodTime)
let byteCount = try? container.decode(Int.self, forKey: .byteCount)
let description = try? container.decode([String].self, forKey: .description)

let data: AttachmentData
if let attachment = try? container.decode(AttachmentBase64.self, forKey: .data) {
data = attachment
} else if let attachment = try? container.decode(AttachmentJws.self, forKey: .data) {
data = attachment
} else if let attachment = try? container.decode(AttachmentHeader.self, forKey: .data) {
data = attachment
} else if let attachment = try? container.decode(AttachmentJwsData.self, forKey: .data) {
data = attachment
} else if let attachment = try? container.decode(AttachmentJsonData.self, forKey: .data) {
data = attachment
} else if let attachment = try? container.decode(AttachmentLinkData.self, forKey: .data) {
data = attachment
} else { fatalError("Cannot do this") }

self.init(
id: id,
mediaType: mediaType,
data: data,
filename: filename,
lastmodTime: lastmodTime,
byteCount: byteCount,
description: description
)
}
}
4 changes: 2 additions & 2 deletions Pluto/Sources/Helpers/CoreData/CoreDataDAO+Combine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ extension CoreDataDAO where CoreDataObject: Identifiable {
func updateOrCreate(
_ id: CoreDataObject.ID,
context: NSManagedObjectContext,
modify: @escaping (CoreDataObject, NSManagedObjectContext) -> Void
modify: @escaping (CoreDataObject, NSManagedObjectContext) throws -> Void
) -> AnyPublisher<CoreDataObject.ID, Error> {
context.write { context in
modify(self.fetchByID(id, context: context) ?? self.newEntity(context: context), context)
try modify(self.fetchByID(id, context: context) ?? self.newEntity(context: context), context)
return id
}
.eraseToAnyPublisher()
Expand Down
26 changes: 26 additions & 0 deletions Pluto/Sources/Helpers/DID+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Domain
import Foundation

extension DID: Codable {
enum CodingKeys: String, CodingKey {
case schema
case method
case methodId
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(schema, forKey: .schema)
try container.encode(method, forKey: .method)
try container.encode(methodId, forKey: .methodId)
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let schema = try container.decode(String.self, forKey: .schema)
let method = try container.decode(DIDMethod.self, forKey: .method)
let methodId = try container.decode(DIDMethodId.self, forKey: .methodId)

self.init(schema: schema, method: method, methodId: methodId)
}
}
70 changes: 70 additions & 0 deletions Pluto/Sources/Helpers/Message+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import Domain
import Foundation

extension Message: Codable {
enum CodingKeys: String, CodingKey {
case id
case piuri
case from
case to
case fromPrior
case extraHeaders
case createdTime
case expiresTimePlus
case attachments
case thid
case pthid
case ack
case body
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(piuri, forKey: .piuri)
try container.encode(body, forKey: .body)
try container.encode(extraHeaders, forKey: .extraHeaders)
try container.encode(createdTime, forKey: .createdTime)
try container.encode(expiresTimePlus, forKey: .expiresTimePlus)
try container.encode(attachments, forKey: .attachments)
try container.encode(ack, forKey: .ack)
try from.map { try container.encode($0, forKey: .from) }
try to.map { try container.encode($0, forKey: .to) }
try fromPrior.map { try container.encode($0, forKey: .fromPrior) }
try thid.map { try container.encode($0, forKey: .thid) }
try pthid.map { try container.encode($0, forKey: .pthid) }
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let id = try container.decode(String.self, forKey: .id)
let piuri = try container.decode(String.self, forKey: .piuri)
let body = try container.decode(Data.self, forKey: .body)
let extraHeaders = try container.decode([String: String].self, forKey: .extraHeaders)
let createdTime = try container.decode(Date.self, forKey: .createdTime)
let expiresTimePlus = try container.decode(Date.self, forKey: .expiresTimePlus)
let attachments = try container.decode([AttachmentDescriptor].self, forKey: .attachments)
let ack = try container.decode([String].self, forKey: .ack)
let from = try? container.decode(DID.self, forKey: .from)
let to = try? container.decode(DID.self, forKey: .to)
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)

self.init(
id: id,
piuri: piuri,
from: from,
to: to,
fromPrior: fromPrior,
body: body,
extraHeaders: extraHeaders,
createdTime: createdTime,
expiresTimePlus: expiresTimePlus,
attachments: attachments,
thid: thid,
pthid: pthid,
ack: ack
)
}
}
19 changes: 19 additions & 0 deletions Pluto/Sources/PersistentStorage/DAO/CDDIDDAO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Combine
import CoreData
import Domain

struct CDDIDDAO: CoreDataDAO {
typealias CoreDataObject = CDDID
let readContext: NSManagedObjectContext
let writeContext: NSManagedObjectContext
let identifierKey: String? = "did"
}

extension CDDID {
func parseFrom(did: DID) {
self.did = did.string
self.schema = did.schema
self.method = did.method
self.methodId = did.methodId
}
}
Loading

0 comments on commit b2b10d3

Please sign in to comment.