init: start bot write of swift
This commit is contained in:
commit
77672b5c2a
11 changed files with 465 additions and 0 deletions
18
Sources/TelegramModeratorBot/DefaultBotHandlers.swift
Normal file
18
Sources/TelegramModeratorBot/DefaultBotHandlers.swift
Normal file
|
@ -0,0 +1,18 @@
|
|||
import Vapor
|
||||
import SwiftTelegramSdk
|
||||
|
||||
final class DefaultBotHandlers {
|
||||
static func addHandlers() async {
|
||||
await defaultBaseHandler()
|
||||
}
|
||||
|
||||
private static func defaultBaseHandler() async {
|
||||
await botActor.bot.dispatcher.add(TGBaseHandler({ update in
|
||||
guard let message = update.message else { return }
|
||||
let params: TGSendMessageParams = .init(chatId: .chat(message.chat.id), text: """
|
||||
Help message
|
||||
""")
|
||||
try await botActor.bot.sendMessage(params: params)
|
||||
}))
|
||||
}
|
||||
}
|
13
Sources/TelegramModeratorBot/TGBotActor.swift
Normal file
13
Sources/TelegramModeratorBot/TGBotActor.swift
Normal file
|
@ -0,0 +1,13 @@
|
|||
import SwiftTelegramSdk
|
||||
|
||||
actor TGBotActor {
|
||||
private var _bot: TGBot!
|
||||
|
||||
var bot: TGBot {
|
||||
self._bot
|
||||
}
|
||||
|
||||
func setBot(_ bot: TGBot) {
|
||||
self._bot = bot
|
||||
}
|
||||
}
|
110
Sources/TelegramModeratorBot/VaporTGClient.swift
Normal file
110
Sources/TelegramModeratorBot/VaporTGClient.swift
Normal file
|
@ -0,0 +1,110 @@
|
|||
//
|
||||
// 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
|
||||
}
|
||||
}
|
20
Sources/TelegramModeratorBot/configure.swift
Normal file
20
Sources/TelegramModeratorBot/configure.swift
Normal file
|
@ -0,0 +1,20 @@
|
|||
import Foundation
|
||||
import Vapor
|
||||
import SwiftTelegramSdk
|
||||
|
||||
public func configure(_ app: Application) async throws {
|
||||
guard let tgApi: String = Environment.get("TG_BOT_API") else { throw Errors.notVariable("Telegram key is not defined")}
|
||||
app.logger.logLevel = .debug
|
||||
let bot: TGBot = try await .init(connectionType: .longpolling(limit: nil,
|
||||
timeout: nil,
|
||||
allowedUpdates: nil),
|
||||
dispatcher: nil,
|
||||
tgClient: VaporTGClient(client: app.client),
|
||||
tgURI: TGBot.standardTGURL,
|
||||
botId: tgApi,
|
||||
log: app.logger)
|
||||
await botActor.setBot(bot)
|
||||
await DefaultBotHandlers.addHandlers()
|
||||
try await botActor.bot.start()
|
||||
// try routes(app)
|
||||
}
|
3
Sources/TelegramModeratorBot/errors.swift
Normal file
3
Sources/TelegramModeratorBot/errors.swift
Normal file
|
@ -0,0 +1,3 @@
|
|||
enum Errors: Error {
|
||||
case notVariable(String)
|
||||
}
|
18
Sources/TelegramModeratorBot/main.swift
Normal file
18
Sources/TelegramModeratorBot/main.swift
Normal file
|
@ -0,0 +1,18 @@
|
|||
// The Swift Programming Language
|
||||
// https://docs.swift.org/swift-book
|
||||
|
||||
import Vapor
|
||||
import SwiftTelegramSdk
|
||||
|
||||
var env = try Environment.detect()
|
||||
try LoggingSystem.bootstrap(from: &env)
|
||||
|
||||
let eventLoop: EventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount * 4)
|
||||
let app: Application = try await Application.make(env, Application.EventLoopGroupProvider.shared(eventLoop))
|
||||
|
||||
let botActor: TGBotActor = .init()
|
||||
|
||||
defer { app.shutdown() }
|
||||
|
||||
try await configure(app)
|
||||
try await app.execute()
|
8
Sources/TelegramModeratorBot/routes.swift
Normal file
8
Sources/TelegramModeratorBot/routes.swift
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
/*
|
||||
import Vapor
|
||||
|
||||
func routes(_ app: Application) throws {
|
||||
try app.register(collection: TelegramController())
|
||||
}
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue