Skip to content

Commit

Permalink
Update StorageManager and VDCCollection API usage (#81)
Browse files Browse the repository at this point in the history
Signed-off-by: Tiago Nascimento <[email protected]>
Co-authored-by: Gregorio <[email protected]>
  • Loading branch information
theosirian and w4ll3 authored Jan 14, 2025
1 parent a027834 commit 57532e4
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 40 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let package = Package(
targets: ["SpruceIDMobileSdk"])
],
dependencies: [
.package(url: "https://github.com/spruceid/mobile-sdk-rs.git", from: "0.4.3"),
.package(url: "https://github.com/spruceid/mobile-sdk-rs.git", from: "0.5.1"),
// .package(path: "../mobile-sdk-rs"),
.package(url: "https://github.com/apple/swift-algorithms", from: "1.2.0")
],
Expand Down
52 changes: 26 additions & 26 deletions Sources/MobileSdk/CredentialPack.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,32 +159,32 @@ public class CredentialPack {
/// Persists the CredentialPack in the StorageManager, and persists all credentials in the VdcCollection.
///
/// If a credential already exists in the VdcCollection (matching on id), then it will be skipped without updating.
public func save(storageManager: StorageManagerInterface) throws {
public func save(storageManager: StorageManagerInterface) async throws {
let vdcCollection = VdcCollection(engine: storageManager)
for credential in list() {
do {
if (try vdcCollection.get(id: credential.id())) == nil {
try vdcCollection.add(credential: try credential.intoGenericForm())
if (try await vdcCollection.get(id: credential.id())) == nil {
try await vdcCollection.add(credential: try credential.intoGenericForm())
}
} catch {
throw CredentialPackError.credentialStorage(id: credential.id(), reason: error)
}
}

try self.intoContents().save(storageManager: storageManager)
try await self.intoContents().save(storageManager: storageManager)
}

/// Remove this CredentialPack from the StorageManager.
///
/// Credentials that are in this pack __are__ removed from the VdcCollection.
public func remove(storageManager: StorageManagerInterface) throws {
try self.intoContents().remove(storageManager: storageManager)
public func remove(storageManager: StorageManagerInterface) async throws {
try await self.intoContents().remove(storageManager: storageManager)
}

/// Loads all CredentialPacks from the StorageManager.
public static func loadAll(storageManager: StorageManagerInterface) throws -> [CredentialPack] {
try CredentialPackContents.list(storageManager: storageManager).map { contents in
try contents.load(vdcCollection: VdcCollection(engine: storageManager))
public static func loadAll(storageManager: StorageManagerInterface) async throws -> [CredentialPack] {
try await CredentialPackContents.list(storageManager: storageManager).asyncMap { contents in
try await contents.load(vdcCollection: VdcCollection(engine: storageManager))
}
}

Expand Down Expand Up @@ -247,10 +247,10 @@ public struct CredentialPackContents {
}

/// Loads all of the credentials from the VdcCollection for this CredentialPack.
public func load(vdcCollection: VdcCollection) throws -> CredentialPack {
let credentials = try credentials.map { credentialId in
public func load(vdcCollection: VdcCollection) async throws -> CredentialPack {
let credentials = try await credentials.asyncMap { credentialId in
do {
guard let credential = try vdcCollection.get(id: credentialId) else {
guard let credential = try await vdcCollection.get(id: credentialId) else {
throw CredentialPackError.credentialNotFound(id: credentialId)
}
return try ParsedCredential.parseFromCredential(credential: credential)
Expand All @@ -263,14 +263,14 @@ public struct CredentialPackContents {
}

/// Clears all CredentialPacks.
public static func clear(storageManager: StorageManagerInterface) throws {
public static func clear(storageManager: StorageManagerInterface) async throws {
do {
try storageManager.list()
try await storageManager.list()
.filter { file in
file.hasPrefix(Self.storagePrefix)
}
.forEach { file in
try storageManager.remove(key: file)
.asyncForEach { file in
try await storageManager.remove(key: file)
}
} catch {
throw CredentialPackError.clearing(reason: error)
Expand All @@ -280,14 +280,14 @@ public struct CredentialPackContents {
/// Lists all CredentialPacks.
///
/// These can then be individually loaded. For eager loading of all packs, see `CredentialPack.loadAll`.
public static func list(storageManager: StorageManagerInterface) throws -> [CredentialPackContents] {
public static func list(storageManager: StorageManagerInterface) async throws -> [CredentialPackContents] {
do {
return try storageManager.list()
return try await storageManager.list()
.filter { file in
file.hasPrefix(Self.storagePrefix)
}
.map { file in
guard let contents = try storageManager.get(key: file) else {
.asyncMap { file in
guard let contents = try await storageManager.get(key: file) else {
throw CredentialPackError.missing(file: file)
}
return try CredentialPackContents(fromBytes: contents)
Expand All @@ -297,10 +297,10 @@ public struct CredentialPackContents {
}
}

public func save(storageManager: StorageManagerInterface) throws {
public func save(storageManager: StorageManagerInterface) async throws {
let bytes = try self.toBytes()
do {
try storageManager.add(key: self.storageKey(), value: bytes)
try await storageManager.add(key: self.storageKey(), value: bytes)
} catch {
throw CredentialPackError.storage(reason: error)
}
Expand All @@ -326,18 +326,18 @@ public struct CredentialPackContents {
/// Remove this CredentialPack from the StorageManager.
///
/// Credentials that are in this pack __are__ removed from the VdcCollection.
public func remove(storageManager: StorageManagerInterface) throws {
public func remove(storageManager: StorageManagerInterface) async throws {
let vdcCollection = VdcCollection(engine: storageManager)
self.credentials.forEach { credential in
await self.credentials.asyncForEach { credential in
do {
try vdcCollection.delete(id: credential)
try await vdcCollection.delete(id: credential)
} catch {
print("failed to remove Credential '\(credential)' from the VdcCollection")
}
}

do {
try storageManager.remove(key: self.storageKey())
try await storageManager.remove(key: self.storageKey())
} catch {
throw CredentialPackError.removing(reason: error)
}
Expand Down
18 changes: 9 additions & 9 deletions Sources/MobileSdk/StorageManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class StorageManager: NSObject, StorageManagerInterface {
///
/// - Returns: An URL for the named file in the app's Application Support directory.

private func path(file: String) -> URL? {
private func path(file: String) async -> URL? {
do {
// Get the applications support dir, and tack the name of the thing we're storing on the end of it.
// This does imply that `file` should be a valid filename.
Expand Down Expand Up @@ -71,8 +71,8 @@ public class StorageManager: NSObject, StorageManagerInterface {
///
/// - Returns: a boolean indicating success

public func add(key: Key, value: Value) throws {
guard let file = path(file: key) else { throw StorageManagerError.InternalError }
public func add(key: Key, value: Value) async throws {
guard let file = await path(file: key) else { throw StorageManagerError.InternalError }

do {
try value.write(to: file, options: .completeFileProtection)
Expand All @@ -88,8 +88,8 @@ public class StorageManager: NSObject, StorageManagerInterface {
///
/// - Returns: optional data potentially containing the value associated with the key; may be `nil`

public func get(key: Key) throws -> Value? {
guard let file = path(file: key) else { throw StorageManagerError.InternalError }
public func get(key: Key) async throws -> Value? {
guard let file = await path(file: key) else { throw StorageManagerError.InternalError }

do {
return try Data(contentsOf: file)
Expand All @@ -115,8 +115,8 @@ public class StorageManager: NSObject, StorageManagerInterface {
///
/// - Returns: a list of items in storage

public func list() throws -> [Key] {
guard let asdir = path(file: "")?.path else { return [String]() }
public func list() async throws -> [Key] {
guard let asdir = await path(file: "")?.path else { return [String]() }

do {
return try FileManager.default.contentsOfDirectory(atPath: asdir)
Expand All @@ -134,8 +134,8 @@ public class StorageManager: NSObject, StorageManagerInterface {
///
/// - Returns: a boolean indicating success; at present, there is no failure path, but this may change

public func remove(key: Key) throws {
guard let file = path(file: key) else { return }
public func remove(key: Key) async throws {
guard let file = await path(file: key) else { return }

do {
try FileManager.default.removeItem(at: file)
Expand Down
22 changes: 22 additions & 0 deletions Sources/MobileSdk/Utils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Foundation

extension Sequence {
func asyncMap<T>(_ transform: @escaping (Element) async throws -> T) async rethrows -> [T] {
var results = [T]()
for element in self {
let result = try await transform(element)
results.append(result)
}
return results
}
}

extension Sequence {
func asyncForEach(
_ operation: (Element) async throws -> Void
) async rethrows {
for element in self {
try await operation(element)
}
}
}
16 changes: 12 additions & 4 deletions Tests/MobileSdkTests/StorageManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@ import XCTest
@testable import SpruceIDMobileSdk

final class StorageManagerTest: XCTestCase {
func testStorage() throws {
func testStorage() async throws {
let storeman = StorageManager()
let key = "test_key"
let value = Data("Some random string of text. 😎".utf8)

XCTAssertNoThrow(try storeman.add(key: key, value: value))
do {
try await storeman.add(key: key, value: value)
} catch {
XCTFail("Failed StorageManager.add")
}

let payload = try storeman.get(key: key)
let payload = try await storeman.get(key: key)

XCTAssert(payload == value, "\(classForCoder):\(#function): Mismatch between stored & retrieved value.")

XCTAssertNoThrow(try storeman.remove(key: key))
do {
try await storeman.remove(key: key)
} catch {
XCTFail("Failed StorageManager.remove")
}
}
}

0 comments on commit 57532e4

Please sign in to comment.