GrubY
A Ruby Telegram wrapper with:
GrubY::Client(BotAPI runtime)GrubY::TDLib::Client(tdjson native runtime, pytdbot-inspired)
Install
gem install gruubY
For local development:
bundle install
From this repo directly:
rake build
gem install ./gruubY-0.2.2.gem
What Is New
TDLib internals upgraded with a dedicated
TdJsonwrapperDecorator-style hooks for TDLib:
initializerfinalizeron_message
Queue workers and handler timeout support
Better authorization lifecycle handling
Multi-client support utility:
GrubY::TDLib::ClientManagerCI workflows for TDLib build and gem publish
BotAPI Quick Start
require_relative "lib/gruubY"
client = GrubY::Client.new("BOT_TOKEN")
client.on(:message, GrubY::Filters.command("start")) { |ctx| ctx.reply("Heya; Started!") }
client.run
TDLib Quick Start
client = GrubY::TDLib::Client.new(
api_id: ENV.fetch("TD_API_ID").to_i,
api_hash: ENV.fetch("TD_API_HASH"),
bot_token: ENV["TD_BOT_TOKEN"],
tdjson_path: ENV["TDJSON_PATH"],
workers: 4,
default_handler_timeout: 10
)
client.initializer do |update|
end
client.on_message do |message|
# Message object from updateNewMessage
end
client.finalizer do |update|
end
client.on("clientReady") { puts "TDLib Ready" }
client.run
TDLib Paths
Supported shared libraries:
Linux:
libtdjson.somacOS:
libtdjson.dylibWindows:
tdjson.dll
Provide via:
TDJSON_PATHenv vartdjson_path:constructor argument
NTgCalls Native
GrubY uses direct Ruby and C bindings for ntgcalls.
example:
example/ntgcalls.rb
Environment
TD_USER_SESSION(required; generated viaexample/generate_user_session.rb)NTGCALLS_PATH(optional; absolute/custom path to shared library)VC_CHAT(required; numeric chat id or@username)VC_AUDIO(required; local file path or URL)VC_INVITE_HASH(optional; invite hash for restricted voice chats)
Run Demo
ruby example/ntgcalls.rb
Direct Ruby Usage
bot = GrubY::NTgCalls::MusicBot.new(
td_user_session: ENV.fetch("TD_USER_SESSION"),
tdjson_path: ENV["TDJSON_PATH"],
ntgcalls_path: ENV["NTGCALLS_PATH"]
)
bot.start
bot.join_and_play(chat: "@GrubYChat", audio: "song.mp3")
bot.pause
bot.resume
bot.mute
bot.unmute
bot.stop_call
bot.stop
Note:
ntgcallsis a media engine.This demo performs signaling/auth through TDLib raw calls plus NTgCalls media engine.
Telegram User Session String (Ruby)
Generate a reusable TDLib user session string:
TD_API_ID=12345 TD_API_HASH=xxxx ruby example/generate_user_session.rb
After login, script prints:
TD_USER_SESSION=<base64>
Reuse:
cfg = GrubY::TDLib::UserSession.client_kwargs(ENV.fetch("TD_USER_SESSION"))
client = GrubY::TDLib::Client.new(**cfg, tdjson_path: ENV["TDJSON_PATH"])
client.run
Framework Helpers
Enums:
GrubY::Enums::ParseMode::MARKDOWN_V2
GrubY::Enums::ChatAction::TYPING
GrubY::Enums::GroupCallUpdateType::UPDATE_GROUP_CALL
InlineKeyboard and WebApp:
markup = GrubY::Keyboard.inline([
[GrubY::Keyboard.button("Ping", "ping:1")],
[GrubY::Keyboard.web_app_button("Open App", "https://example.com/app")]
])
client.send_message(chat_id, "Menu", reply_markup: markup)
Bound and Raw:
bound = GrubY::Bound.bind(ctx)
bound[:send].call("hello")
bound[:raw].call("getMe")
GrubY::Raw.td_call!(td_client, { "@type": "getMe" })
Bound Objects:
client.on(:message) do |ctx|
msg = ctx.message
msg.reply_text("pong")
msg.reply_photo("file_id_or_url")
msg.edit_text("updated")
msg.react(reaction: [{ type: "emoji", emoji: "👍" }])
end
Dynamic type registry:
# Hundreds of Telegram types are available as BaseObject subclasses
u = GrubY::VerificationStatus.new("is_verified" => true)
p u.to_h
Enumerations
Enum groups are available under GrubY::Enums:
BlockList,BusinessSchedule,ButtonStyle,ChatAction,ChatEventAction,ChatJoinTypeChatMemberStatus,ChatMembersFilter,ChatType,ClientPlatform,FolderColorMessageEntityType,MessageMediaType,MessageOriginType,MessageServiceType,MessagesFilterNextCodeType,PaidReactionPrivacy,ParseMode,PhoneCallDiscardReason,PhoneNumberCodeType,PollTypePrivacyKey,ProfileColor,ProfileTab,ReplyColor,SentCodeType,StoriesPrivacyRules,UserStatusUpgradedGiftOrigin,GiftAttributeType,MediaAreaType,PrivacyRuleType,GiftForResaleOrderGiftPurchaseOfferState,GiftType,PaymentFormType,StickerType,MaskPointTypeSuggestedPostRefundReason,SuggestedPostState
Example:
GrubY::Enums::ParseMode::MARKDOWN_V2
GrubY::Enums::ChatType::SUPERGROUP
GrubY::Enums::ChatMemberStatus::ADMINISTRATOR
Decorators
Decorators are supported on GrubY::Client:
on_message,on_edited_message,on_business_message,on_edited_business_messageon_deleted_messages,on_deleted_business_messageson_message_reaction_count,on_message_reactionon_business_connection,on_story,on_callback_query,on_chat_booston_chat_join_request,on_chat_member_updated,on_chosen_inline_result,on_inline_queryon_poll,on_pre_checkout_query,on_purchased_paid_media,on_shipping_query,on_user_statuson_start,on_stop,on_connect,on_disconnect,on_error,on_managed_bot,on_raw_update
Example:
client.on_message(GrubY::Filters.command("start")) do |app, message|
message.reply_text("pong")
end
client.on_callback_query do |app, cq|
cq.answer("ok")
end
Handlers
GrubY::Handlers classes are available for add_handler():
MessageHandler,EditedMessageHandler,DeletedMessagesHandlerBusinessMessageHandler,EditedBusinessMessageHandler,DeletedBusinessMessagesHandlerBusinessConnectionHandler,CallbackQueryHandler,ChatBoostHandler,ChatJoinRequestHandlerChatMemberUpdatedHandler,ChosenInlineResultHandler,InlineQueryHandlerMessageReactionCountHandler,MessageReactionHandler,PollHandlerPreCheckoutQueryHandler,PurchasedPaidMediaHandler,ShippingQueryHandlerStoryHandler,UserStatusHandlerStartHandler,StopHandler,ConnectHandler,DisconnectHandlerErrorHandler,ManagedBotUpdatedHandler,RawUpdateHandler
Example:
handler = GrubY::Handlers::MessageHandler.new(proc { |app, message| message.reply_text("hi") })
client.add_handler(handler)
Update Filters
Ruby GrubY::Filters now supports:
create(func:, name:, **kwargs)custom filter creatorBoolean composition:
&,|,~Update filters:
all,me,bot,sender_chat,incoming,outgoingContent filters:
text,reply,forwarded,caption,audio,document,photo,sticker,animation,video,voice,video_note,contact,location,venue,web_page,poll,dice,quote,media_spoiler,story,media_groupChat filters:
private,group,channel,direct,forumService/media filters:
service,media, plus specific service keys (new_chat_members,pinned_message,video_chat_started, etc.)Parameterized filters:
command(...),regex(...),user(...),chat(...),topic(...)
Example:
f = GrubY::Filters.command(%w[start help]) & GrubY::Filters.private
client.on_message(f) { |app, msg| msg.reply_text("ok") }
Raw Group-Call Objects:
igc = GrubY::RawTypes.input_group_call(id: 1, access_hash: 2)
peer = GrubY::RawTypes.input_peer_self
json = GrubY::RawTypes.to_data_json({ ufrag: "x" })
join = GrubY::RawTypes.join_group_call(call: igc, params: json, join_as: peer)
leave = GrubY::RawTypes.leave_group_call(call: igc, source: 123)
Steps to Setup TDJSON:
Push a tag (example:
v0.2.1) or manually run theRelease TDJSONworkflow.Download the zip for your OS from the GitHub Release assets:
tdjson-linux-x64.ziptdjson-macos-x64.ziptdjson-windows-x64.zip
Extract and copy them into the repo:
Linux: vendor/tdlib/linux/libtdjson.somacOS: vendor/tdlib/macos/libtdjson.dylibWindows: vendor/tdlib/windows/tdjson.dll
Optional: Set
TDJSON_PATHif you want to use a custom path.
Note: GrubY::TDLib::Native now also auto-detects from vendor/tdlib/... paths.
Examples:
example/bot.rbexample/ntgcalls.rbexample/generate_user_session.rbexample/tdlib.rbexample/userbot.rb(phone/QR login)