Skip to content

Origin#8

Merged
Silentely merged 9 commits intodevfrom
origin
Jun 8, 2025
Merged

Origin#8
Silentely merged 9 commits intodevfrom
origin

Conversation

@Silentely
Copy link
Copy Markdown
Member

@Silentely Silentely commented Jun 8, 2025

Summary by Sourcery

Implement a userbot client fallback mechanism and embed internationalization throughout the application, upgrade dependencies, and refactor configuration, logging, and task handling to support localization and userbot features

New Features:

  • Add a userbot client fallback to fetch files when the primary bot client cannot retrieve them
  • Integrate internationalization support with embedded locale files and localization helper functions

Enhancements:

  • Upgrade project dependencies to their latest versions
  • Extend configuration to include language and userbot settings and display localized messages
  • Propagate a UseUserClient flag through the database model, task struct, and download pipeline to enable userbot usage
  • Refactor logging and common utilities to use localized templates and a consistent log format
  • Improve handler registration to ignore channel and chat messages early

Chores:

  • Add a CLI tool to generate i18n key constants from locale files

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Jun 8, 2025

Reviewer's Guide

This PR introduces full i18n support, adds a userbot fallback client for fetching files, extends configuration with language and userbot options, refactors handler registration, updates logging formatting, and upgrades project dependencies.

Sequence Diagram for File Fetching with Userbot Fallback

sequenceDiagram
    actor User
    participant MainBot
    participant UserBotClient
    participant Telegram

    User->>MainBot: Send message with file link
    MainBot->>MainBot: Parse link (chatID, messageID)
    MainBot->>Telegram: Attempt to fetch file metadata (using MainBot client)
    alt Fetch with MainBot Fails (e.g., peer not found) AND UserBot Enabled
        Telegram-->>MainBot: Error (e.g., peer not found)
        MainBot->>UserBotClient: Request file fetch (chatID, messageID)
        UserBotClient->>Telegram: Fetch file metadata (using UserBot client)
        Telegram-->>UserBotClient: File metadata
        UserBotClient-->>MainBot: File metadata (file, useUserClient=true)
    else Fetch with MainBot Succeeds or UserBot not applicable
        Telegram-->>MainBot: File metadata
        MainBot->>MainBot: Process file (useUserClient=false)
    end
    MainBot->>MainBot: Create Task (with useUserClient flag)
    MainBot-->>User: Reply (e.g., "Processing file...")

    Note right of MainBot: Later, during download:
    alt Task.UseUserClient is true
        MainBot->>UserBotClient: Download file via UserBotClient API
        UserBotClient->>Telegram: Download file bytes
        Telegram-->>UserBotClient: File bytes
        UserBotClient-->>MainBot: File bytes
    else Task.UseUserClient is false
        MainBot->>Telegram: Download file bytes via MainBot API
        Telegram-->>MainBot: File bytes
    end
Loading

ER Diagram for ReceivedFile Entity Update

erDiagram
    ReceivedFile {
        int ID PK
        string ChatID
        string MessageID
        string FileName
        bool IsTelegraph
        string TelegraphURL
        bool UseUserClient "New: Whether to use userbot client to fetch the file"
    }
Loading

Class Diagram for Configuration Structures

classDiagram
    class Config {
        +String Lang
        +Int Workers
        +Int Retry
        +Bool NoCleanCache
        +Int Threads
        +Bool Stream
        +Bool AsPublicCopyMediaBot
        +telegramConfig Telegram
        +logConfig Log
        +tempConfig Temp
        +dbConfig DB
        +List~StorageInterface~ Storages
    }
    class telegramConfig {
        +String Token
        +Int AppID
        +String AppHash
        +Int Timeout
        +proxyConfig Proxy
        +Int FloodRetry
        +Int RpcRetry
        +userbotConfig Userbot
    }
    class userbotConfig {
        +Bool Enable
        +String Session
    }
    class proxyConfig {
        +Bool Enable
        +String Url
    }
    Config *-- telegramConfig
    telegramConfig *-- userbotConfig
    telegramConfig *-- proxyConfig
Loading

Class Diagram for Updated Data Models

