You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.5 KiB
114 lines
3.5 KiB
|
|
import Foundation |
|
|
|
public class Connection { |
|
private var endpoint: URL? |
|
private var token: String? |
|
|
|
@Published public var authenticated = false |
|
|
|
public init() { } |
|
|
|
private func authenticatedGET(service: String, |
|
queryItems: [String : String] = .init()) |
|
async -> Data? { |
|
guard let token = token else { |
|
return nil |
|
} |
|
|
|
let url = apiURL(service) |
|
var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)! |
|
urlComponents.queryItems = queryItems.map({ (key, string) in |
|
URLQueryItem(name: key, value: string) |
|
}) |
|
let finalURL = urlComponents.url! |
|
|
|
var request = URLRequest(url: finalURL) |
|
request.httpMethod = "GET" |
|
request.setValue("Bearer: \(token)", forHTTPHeaderField: "Authorization") |
|
|
|
return try? await URLSession.shared.data(for: request).0 |
|
} |
|
|
|
public func connect(info: ConnectionInfo) async { |
|
self.token = nil |
|
self.endpoint = URL(string: info.serverAddress) |
|
self.authenticated = false |
|
let body = try? JSONEncoder().encode(info.credentials) |
|
|
|
var request = URLRequest(url: apiURL("authenticate")) |
|
request.httpMethod = "POST" |
|
request.httpBody = body |
|
request.addValue("application/json", forHTTPHeaderField: "Content-Type") |
|
request.addValue("application/json", forHTTPHeaderField: "Accept") |
|
|
|
if let result = try? await URLSession.shared.data(for: request) { |
|
if let response = result.1 as? HTTPURLResponse { |
|
if let token = response.value(forHTTPHeaderField: "Set-Cookie") { |
|
self.token = token.replacingOccurrences(of: "auth_token=", with: "") |
|
DispatchQueue.main.async { |
|
self.authenticated = true |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
public func conversations() async -> [Conversation]? { |
|
if let data = await authenticatedGET(service: "conversations") { |
|
if let conversations = try? JSONDecoder().decode([RawConversation].self, from: data) { |
|
return conversations.map { |
|
$0.conversation |
|
} |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
public func messages(in conversation: Conversation) async -> [Message]? { |
|
if let data = await authenticatedGET(service: "messages", queryItems: ["guid" : conversation.guid]) { |
|
if let messages = try? JSONDecoder().decode([RawMessage].self, from: data) { |
|
return messages.map { |
|
$0.message |
|
} |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
} |
|
|
|
extension Connection { |
|
private func apiURL(_ suffix: String) -> URL { |
|
endpoint? |
|
.appendingPathComponent("api") |
|
.appendingPathComponent(suffix) |
|
?? |
|
.init(fileURLWithPath: "") |
|
} |
|
} |
|
|
|
extension Connection : ObservableObject { |
|
|
|
} |
|
|
|
public struct ConnectionInfo : Hashable, Codable { |
|
public var serverAddress: String |
|
public var credentials: Credentials |
|
|
|
public init(serverAddress: String, credentials: Credentials) { |
|
self.serverAddress = serverAddress |
|
self.credentials = credentials |
|
} |
|
} |
|
|
|
public struct Credentials : Hashable, Codable { |
|
public var username: String = "" |
|
public var password: String = "" |
|
|
|
public init(username: String, password: String) { |
|
self.username = username |
|
self.password = password |
|
} |
|
}
|
|
|