110 lines
4 KiB
Swift
110 lines
4 KiB
Swift
//
|
|
// VaporTGClient.swift
|
|
// Vapor-telegram-bot-example
|
|
//
|
|
// Created by Oleh Hudeichuk on 01.07.2024.
|
|
//
|
|
|
|
import Foundation
|
|
import Vapor
|
|
import SwiftTelegramSdk
|
|
|
|
public enum TGHTTPMediaType: String, Equatable {
|
|
case formData
|
|
case json
|
|
}
|
|
|
|
private struct TGEmptyParams: Encodable {}
|
|
|
|
public final class VaporTGClient: TGClientPrtcl {
|
|
|
|
public typealias HTTPMediaType = SwiftTelegramSdk.HTTPMediaType
|
|
public var log: Logging.Logger = .init(label: "VaporTGClient")
|
|
private let client: Vapor.Client
|
|
|
|
public init(client: Vapor.Client) {
|
|
self.client = client
|
|
}
|
|
|
|
@discardableResult
|
|
public func post<Params: Encodable, Response: Decodable>
|
|
(
|
|
_ url: URL,
|
|
params: Params? = nil,
|
|
as mediaType: HTTPMediaType? = nil
|
|
) async throws -> Response {
|
|
let clientResponse: ClientResponse = try await client.post(URI(string: url.absoluteString), headers: HTTPHeaders()) { clientRequest in
|
|
if mediaType == .formData || mediaType == nil {
|
|
#warning("THIS CODE FOR FAST FIX, BECAUSE https://github.com/vapor/multipart-kit/issues/63 not accepted yet")
|
|
var rawMultipart: (body: NSMutableData, boundary: String)!
|
|
do {
|
|
/// Content-Disposition: form-data; name="nested_object"
|
|
///
|
|
/// { json string }
|
|
if let currentParams: Params = params {
|
|
rawMultipart = try currentParams.toMultiPartFormData(log: log)
|
|
} else {
|
|
rawMultipart = try TGEmptyParams().toMultiPartFormData(log: log)
|
|
}
|
|
} catch {
|
|
log.critical("Post request error: \(error.logMessage)")
|
|
}
|
|
clientRequest.headers.add(name: "Content-Type", value: "multipart/form-data; boundary=\(rawMultipart.boundary)")
|
|
let buffer = ByteBuffer.init(data: rawMultipart.body as Data)
|
|
clientRequest.body = buffer
|
|
/// Debug
|
|
// TGBot.log.critical("url: \(url)\n\(String(decoding: rawMultipart.body, as: UTF8.self))")
|
|
} else {
|
|
let mediaType: Vapor.HTTPMediaType = if let mediaType {
|
|
.init(type: mediaType.type, subType: mediaType.subType, parameters: mediaType.parameters)
|
|
} else {
|
|
.json
|
|
}
|
|
try clientRequest.content.encode(params ?? (TGEmptyParams() as! Params), as: mediaType)
|
|
}
|
|
}
|
|
let telegramContainer: TGTelegramContainer = try clientResponse.content.decode(TGTelegramContainer<Response>.self)
|
|
return try processContainer(telegramContainer)
|
|
}
|
|
|
|
@discardableResult
|
|
public func post<Response: Decodable>(_ url: URL) async throws -> Response {
|
|
try await post(url, params: TGEmptyParams(), as: nil)
|
|
}
|
|
|
|
private func processContainer<T: Decodable>(_ container: TGTelegramContainer<T>) throws -> T {
|
|
guard container.ok else {
|
|
let desc = """
|
|
Response marked as `not Ok`, it seems something wrong with request
|
|
Code: \(container.errorCode ?? -1)
|
|
\(container.description ?? "Empty")
|
|
"""
|
|
let error = BotError(
|
|
type: .server,
|
|
description: desc
|
|
)
|
|
log.error(error.logMessage)
|
|
throw error
|
|
}
|
|
|
|
guard let result = container.result else {
|
|
let error = BotError(
|
|
type: .server,
|
|
reason: "Response marked as `Ok`, but doesn't contain `result` field."
|
|
)
|
|
log.error(error.logMessage)
|
|
throw error
|
|
}
|
|
|
|
let logString = """
|
|
|
|
Response:
|
|
Code: \(container.errorCode ?? 0)
|
|
Status OK: \(container.ok)
|
|
Description: \(container.description ?? "Empty")
|
|
|
|
"""
|
|
log.trace(logString.logMessage)
|
|
return result
|
|
}
|
|
}
|