classDiagram
    class ReceivedFile {
        +int ID
        +string ChatID
        +string MessageID
        +string FileName
        +bool IsTelegraph
        +string TelegraphURL
        +bool UseUserClient
    }
    class Task {
        +Context Ctx
        +CancelFunc Cancel
        +Error Error
        +bool UseUserClient
        +TaskStatus Status
        +String StorageName
        +String StoragePath
        +Time StartTime
        +uint FileDBID
        +File File
        +int FileMessageID
        +int64 FileChatID
        +int ReplyMessageID
        +int64 ReplyChatID
        +String UserID
    }
Loading

File-Level Changes

Change Details Files
Integrate internationalization (i18n) across the codebase
  • Added i18n package with locale embeddings and utility functions
  • Generated key constants via cmd/gen_i18n
  • Replaced hard-coded messages in config, run, os utilities, logger, and help text with localized calls
i18n/i18n.go
cmd/gen_i18n/main.go
i18n/locale/zh-Hans.toml
i18n/i18nk/keys.go
config/viper.go
cmd/run.go
common/os.go
common/logger.go
bot/handle_start.go
Implement userbot client fallback for file retrieval
  • Created userclient package with auth, login and middleware support
  • Wrapped file fetch in tryFetchFileFromMessage/tryFetchMessage functions
  • Propagated UseUserClient flag through ReceivedFile, Task, AddToQueue and download logic
  • Initialized userclient on startup when enabled in config
userclient/auth.go
userclient/userclient.go
userclient/middlewares/recovery/recovery.go
userclient/middlewares/retry/retry.go
userclient/middlewares/middlewares.go
bot/handle_link.go
bot/handle_add_task.go
core/download.go
types/task.go
dao/model.go
cmd/run.go
Extend configuration schema for language and userbot settings
  • Added Lang and telegram.userbot fields to Config struct
  • Set viper defaults for lang and userbot.enable/session
  • Updated duplicate storage name error to use localized message
config/viper.go
Refactor dispatcher handler registration
  • Dropped channel and private chat updates early
  • Standardized dispatcher variable naming and handler registration calls
bot/handlers.go
Enhance logging format template
  • Defined a custom log template for text formatter
  • Applied template to both console and rotating file handlers
common/logger.go
Update and bump project dependencies
  • Added new modules (backoff, charmbracelet libraries, go-i18n, gotd userclient)
  • Upgraded multiple existing dependencies to latest minor/patch versions
go.mod
go.sum

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jun 8, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @Silentely, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Summary of Changes

As gemini-code-assist, I've reviewed this pull request titled "Origin". This PR introduces significant new functionality by integrating a Telegram user client alongside the existing bot client. The primary goal appears to be enabling the bot to access and process files and messages from sources that might be restricted for a standard bot, such as private channels or groups where the user client is a member. The changes involve adding a user client login and session management system, implementing logic to fall back to the user client for file fetching when the bot client encounters specific errors, and laying the groundwork for internationalization (i18n) by adding a new i18n package and updating various messages to be localizable.

Highlights

  • User Client Integration: Adds support for logging in and using a Telegram user client (gotd/td) to fetch files and messages, providing a fallback mechanism when the standard bot client fails, particularly for 'peer not found' or 'unexpected message type' errors.
  • Internationalization (i18n): Introduces a new i18n package (go-i18n) with support for loading locale files (TOML) and provides functions for translating messages. Includes a command-line tool to generate Go constants for message keys.
  • Dependency Updates: Updates several dependencies, including gotd/td, and adds new dependencies for i18n (go-i18n, pelletier/go-toml/v2), user client session storage (glebarez/sqlite), user client middlewares (cenkalti/backoff/v4), and terminal interaction for user client auth (charmbracelet/huh, charmbracelet/log, fatih/color).
  • Improved API Call Handling: Adds custom retry and recovery middlewares for the user client API calls to enhance robustness against transient errors.

Changelog

