Skip to content

Bot Service

Bingo Bot is a multi-platform bot service supporting Telegram and Discord, providing service management, notification delivery, and channel subscription features.

Core Features

  • Multi-Platform Support - Telegram and Discord
  • Service Management - Health checks, version queries, maintenance mode
  • Notification Subscription - Channel subscription management and system notifications
  • Unified Interface - Shared business logic and data storage across platforms

Supported Platforms

Telegram

Built on telebot.v3:

  • Bot command interactions
  • Channel message broadcasting
  • Group management

Discord

Built on discordgo:

  • Slash Commands
  • Channel message broadcasting
  • Server management

Quick Start

1. Create Bot

Telegram Bot

  1. Find @BotFather in Telegram
  2. Send /newbot to create a new bot
  3. Follow prompts to set bot name and username
  4. Get Bot Token (keep it secure and never expose it publicly)

Discord Bot

  1. Visit Discord Developer Portal
  2. Click "New Application"
  3. Go to "Bot" tab, click "Add Bot"
  4. Get Bot Token from "TOKEN" section
  5. Enable necessary Intents (e.g., Message Content Intent)

2. Configuration

Create bingo-bot.yaml:

yaml
# Bot server
server:
  name: bingo-bot
  mode: release
  addr: :18080
  timezone: Asia/Shanghai
  key: your-secret-key

# Bot configuration
bot:
  telegram: "YOUR_TELEGRAM_BOT_TOKEN"
  discord: "YOUR_DISCORD_BOT_TOKEN"

# MySQL configuration
mysql:
  host: mysql:3306
  username: root
  password: root
  database: bingo
  maxIdleConnections: 100
  maxOpenConnections: 100
  maxConnectionLifeTime: 10s
  logLevel: 4

# Redis configuration
redis:
  host: redis:6379
  password: ""
  database: 1

# JWT configuration
jwt:
  secretKey: your-jwt-secret-key
  ttl: 1440  # Token expiration (minutes)

# Logging
log:
  level: info
  days: 7
  format: console
  console: true
  maxSize: 100
  compress: true
  path: storage/log/bot.log

feature:
  profiling: true

# Mail service
mail:
  host: "smtp.example.com"
  port: 465
  username: "[email protected]"
  password: "your-password"
  fromAddr: "[email protected]"
  fromName: "Bingo Bot"

# Verification code
code:
  length: 6
  ttl: 5       # Expiration (minutes)
  waiting: 1   # Resend wait time (minutes)

⚠️ Security Warning:

  • Replace YOUR_TELEGRAM_BOT_TOKEN and YOUR_DISCORD_BOT_TOKEN with your actual tokens from BotFather and Discord Developer Portal
  • Never commit configuration files containing real tokens to Git repositories or share them publicly
  • Consider using environment variables or secret management services to store tokens
  • If a token is leaked, regenerate it immediately on the respective platform

3. Start Service

bash
# Use default configuration
./bingo-bot

# Specify configuration file
./bingo-bot -c /path/to/bingo-bot.yaml

4. Add Bot to Channel

Telegram

  1. Add bot to group or channel
  2. Grant necessary permissions (send messages, manage messages, etc.)

Discord

  1. In Developer Portal, go to "OAuth2" > "URL Generator":
    • Scopes: bot, applications.commands
    • Select required Bot Permissions
  2. Copy generated URL and open in browser
  3. Select server and authorize

Available Commands

Service Management

CommandDescriptionExample
/ping or /pongHealth check/pingpong
/healthzService status/healthzok
/versionView version/versionv1.0.0
/maintenanceToggle maintenance/maintenanceOperation success

Subscription Management

CommandDescriptionExample
/subscribeSubscribe to notifications/subscribeSuccessfully subscribe
/unsubscribeUnsubscribe/unsubscribeSuccessfully unsubscribe

Usage Examples

Telegram Bot

User: /ping
Bot:  pong

User: /subscribe
Bot:  Successfully subscribe, enjoy it!

Discord Bot (Slash Commands)

/ping
Bot: pong

/subscribe
Bot: Successfully subscribe, enjoy it!

Notification System

Bot service supports pushing system notifications to subscribed channels.

Database Schema

Subscription data is stored in bot_channels table:

sql
CREATE TABLE `bot_channels` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `source` varchar(20) NOT NULL COMMENT 'Platform: telegram, discord',
  `channel_id` varchar(100) NOT NULL COMMENT 'Channel ID',
  `author` text COMMENT 'Subscriber info (JSON)',
  `status` tinyint NOT NULL DEFAULT '1' COMMENT 'Status: 1-enabled, 0-disabled',
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_source_channel` (`source`, `channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Send Notifications

Trigger notifications from other services:

go
import (
    "bingo/internal/pkg/store"
    "bingo/internal/pkg/model/bot"
)

// Get all subscribed channels
channels, err := store.S.Channels().List(ctx, &bot.ListChannelsOptions{
    Status: bot.StatusEnabled,
})

// Send message to each channel
for _, channel := range channels {
    sendMessage(channel.Source, channel.ChannelID, "System notification: Service updated")
}

Architecture

Layered Design

┌─────────────────────────────────────┐
│  Platform Layer (Telegram/Discord) │  ← Platform adapters
├─────────────────────────────────────┤
│     Controller Layer                │  ← Controllers
├─────────────────────────────────────┤
│     Business Logic (Biz)            │  ← Business logic
├─────────────────────────────────────┤
│     Data Access (Store)             │  ← Data access
└─────────────────────────────────────┘

Code Structure

