• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hyperledger / identus-edge-agent-sdk-swift / 11035384347

25 Sep 2024 02:40PM UTC coverage: 40.842% (-3.1%) from 43.981%
11035384347

Pull #159

github

web-flow
Merge 65ff99d66 into d3597e19d
Pull Request #159: feat(agent): agent separation of concerns

232 of 1063 new or added lines in 19 files covered. (21.83%)

187 existing lines in 14 files now uncovered.

5202 of 12737 relevant lines covered (40.84%)

97.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

34.53
/EdgeAgentSDK/EdgeAgent/Sources/DIDCommAgent/DIDCommAgent.swift
1
import Builders
2
import Combine
3
import Core
4
import Domain
5
import Foundation
6

7
public class DIDCommAgent {
8
    /// Enumeration representing the current state of the agent.
9
    public enum State: String {
10
        case stoped
11
        case starting
12
        case running
13
        case stoping
14
    }
15
    
16
    /// Represents the current state of the agent.
17
    public private(set) var state = State.stoped
10✔
18
    
19
    /// The mediator routing DID if one is currently registered.
NEW
20
    public var mediatorRoutingDID: DID? {
×
NEW
21
        connectionManager?.mediationHandler.mediator?.routingDID
×
NEW
22
    }
×
23
    
24
    public let mercury: Mercury
25
    public let edgeAgent: EdgeAgent
26
    public var apollo: Apollo & KeyRestoration { edgeAgent.apollo }
14✔
NEW
27
    public var castor: Castor { edgeAgent.castor }
×
28
    public var pluto: Pluto { edgeAgent.pluto }
28✔
29
    public var pollux: Pollux { edgeAgent.pollux }
6✔
NEW
30
    var logger: SDKLogger { edgeAgent.logger }
×
31

32
    var mediationHandler: MediatorHandler?
33

34
    var connectionManager: ConnectionsManagerImpl?
35
    var cancellables = [AnyCancellable]()
10✔
36
    // Not a "stream"
37
    var messagesStreamTask: Task<Void, Error>?
38

39
    /// Initializes a EdgeAgent with the given dependency objects and seed data.
40
    ///
41
    /// - Parameters:
42
    ///   - apollo: An instance of Apollo.
43
    ///   - castor: An instance of Castor.
44
    ///   - pluto: An instance of Pluto.
45
    ///   - pollux: An instance of Pollux.
46
    ///   - mercury: An instance of Mercury.
47
    ///   - seed: A unique seed used to generate the unique DID.
48
    ///   - mediatorServiceEnpoint: The endpoint of the Mediator service to use.
49
    public init(
50
        edgeAgent: EdgeAgent,
51
        mercury: Mercury,
52
        mediationHandler: MediatorHandler? = nil
53
    ) {
10✔
54
        self.edgeAgent = edgeAgent
10✔
55
        self.mercury = mercury
10✔
56
        self.mediationHandler = mediationHandler
10✔
57
        mediationHandler.map {
10✔
58
            self.connectionManager = ConnectionsManagerImpl(
2✔
59
                castor: edgeAgent.castor,
2✔
60
                mercury: mercury,
2✔
61
                pluto: edgeAgent.pluto,
2✔
62
                mediationHandler: $0,
2✔
63
                pairings: []
2✔
64
            )
2✔
65
        }
2✔
66
    }
10✔
67

68
    /**
69
      Convenience initializer for `EdgeAgent` that allows for optional initialization of seed data and mediator service endpoint.
70

71
      - Parameters:
72
        - seedData: Optional seed data for creating a new seed. If not provided, a random seed will be generated.
73
        - mediatorServiceEnpoint: Optional DID representing the service endpoint of the mediator. If not provided, the default Prism mediator endpoint will be used.
74
    */
75
    public convenience init(
76
        seedData: Data? = nil,
77
        mediatorDID: DID
78
    ) {
2✔
79
        let edgeAgent = EdgeAgent(seedData: seedData)
2✔
80
        let secretsStream = createSecretsStream(
2✔
81
            keyRestoration: edgeAgent.apollo,
2✔
82
            pluto: edgeAgent.pluto,
2✔
83
            castor: edgeAgent.castor
2✔
84
        )
2✔
85

2✔
86
        let mercury = MercuryBuilder(
2✔
87
            castor: edgeAgent.castor,
2✔
88
            secretsStream: secretsStream
2✔
89
        ).build()
2✔
90

2✔
91
        self.init(
2✔
92
            edgeAgent: edgeAgent,
2✔
93
            mercury: mercury,
2✔
94
            mediationHandler: BasicMediatorHandler(
2✔
95
                mediatorDID: mediatorDID,
2✔
96
                mercury: mercury,
2✔
97
                store: BasicMediatorHandler.PlutoMediatorStoreImpl(pluto: edgeAgent.pluto)
2✔
98
            )
2✔
99
        )
2✔
100
    }
2✔
101

NEW
102
    public func setupMediatorHandler(mediationHandler: MediatorHandler) async throws {
×
NEW
103
        try await stop()
×
NEW
104
        self.mediationHandler = mediationHandler
×
NEW
105
        self.connectionManager = ConnectionsManagerImpl(
×
NEW
106
            castor: castor,
×
NEW
107
            mercury: mercury,
×
NEW
108
            pluto: pluto,
×
NEW
109
            mediationHandler: mediationHandler,
×
NEW
110
            pairings: []
×
NEW
111
        )
×
NEW
112
    }
×
113

NEW
114
    public func setupMediatorDID(did: DID) async throws {
×
NEW
115
        let mediatorHandler = BasicMediatorHandler(
×
NEW
116
            mediatorDID: did,
×
NEW
117
            mercury: mercury,
×
NEW
118
            store: BasicMediatorHandler.PlutoMediatorStoreImpl(pluto: pluto)
×
NEW
119
        )
×
NEW
120
        try await setupMediatorHandler(mediationHandler: mediatorHandler)
×
NEW
121
    }
×
122

123
    /**
124
     Start the EdgeAgent and Mediator services
125

126
     - Throws: EdgeAgentError.noMediatorAvailableError if no mediator is available,
127
     as well as any error thrown by `createNewPeerDID` and `connectionManager.registerMediator`
128
    */
NEW
129
    public func start() async throws {
×
NEW
130
        guard
×
NEW
131
            let connectionManager,
×
NEW
132
            state == .stoped
×
NEW
133
        else { return }
×
NEW
134
        logger.info(message: "Starting agent")
×
NEW
135
        state = .starting
×
NEW
136
        do {
×
NEW
137
            try await connectionManager.startMediator()
×
NEW
138
        } catch EdgeAgentError.noMediatorAvailableError {
×
NEW
139
            let hostDID = try await createNewPeerDID(updateMediator: false)
×
NEW
140
            try await connectionManager.registerMediator(hostDID: hostDID)
×
NEW
141
        }
×
NEW
142
        try await edgeAgent.firstLinkSecretSetup()
×
NEW
143
        state = .running
×
NEW
144
        logger.info(message: "Mediation Achieved", metadata: [
×
NEW
145
            .publicMetadata(key: "Routing DID", value: mediatorRoutingDID?.string ?? "")
×
NEW
146
        ])
×
NEW
147
        logger.info(message: "Agent running")
×
NEW
148
    }
×
149

150
    /**
151
      This function is used to stop the EdgeAgent.
152
      The function sets the state of EdgeAgent to .stoping.
153
      All ongoing events that was created by the EdgeAgent are stopped.
154
      After all the events are stopped the state of the EdgeAgent is set to .stoped.
155

156
      - Throws: If the current state is not running throws error.
157
      */
NEW
158
     public func stop() async throws {
×
NEW
159
         guard state == .running else { return }
×
NEW
160
         logger.info(message: "Stoping agent")
×
NEW
161
         state = .stoping
×
NEW
162
         cancellables.forEach { $0.cancel() }
×
NEW
163
         connectionManager?.stopAllEvents()
×
NEW
164
         state = .stoped
×
NEW
165
         logger.info(message: "Agent not running")
×
NEW
166
     }
×
167
}
168