Click here to see the changelog
  • bot/handle_add_task.go
    • Imported userclient package.
    • Added UseUserClient boolean field to types.Task struct.
    • Modified AddToQueue to conditionally use the user client (userclient.UC) for fetching files if record.UseUserClient is true and the user client is initialized.
  • bot/handle_link.go
    • Imported userclient package.
    • Added tryFetchFileFromMessage function to attempt fetching a file with the bot client and fall back to the user client on specific errors.
    • Added tryFetchMessage function as a wrapper for GetTGMessage.
    • Updated handleLinkMessage to use the new tryFetchFileFromMessage and tryFetchMessage functions.
    • Stored the useUserClient flag in the dao.ReceivedFile record and the created task.
  • bot/handle_start.go
    • Changed the help message to display the full Git commit hash instead of a truncated one.
  • bot/handlers.go
    • Imported ext package.
    • Added handlers to ignore messages received in channels and chats (groups).
    • Renamed the dispatcher variable from dispatcher to disp.
  • cmd/geni18n/main.go
    • Added a new command-line tool to generate Go constants for i18n message keys by parsing TOML locale files.
  • cmd/run.go
    • Imported context, i18n, i18n/i18nk, and userclient packages.
    • Initialized the i18n system using i18n.Init.
    • Added logic to log in the user client (userclient.Login) if enabled in the configuration.
    • Updated various log and error messages to use the i18n translation function i18n.T.
  • common/logger.go
    • Removed the default channel name setting for the logger.
    • Set a custom template format for console and file log handlers.
  • common/os.go
    • Updated log messages related to file removal to use i18n translation.
  • config/viper.go
    • Imported errors, i18n, and i18n/i18nk packages.
    • Added Lang field to the main Config struct.
    • Added Userbot struct with Enable and Session fields to telegramConfig.
    • Set default values for lang, telegram.userbot.enable, and telegram.userbot.session.
    • Updated config validation error messages to use i18n.TWithoutInit.
  • core/download.go
    • Imported userclient package.
    • Modified processPendingTask to use the user client's API (userclient.UC.API()) for downloading files if the task's UseUserClient flag is true and the user client is available, otherwise uses the bot client's API.
  • dao/model.go
    • Added a UseUserClient boolean field to the ReceivedFile struct to track which client was used to fetch the file.
  • go.mod
    • Updated dependencies, including gotd/td and duke-git/lancet/v2.
    • Added new dependencies: cenkalti/backoff/v4, charmbracelet/huh, charmbracelet/log, fatih/color, nicksnyder/go-i18n/v2, pelletier/go-toml/v2, glebarez/sqlite.
  • go.sum
    • Updated checksums for added and updated dependencies.
  • i18n/i18n.go
    • Added a new package for internationalization.
    • Implements i18n using go-i18n, loading messages from embedded TOML files.
    • Provides Init, T, TWithLang, and TWithoutInit functions for translation.
  • i18n/i18nk/keys.go
    • Added a new file containing generated Go constants for i18n message IDs.
  • i18n/locale/zh-Hans.toml
    • Added a new locale file containing Chinese translations for various messages.
  • types/task.go
    • Added a UseUserClient boolean field to the Task struct to indicate if the task should use the user client for operations.
  • userclient/auth.go
    • Added a new file implementing a gotgproto.AuthConversator using charmbracelet/huh for terminal-based user client authentication (phone number, code, 2FA password).
  • userclient/middlewares/middlewares.go
    • Added a new file defining default middlewares for the user client, including recovery and retry.
  • userclient/middlewares/recovery/recovery.go
    • Added a new file implementing a recovery middleware using cenkalti/backoff to handle non-Telegram business errors.
  • userclient/middlewares/retry/retry.go
    • Added a new file implementing a retry middleware for specific Telegram API errors.
  • userclient/userclient.go
    • Added a new package for managing the user client.
    • Implements user client login using gotgproto and SQLite for session storage.
    • Uses the custom terminal auth conversator and default middlewares.
    • Exports the user client instance (UC) and a function to get its context (GetCtx).
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@Silentely Silentely merged commit 6e897a1 into dev Jun 8, 2025
4 of 5 checks passed
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant and valuable features: userbot client fallback and comprehensive internationalization. The implementation is largely robust, with good attention to configuration, logging, and error handling for the new userbot client. The i18n integration is well-done and will greatly improve the bot's usability.