internal/bot/
├── biz/               # Business logic
│   ├── bot/
│   └── syscfg/
├── telegram/         # Telegram platform
│   ├── controller/
│   ├── middleware/
│   ├── router.go
│   └── run.go
├── discord/          # Discord platform
│   ├── controller/
│   ├── middleware/
│   ├── client/
│   ├── router.go
│   └── run.go
├── app.go
└── run.go

Advanced Features

Custom Commands

1. Add Command Handler

go
// internal/bot/telegram/controller/v1/custom/custom.go
package custom

import "gopkg.in/telebot.v3"

type CustomController struct {
    // ...
}

func (ctrl *CustomController) Hello(c telebot.Context) error {
    return c.Send("Hello, " + c.Sender().FirstName + "!")
}

2. Register Route

go
// internal/bot/telegram/router.go
func RegisterRouter(b *telebot.Bot) {
    customCtrl := custom.New(store.S)
    b.Handle("/hello", customCtrl.Hello)
}

Middleware

go
// Logging middleware
func Logger(next telebot.HandlerFunc) telebot.HandlerFunc {
    return func(c telebot.Context) error {
        start := time.Now()
        err := next(c)
        log.Infof("Command: %s, User: %s, Duration: %v",
            c.Text(), c.Sender().Username, time.Since(start))
        return err
    }
}

// Register middleware
b.Use(Logger)

Permission Control

go
// Admin-only middleware
func AdminOnly(next telebot.HandlerFunc) telebot.HandlerFunc {
    return func(c telebot.Context) error {
        if !isAdmin(c.Sender().ID) {
            return c.Send("Admin only")
        }
        return next(c)
    }
}

// Use permission middleware
b.Handle("/maintenance", ctrl.ToggleMaintenance, AdminOnly)

Operations & Monitoring

View Logs

bash
# Real-time logs
tail -f storage/log/bot.log

# Error logs
grep "ERROR" storage/log/bot.log

Performance Profiling

If profiling is enabled:

bash
# Heap memory
curl http://localhost:18080/debug/pprof/heap

# Goroutines
curl http://localhost:18080/debug/pprof/goroutine

# CPU profile (30s)
curl http://localhost:18080/debug/pprof/profile?seconds=30 > cpu.prof

Common Issues

1. Bot Not Responding

Check:

  • Bot Token correctness
  • Network connectivity
  • Bot added to channel
  • Sufficient permissions

2. Subscription Failed

Possible Causes:

  • Database connection failure
  • Duplicate channel ID
  • Insufficient permissions

3. Message Send Failed

Check:

  • Bot in channel
  • Sufficient permissions
  • Correct channel ID
  • Rate limits (Telegram: 30 msg/sec, Discord: 5 req/sec)

Best Practices

1. Error Handling

go
func (ctrl *ServerController) SomeCommand(c telebot.Context) error {
    result, err := ctrl.b.DoSomething(ctx)
    if err != nil {
        log.Errorf("Operation failed: %v", err)
        return c.Send("Operation failed, please try again")
    }
    return c.Send(fmt.Sprintf("Success: %s", result))
}

2. Message Formatting

go
// Telegram supports Markdown and HTML
func (ctrl *ServerController) Status(c telebot.Context) error {
    message := `
*Service Status*
━━━━━━━━━━━━
🟢 API Server: Running
🟢 Scheduler: Running
🟡 Bot: Maintenance
━━━━━━━━━━━━
Updated: %s
    `
    return c.Send(fmt.Sprintf(message, time.Now().Format("15:04:05")),
        &telebot.SendOptions{ParseMode: telebot.ModeMarkdown})
}

3. Rate Limiting

go
// Prevent abuse
var limiter = rate.NewLimiter(rate.Every(time.Second), 10)

func (ctrl *ServerController) RateLimitedCommand(c telebot.Context) error {
    if !limiter.Allow() {
        return c.Send("Too many requests, please try again later")
    }
    // Process command
    return nil
}

4. Scheduler Integration

Send scheduled notifications:

go
// Define task in Scheduler
func SendDailyReport(ctx context.Context, t *asynq.Task) error {
    report := generateReport()
    channels, _ := store.S.Channels().List(ctx, nil)
    for _, ch := range channels {
        sendNotification(ch, report)
    }
    return nil
}

Security

1. Token Protection

yaml
# Don't hardcode tokens
# Use environment variables or config files
bot:
  telegram: ${TELEGRAM_BOT_TOKEN}
  discord: ${DISCORD_BOT_TOKEN}

2. Minimal Permissions

  • Grant only necessary permissions
  • Regular permission audits
  • Use admin whitelist

3. Input Validation

go
func (ctrl *ServerController) ProcessInput(c telebot.Context) error {
    input := c.Text()
    if len(input) > 1000 {
        return c.Send("Input too long")
    }
    input = sanitize(input)
    // Process input
    return nil
}

Integration with Other Services

Call API Server

go
import "bingo/internal/apiserver/biz"

func (ctrl *ServerController) GetUserInfo(c telebot.Context) error {
    user, err := store.S.Users().Get(ctx, userID)
    if err != nil {
        return c.Send("User not found")
    }
    return c.Send(fmt.Sprintf("User: %s", user.Username))
}

Send Email

go
import "bingo/internal/pkg/mail"

func (ctrl *ServerController) SendReport(c telebot.Context) error {
    report := generateReport()
    err := mail.Send(mail.Message{
        To:      []string{"[email protected]"},
        Subject: "Bot Report",
        Body:    report,
    })
    if err != nil {
        return c.Send("Failed to send")
    }
    return c.Send("Report sent")
}

Next Step

Released under the Apache 2.0 License.