Contents

nerzh/swift-telegram-bot

🤖 The wrapper for the Telegram Bot API written in Swift. It's not a framework. There is no special syntax here. This is a library that implements all [Telegram Bot API methods](https://core.telegram.org/bots/api#available-methods), which is available to you to work with Vapor, S

Bot configuration.

Define bot ID

import SwiftTelegramBot
import Logging

let tgApi: String = "XXXXXXXXXX:YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
var logger: Logger = .init(label: "swift_telegram_bot")
logger.logLevel = .error

Define connection type

LongPolling
let connectionType: TGConnectionType = .longpolling()
WebHook
let connectionType: TGConnectionType = .webhook(webHookURL: URL(string: "\(TG_WEBHOOK_DOMAIN!)/\(TGWebHookRouteName)")!)
/// Add route for webhook. For example Vapor:

/// routes.swift
func routes(_ app: Application) throws {
    try app.register(collection: TelegramController())
}


/// TelegramController.swift
final class TelegramController: RouteCollection {
    func boot(routes: Vapor.RoutesBuilder) throws {
        routes.post(TGWebHookRouteName, use: telegramWebHook)
    }

    func telegramWebHook(_ req: Request) async throws -> Bool {
        let update: TGUpdate = try req.content.decode(TGUpdate.self)
        Task { await bot.processing(updates: [update]) }
        return true
    }
}

Start bot with added handlers

let bot: TGBot = try await .init(connectionType: connectionType,
                                 tgClient: TGClientDefault(),
                                 tgURI: TGBot.standardTGURL,
                                 botId: botId,
                                 log: logger)

/// add dispatcher with some bot logic
try await bot.add(dispatcher: TestDispatcher(bot: bot, logger: logger))
/// try await bot.add(dispatcher: SecondDispatcher(bot: bot, logger: logger))
/// etc

try await bot.start()

TestDispatcher code example

import SwiftTelegramBot

class TestDispatcher: TGDefaultDispatcher, @unchecked Sendable {
        
    override
    func handle() async {
        /// defaultBaseHandler example
        await add(TGBaseHandler({ update in
            guard let message = update.message else { return }
            let params: TGSendMessageParams = .init(chatId: .chat(message.chat.id), text: "TGBaseHandler")
            try await self.bot.sendMessage(params: params)
        }))

        /// commandPingHandler example
        await add(TGCommandHandler(commands: ["/ping"]) { update in
            try await update.message?.reply(text: "pong", bot: self.bot)
        })

        /// commandShowButtonsHandler example
        await add(TGCommandHandler(commands: ["/show_buttons"]) { update in
            guard let userId = update.message?.from?.id else { fatalError("user id not found") }
            let buttons: [[TGInlineKeyboardButton]] = [
                [.init(text: "Button 1", callbackData: "press 1"), .init(text: "Button 2", callbackData: "press 2")]
            ]
            let keyboard: TGInlineKeyboardMarkup = .init(inlineKeyboard: buttons)
            let params: TGSendMessageParams = .init(chatId: .chat(userId),
                                                    text: "Keyboard active",
                                                    replyMarkup: .inlineKeyboardMarkup(keyboard))
            try await self.bot.sendMessage(params: params)
        })

        /// buttonsActionHandler 1 example
        await add(TGCallbackQueryHandler(pattern: "press 1") { update in
            await self.bot.log.info("press 1")
            guard let userId = update.callbackQuery?.from.id else { fatalError("user id not found") }
            let params: TGAnswerCallbackQueryParams = .init(callbackQueryId: update.callbackQuery?.id ?? "0",
                                                            text: update.callbackQuery?.data  ?? "data not exist",
                                                            showAlert: nil,
                                                            url: nil,
                                                            cacheTime: nil)
            try await self.bot.answerCallbackQuery(params: params)
            try await self.bot.sendMessage(params: .init(chatId: .chat(userId), text: "press 1"))
        })

        /// buttonsActionHandler 2 example
        await add(TGCallbackQueryHandler(pattern: "press 2") { update in
            await self.bot.log.info("press 2")
            guard let userId = update.callbackQuery?.from.id else { fatalError("user id not found") }
            let params: TGAnswerCallbackQueryParams = .init(callbackQueryId: update.callbackQuery?.id ?? "0",
                                                            text: update.callbackQuery?.data  ?? "data not exist",
                                                            showAlert: nil,
                                                            url: nil,
                                                            cacheTime: nil)
            try await self.bot.answerCallbackQuery(params: params)
            try await self.bot.sendMessage(params: .init(chatId: .chat(userId), text: "press 2"))
        })
    }
}

Advanced Example Usage

You should to implement TGClientPrtcl protocol

To configure and run a bot with or without any framework, you need to use TGClientDefault or implement a simple TGClient protocol to send requests to the network with Content-Type: multipart/form-data. You can see an example here: TGClientDefault

public protocol TGClientPrtcl {
    
    @discardableResult
    func post<Params: Encodable, Response: Decodable>(_ url: URL, params: Params?, as mediaType: HTTPMediaType?) async throws -> Response
    
    @discardableResult
    func post<Response: Decodable>(_ url: URL) async throws -> Response
}

Add to your Vapor project with Swift Package Manager

add to yor Package.json

// swift-tools-version:6.0

import PackageDescription

var packageDependencies: [Package.Dependency] = [
    .package(url: "https://github.com/vapor/vapor.git", .upToNextMajor(from: "4.57.0")),
]

packageDependencies.append(.package(url: "https://github.com/nerzh/swift-telegram-bot", .upToNextMajor(from: "4.2.0")))


let package = Package(
    name: "Telegram-bot-example",
    platforms: [
        .macOS(.v12)
    ],
    dependencies: packageDependencies,
    targets: [
        .executableTarget(
            name: "Telegram-bot-example",
            dependencies: [
                .product(name: "Vapor", package: "vapor"),
                .product(name: "SwiftTelegramBot", package: "swift-telegram-bot"),
            ]
        )
    ]
)


Acknowledgments

Inspired by Telegrammer

Package Metadata

Repository: nerzh/swift-telegram-bot

Default branch: master

README: README.md