I have one primary concern regarding the new message handlers in bot/handlers.go which might unintentionally prevent the bot from processing commands or links in group/channel chats. There are also a couple of minor points for consideration. Please see the detailed comments.

Summary of Findings

  • Handler Order and Scope: New handlers in bot/handlers.go for channel and chat messages might prematurely terminate message processing, potentially preventing commands and other interactions in those chat types. This needs clarification on intended behavior.
  • Error String Matching for Userbot Fallback: In bot/handle_link.go, the logic to trigger userbot fallback relies on specific error message strings, which could be brittle. A more robust error detection mechanism might be preferable.
  • Inconsistent Internationalization: A config loading error message in cmd/run.go remains hardcoded in English, while other similar messages are internationalized.
  • Efficiency of TWithoutInit: The i18n.TWithoutInit function re-initializes a bundle on each call. This is acceptable for its current use in early startup/config phases but should be noted if its usage expands.

Merge Readiness

This pull request introduces excellent new features and shows a lot of good work. However, before merging, I strongly recommend addressing the high severity issue identified in bot/handlers.go concerning the new message handlers, as it could significantly impact the bot's functionality in group and channel chats. The medium severity items should also be considered for improvement. I am not authorized to approve pull requests, so please ensure these points are reviewed and resolved by the appropriate maintainers before merging.

Comment thread bot/handlers.go
Comment on lines +12 to +14
disp.AddHandler(handlers.NewMessage(filters.Message.ChatType(filters.ChatTypeChannel), func(ctx *ext.Context, u *ext.Update) error {
return dispatcher.EndGroups
}))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

These new handlers for ChatTypeChannel and ChatTypeChat are placed at the beginning of the handler chain and return dispatcher.EndGroups. This means any message from a channel or a group chat will be caught by these handlers, and no subsequent handlers (like command handlers, link handlers, or even checkPermission) will be processed for those messages.

If the bot is intended to operate at all in channels or group chats (e.g., respond to commands from authorized users, process links posted there), this change will prevent that. The PR description mentions "Improve handler registration to ignore channel and chat messages early," which is good, but this implementation might be too broad if it's not intended to completely disable the bot in these chat types.

Could you clarify the intended behavior?

  • Is the bot now meant to function only in private chats?
  • If it should still work in groups/channels for certain actions (e.g., commands), how should these early-exit handlers be adjusted to allow that while still ignoring other irrelevant messages?

Comment thread bot/handle_link.go
Comment on lines +62 to +71
if (strings.Contains(err.Error(), "peer not found") || strings.Contains(err.Error(), "unexpected message type")) && userclient.UC != nil {
common.Log.Warnf("无法获取文件 %d:%d, 尝试使用 userbot: %s", chatID, messageID, err)
uctx := userclient.GetCtx()
// TODO: 群组支持
file, err = FileFromMessage(uctx, chatID, messageID, fileName)
if err == nil {
return file, true, nil
}
return nil, true, err
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The condition strings.Contains(err.Error(), "peer not found") || strings.Contains(err.Error(), "unexpected message type") for deciding to use the userbot is quite specific. While these errors might currently cover the main scenarios where a userbot is beneficial, relying on specific error strings can be brittle if Telegram API error messages change or if other error types also signify a situation where the bot client lacks access but a user client might succeed.

Could we consider a more robust way to determine if a userbot attempt is warranted? Perhaps checking for specific error codes if available, or a broader category of permission-related errors?

Comment thread cmd/run.go
func InitAll() {
if err := config.Init(); err != nil {
fmt.Println("加载配置文件失败: ", err)
fmt.Println("Failed to load config:", err)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error message "Failed to load config:" is hardcoded in English here, while other messages in this file and config/viper.go are being internationalized. Since i18n.Init() is called after config loading, if this message needs to be localized, i18n.TWithoutInit(config.Cfg.Lang, i18nk.YourKeyForConfigLoadFailure, map[string]any{"Error": err}) would be appropriate. Was this hardcoding intentional?

fmt.Println(i18n.TWithoutInit(config.Cfg.Lang, i18nk.ConfigLoadFailed, map[string]any{
				"Error": err,
			}))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants