Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Commit

Permalink
Implement fetching offerings from a PFI DID
Browse files Browse the repository at this point in the history
This is incredibly hacky right now, and needs to be cleaned up. But it's working locally with the tbdex-pfi-exemplar running locally!
  • Loading branch information
amika-sq committed Jan 12, 2024
1 parent f142008 commit 86323c2
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 8 deletions.
17 changes: 17 additions & 0 deletions Sources/tbDEX/HttpClient/GetOfferingsFilter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

public struct GetOfferingFilter: Codable {
let id: String?
let payinCurrency: String?
let payoutCurrency: String?

public init(
id: String? = nil,
payinCurrency: String? = nil,
payoutCurrency: String? = nil
) {
self.id = id
self.payinCurrency = payinCurrency
self.payoutCurrency = payoutCurrency
}
}
72 changes: 72 additions & 0 deletions Sources/tbDEX/HttpClient/HttpClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Foundation

public enum HttpClient {

public struct HttpClientError: Error {
let reason: String
}

static let session = URLSession(configuration: .default)

public struct GetOfferingsResponse: Codable {
public let data: [Offering]
}

/// Get `Offering`s from a PFI.
public static func getOfferings(
pfiDidUri: String,
filter: GetOfferingFilter? = nil
) async -> Result<GetOfferingsResponse, HttpClientError> {
guard let pfiServiceEndpoint = await getPFIServiceEndpoint(pfiDidUri: pfiDidUri) else {
return .failure(.init(reason: "DID does not have service of type PFI"))
}

guard var components = URLComponents(string: "\(pfiServiceEndpoint)/offerings") else {
return .failure(.init(reason: "Could not create URLComponents from PFI service endpoint"))
}

components.queryItems = filter?.queryItems()

guard let url = components.url else {
return .failure(.init(reason: "Could not create URL from URLComponents"))
}

do {
let response = try await URLSession.shared.data(from: url)

// Set up the JSONDecoder with a custom date decoding strategy
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
let container = try decoder.singleValueContainer()
let dateString = try container.decode(String.self)

// Create a custom ISO8601DateFormatter
let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]

if let date = dateFormatter.date(from: dateString) {
return date
} else {
throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "Invalid date: \(dateString)"
)
}
})

let offerings = try decoder.decode(GetOfferingsResponse.self, from: response.0)
return .success(offerings)
} catch {
return .failure(.init(reason: "Error while fetching offerings: \(error)"))
}
}

private static func getPFIServiceEndpoint(pfiDidUri: String) async -> String? {
let resolutionResult = await DidResolver.resolve(didUri: pfiDidUri)
if let service = resolutionResult.didDocument?.service?.first(where: { $0.type == "PFI" }) {
return service.serviceEndpoint
} else {
return nil
}
}
}
17 changes: 17 additions & 0 deletions Sources/tbDEX/Utilities/Encodable+QueryItems.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

extension Encodable {

/// Returns an array of `URLQueryItem` representing the `Encodable` object.
func queryItems() -> [URLQueryItem] {
let encoder = JSONEncoder()
guard let data = try? encoder.encode(self) else {
return []
}
guard let dictionary = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
return []
}
return dictionary.map { URLQueryItem(name: $0.key, value: "\($0.value)") }
}

}
8 changes: 0 additions & 8 deletions Tests/tbDEXTests/Dids/DidJwkTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,4 @@ final class DidJwkTests: XCTestCase {
XCTAssertNil(resolutionResult.didResolutionMetadata.error)
}

func test_resolveIon() async throws {
let didUri =
"did:ion:EiC8RWXbMYyFsqQ5hxP3k2GVvqPaeP8EAN6i9wQblzj__Q:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpb24iOiJyZXBsYWNlIiwiZG9jdW1lbnQiOnsicHVibGljS2V5cyI6W3siaWQiOiJkd24tc2lnIiwicHVibGljS2V5SndrIjp7ImNydiI6IkVkMjU1MTkiLCJrdHkiOiJPS1AiLCJ4IjoiSUM3NnB5QnAtNXFYbFpHS2I1M1V3M1NEWXJfY3AzaUpyLTFzSlBqb2hsSSJ9LCJwdXJwb3NlcyI6WyJhdXRoZW50aWNhdGlvbiIsImFzc2VydGlvbk1ldGhvZCJdLCJ0eXBlIjoiSnNvbldlYktleTIwMjAifV0sInNlcnZpY2VzIjpbeyJpZCI6InBmaSIsInNlcnZpY2VFbmRwb2ludCI6Imh0dHA6Ly9sb2NhbGhvc3Q6OTAwMCIsInR5cGUiOiJQRkkifV19fV0sInVwZGF0ZUNvbW1pdG1lbnQiOiJFaUN6SENrVEJtNDIwbEo3alluZElCa1VzamktanJoMnhYdEt4NHoxWm1QVEpBIn0sInN1ZmZpeERhdGEiOnsiZGVsdGFIYXNoIjoiRWlBZFJYbHhJNlpadzhUbE9NR2xEcUtaLVkwdlF4WV8xanJWVVUtcWgtUWZHUSIsInJlY292ZXJ5Q29tbWl0bWVudCI6IkVpQ1hZaVEyOWdZTXEzWHk0WEt2QnVTcjItNFRVWHhBVEY0QXpKald2Y3ptc1EifX0"

let resolutionResult = await DidIon.resolve(didUri: didUri)
XCTAssertNotNil(resolutionResult.didDocument)
}

}

0 comments on commit 86323c2

Please sign in to comment.