169
private func createSecretsStream(
170
    keyRestoration: KeyRestoration,
171
    pluto: Pluto,
172
    castor: Castor
173
) -> AnyPublisher<[Secret], Error> {
2✔
174
    pluto.getAllKeys()
2✔
175
        .first()
2✔
176
        .flatMap { keys in
2✔
NEW
177
            Future {
×
NEW
178
                let privateKeys = await keys.asyncMap {
×
NEW
179
                    try? await keyRestoration.restorePrivateKey($0)
×
NEW
180
                }.compactMap { $0 }
×
NEW
181
                return try parsePrivateKeys(
×
NEW
182
                    privateKeys: privateKeys,
×
NEW
183
                    castor: castor
×
NEW
184
                )
×
NEW
185
            }
×
NEW
186
        }
×
187
        .eraseToAnyPublisher()
2✔
188
}
2✔
189

190
private func parsePrivateKeys(
191
    privateKeys: [PrivateKey],
192
    castor: Castor
NEW
193
) throws -> [Domain.Secret] {
×
NEW
194
    return try privateKeys
×
NEW
195
        .map { $0 as? (PrivateKey & ExportableKey & StorableKey) }
×
NEW
196
        .compactMap { $0 }
×
NEW
197
        .map { privateKey in
×
NEW
198
        return privateKey
×
NEW
199
    }
×
NEW
200
    .map { privateKey in
×
NEW
201
        try parseToSecret(
×
NEW
202
            privateKey: privateKey,
×
NEW
203
            identifier: privateKey.identifier
×
NEW
204
        )
×
NEW
205
    }
×
NEW
206
}
×
207

NEW
208
private func parseToSecret(privateKey: PrivateKey & ExportableKey, identifier: String) throws -> Domain.Secret {
×
NEW
209
    let jwk = privateKey.jwk
×
NEW
210
    guard
×
NEW
211
        let dataJson = try? JSONEncoder().encode(jwk),
×
NEW
212
        let stringJson = String(data: dataJson, encoding: .utf8)
×
NEW
213
    else {
×
NEW
214
        throw CommonError.invalidCoding(message: "Could not encode privateKey.jwk")
×
NEW
215
    }
×
NEW
216
    return .init(
×
NEW
217
        id: identifier,
×
NEW
218
        type: .jsonWebKey2020,
×
NEW
219
        secretMaterial: .jwk(value: stringJson)
×
NEW
220
    )
×
NEW
221
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc