From 75e8b8dff1436801ff4c3e7ca78d5d810e9a4e9a Mon Sep 17 00:00:00 2001 From: cosmonawt Date: Sun, 27 Mar 2016 21:34:18 +0200 Subject: [PATCH] v.2.0 Framework extension - Added Framework extension with callbacks and integrated update handler to help developers get started quicker. - Bugfixes --- README.md | 180 +++++++++++++++++++++++++++++++++++++++++-- bot-example.lua | 28 +++++++ lua-bot-api-test.lua | 2 +- lua-bot-api.lua | 153 ++++++++++++++++++++++++++++++++++-- 4 files changed, 348 insertions(+), 15 deletions(-) create mode 100644 bot-example.lua mode change 100644 => 100755 lua-bot-api-test.lua diff --git a/README.md b/README.md index e477061..ff18c9c 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,24 @@ # lua-telegram-bot A simple LUA Framework for the [Telegram Bot API](https://https://core.telegram.org/bots/api) +Made with ❤️ by [@cosmonawt](https://telegram.me/cosmonawt) + ## Changelog -### Feb 28 2016 +### Mar 27 2016 - v2.0 + +* Added [Framework Extension](https://github.com/cosmonawt/lua-telegram-bot#framework-extension) which includes an internal update and callback handler and several callback functions which can be overridden. +* Added file `bot-example.lua` with examples on how to use the new [Framework Extension](https://github.com/cosmonawt/lua-telegram-bot#framework-extension). +* Minor bug fixes + +### Feb 28 2016 v1.1 * Added `disable_notification` argument to all sending methods to enable [silent messages](https://telegram.org/blog/channels-2-0#silent-messages) * Added `caption` argument to `sendDocument()` -### Jan 22 2016 +### Jan 22 2016 - v1.0 -* Initial release v0.1-alpha +* Initial release v1.0-alpha ## Installing @@ -29,13 +37,14 @@ Simply place it in the `lua-telegram-bot` Folder. To use this module, import it into your bot like this: ```lua -local bot = (require "lua-bot-api").configure(token) +local bot, extension = (require "lua-bot-api").configure(token) ``` Include your bot token as parameter for `configure()`. At the moment, only getUpdates method (aka polling) is supported, no webhooks. -The `bot` Table exports variables and functions which return the following return values: +The `bot` Table exports variables and functions which return the following return values. +The `extension` Table exports several callback functions as well as an update handler. Check Framework Extension for more information. ### Return values @@ -44,7 +53,7 @@ This does *not* mean the request was successful, for example in case of a bad `o A function returns `nil` and an `error description` if it was wrongly called (missing parameters). -### Variables +### Available Variables ```lua id @@ -56,7 +65,7 @@ username first_name ``` -### Functions +### Available Functions ```lua getMe() @@ -131,3 +140,160 @@ generateForceReply([force_reply] [,selective]) - Generates a `ForceReply` of type `reply_markup` which can be sent optionally in other functions such as `sendMessage()`. - Forces to reply to the corresponding message from the receivers device. - `force_reply` can be left out, as it is always `true`. + +## Framework Extension + +The framework extension was added to help developers focus on the things that actually matter in a bot: It's logic. +It offers serveral callback functions which can be overridden to provide the wanted logic. + +### Available Functions + +To use the extension, simply add another table variable to the initial `require` call like so: + +```lua +local bot, extension = require("lua-bot-api").configure(token) +``` + +The `extension` Table now stores the following functions: + +```lua +run() +``` +- Provides an update handler which automatically fetches new updates from the server and calls the respective callback functions. + +```lua +onUpdateReceive(update) +``` +- Is called every time an update, no matter of what type, is received. + +```lua +onMessageReceive(message) +``` +- Is called every time a text message is received. + +```lua +onPhotoReceive(message) +``` +- Is called every time a photo is received. + +```lua +onAudioReceive(message) +``` +- Is called every time audio is received. + +```lua +onDocumentReceive(message) +``` +- Is called every time a document is received. + +```lua +onStickerReceive(message) +``` +- Is called every time a sticker is received. + +```lua +onVideoReceive(message) +``` +- Is called every time a video is received. + +```lua +onVoiceReceive(message) +``` +- Is called every time a voice message is received. + +```lua +onContactReceive(message) +``` +- Is called every time a contact is received. + +```lua +onLocationReceive(message) +``` +- Is called every time a location is received. + +```lua +onLeftChatParticipant(message) +``` +- Is called every time a member or the bot itself leaves the chat. + +```lua +onNewChatParticipant(message) +``` +- Is called when a member joins a chat or the bot itself is added. + +```lua +onNewChatTitle(message) +``` +- Is called every time the chat title is changed. + +```lua +onNewChatPhoto(message) +``` +- Is called every time the chat photo is changed. + +```lua +onDeleteChatPhoto(message) +``` +- Is called every time the chat photo is deleted. + +```lua +onGroupChatCreated(message) +``` +- Is called every time a group chat is created directly with the bot. + +```lua +onSupergroupChatCreated(message) +``` + +```lua +onChannelChatCreated(message) +``` + +```lua +onMigrateToChatId(message) +``` +- Is called every time a group is upgraded to a supergroup. + +```lua +onMigrateFromChatId(message) +``` + +```lua +onInlineQueryReceive(inlineQuery) +``` +- Is called every time an inline query is received. + +```lua +onChosenInlineQueryReceive(chosenInlineQuery) +``` +- Is called every time a chosen inline query result is received. + +```lua +onUnknownTypeReceive(unknownType) +``` +- Is called every time when an unknown type is received. + +### Using extension functions + +In order to provide your own desired behaviour to these callback functions, you need to override them, like so, for example: + +```lua +local bot, extension = require("lua-bot-api").configure(token) + +extension.onMessageReceive = function (message) + -- Your own desired behaviour here +end + +extension.run() + +``` + +You can now use `extension.run()` to use the internal update handler to fetch new updates from the server and call the representive functions. + +You can even override `extension.run()` with your own update handler. + +See bot-example.lua for some examples on how to use extension functions. + + + + diff --git a/bot-example.lua b/bot-example.lua new file mode 100644 index 0000000..9d4a251 --- /dev/null +++ b/bot-example.lua @@ -0,0 +1,28 @@ +-- pass token as command line argument or insert it into code +local token = arg[1] or "" + +-- create and configure new bot with set token +local bot, extension = require("lua-bot-api").configure(token) + +-- override onMessageReceive function so it does what we want +extension.onMessageReceive = function (msg) + print("New Message by " .. msg.from.first_name) + + if (msg.text == "/start") then + bot.sendMessage(msg.from.id, "Hello there 👋\nMy name is " .. bot.first_name) + elseif (msg.text == "ping") then + bot.sendMessage(msg.chat.id, "pong!") + else + bot.sendMessage(msg.chat.id, "I am just an example, running on the Lua Telegram Framework written with ❤️ by @cosmonawt") + end +end + +-- override onPhotoReceive as well +extension.onPhotoReceive = function (msg) + print("Photo received!") + bot.sendMessage(msg.chat.id, "Nice photo! It dimensions are " .. msg.photo[1].width .. "x" .. msg.photo[1].height) +end + +-- This runs the internal update and callback handler +-- you can even override run() +extension.run() \ No newline at end of file diff --git a/lua-bot-api-test.lua b/lua-bot-api-test.lua old mode 100644 new mode 100755 index d67cc62..7fe1cca --- a/lua-bot-api-test.lua +++ b/lua-bot-api-test.lua @@ -23,7 +23,7 @@ for key, query in pairs(updates.result) do -- get the users profile pictures local profilePicture = getUserProfilePhotos(query.message.from.id) -- and send the first one back to him using its file id - sendPhoto(query.message.from.id, profilePicture.result.photos[1][1].file_id) + bot.sendPhoto(query.message.from.id, profilePicture.result.photos[1][1].file_id) end end end diff --git a/lua-bot-api.lua b/lua-bot-api.lua index b7a954c..1141526 100644 --- a/lua-bot-api.lua +++ b/lua-bot-api.lua @@ -18,10 +18,11 @@ -- Import Libraries local https = require("ssl.https") local ltn12 = require("ltn12") -local encode = (require "multipart.multipart-post").encode -local JSON = (require "JSON") +local encode = require("multipart.multipart-post").encode +local JSON = require("JSON") local M = {} -- Main Bot Framework +local E = {} -- Extension Framework local C = {} -- Configure Constructor -- JSON Error handlers @@ -37,7 +38,7 @@ function JSON:onDecodeError(message, text, location, etc) end function JSON:onEncodeError(message, etc) - print(print("Error while encoding JSON:\n", message)) + print("Error while encoding JSON:\n", message) end -- configure and initialize bot @@ -50,11 +51,11 @@ local function configure(token) M.token = assert(token, "No token specified!") local bot_info = M.getMe() if (bot_info) then - M.id = bot_info.id - M.username = bot_info.username - M.first_name = bot_info.first_name + M.id = bot_info.result.id + M.username = bot_info.result.username + M.first_name = bot_info.result.first_name end - return M + return M, E end C.configure = configure @@ -626,4 +627,142 @@ end M.answerInlineQuery = answerInlineQuery +-- Extension Framework + +local function onUpdateReceive(update) end +E.onUpdateReceive = onUpdateReceive + +local function onMessageReceive(message) end +E.onMessageReceive = onMessageReceive + +local function onPhotoReceive(message) end +E.onPhotoReceive = onPhotoReceive + +local function onAudioReceive(message) end +E.onAudioReceive = onAudioReceive + +local function onDocumentReceive(message) end +E.onDocumentReceive = onDocumentReceive + +local function onStickerReceive(message) end +E.onStickerReceive = onStickerReceive + +local function onVideoReceive(message) end +E.onVideoReceive = onVideoReceive + +local function onVoiceReceive(message) end +E.onVoiceReceive = onVoiceReceive + +local function onContactReceive(message) end +E.onContactReceive = onContactReceive + +local function onLocationReceive(message) end +E.onLocationReceive = onLocationReceive + +local function onLeftChatParticipant(message) end +E.onLeftChatParticipant = onLeftChatParticipant + +local function onNewChatParticipant(message) end +E.onNewChatParticipant = onNewChatParticipant + +local function onNewChatTitle(message) end +E.onNewChatTitle = onNewChatTitle + +local function onNewChatPhoto(message) end +E.onNewChatPhoto = onNewChatPhoto + +local function onDeleteChatPhoto(message) end +E.onDeleteChatPhoto = onDeleteChatPhoto + +local function onGroupChatCreated(message) end +E.onGroupChatCreated = onGroupChatCreated + +local function onSupergroupChatCreated(message) end +E.onsuperGroupChatCreated = onsuperGroupChatCreated + +local function onChannelChatCreated(message) end +E.onChannelChatCreated = onChannelChatCreated + +local function onMigrateToChatId(message) end +E.onMigrateToChatId = onMigrateToChatId + +local function onMigrateFromChatId(message) end +E.onMigrateFromChatId = onMigrateFromChatId + +local function onInlineQueryReceive(inlineQuery) end +E.onInlineQueryReceive = onInlineQueryReceive + +local function onChosenInlineQueryReceive(chosenInlineQuery) end +E.onChosenInlineQueryReceive = onChosenInlineQueryReceive + +local function onUnknownTypeReceive(unknownType) + print("new unknownType!") +end + +E.onChosenInlineQueryReceive = onChosenInlineQueryReceive + +local function parseUpdateCallbacks(update) + E.onUpdateReceive(update) + if (update.message.text) then + E.onMessageReceive(update.message) + elseif (update.message.photo) then + E.onPhotoReceive(update.message) + elseif (update.message.audio) then + E.onAudioReceive(update.message) + elseif (update.message.document) then + E.onDocumentReceive(update.message) + elseif (update.message.sticker) then + E.onStickerReceive(update.message) + elseif (update.message.video) then + E.onVideoReceive(update.message) + elseif (update.message.voice) then + E.onVoiceReceive(update.message) + elseif (update.message.contact) then + E.onContactReceive(update.message) + elseif (update.message.location) then + E.onLocationReceive(update.message) + elseif (update.message.left_chat_participant) then + E.onLeftChatParticipant(update.message) + elseif (update.message.new_chat_participant) then + E.onNewChatParticipant(update.message) + elseif (update.message.new_chat_photo) then + E.onNewChatPhoto(update.message) + elseif (update.message.delete_chat_photo) then + E.onDeleteChatPhoto(update.message) + elseif (update.message.group_chat_created) then + E.onGroupChatCreated(update.message) + elseif (update.message.supergroup_chat_created) then + E.onSupergroupChatCreated(update.message) + elseif (update.message.channel_chat_created) then + E.onChannelChatCreated(update.message) + elseif (update.message.migrate_to_chat_id) then + E.onMigrateToChatId(update.message) + elseif (update.message.migrate_from_chat_id) then + E.onMigrateFromChatId(update.message) + elseif (update.inline_query) then + E.onInlineQueryReceive(update.inline_query) + elseif (update.chosen_inline_result) then + E.onChosenInlineQueryReceive(update.chosen_inline_result) + else + E.onUnknownTypeReceive(update) + end +end + +local function run() + local offset = 0 + while true do + local updates = M.getUpdates(offset) + if(updates) then + if (updates.result) then + for key, update in pairs(updates.result) do + parseUpdateCallbacks(update) + offset = update.update_id + 1 + end + end + end + end +end + +E.run = run + return C