A basic Lua wrapper for TDLib's JSON interface
You first need to install
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
By default the repository builds its bundled TDLib copy. To use an installed TDLib instead, configure with:
cmake -S . -B build \
-DTDLUA_BUNDLED_TDLIB=OFF \
-DCMAKE_PREFIX_PATH=/path/to/tdlib
cmake --build buildThe Lua module can be installed with:
cmake --install build --prefix /usr/localThe default destination is lib/lua/<lua-version>/tdlua.so and can be changed
with -DTDLUA_LUA_MODULE_DIR=....
The bundled TDLib build uses TDLib's current JSON interface internally. TDLua keeps the TDLib client identifier private and continues to expose the existing Lua request and update API.
You can also use one of our precompiled binary from @tdlua Build with Lua 5.2 and the latest version of tdlib.
Special thanks for @danogentili for his work on php-libtgvoip Check out MadelineProto, a pure MTProto client written in PHP
Since i didn't wrote an actual installation script you'll need to manually copy the file tdlua.so into the appropriate directory
See example.lua See call.lua for an example on VoIP Calls [BETA]
The Lua type alias _ is accepted alongside @type and is emitted together with
@type in decoded objects. Clients accept fractional receive and execute timeouts:
local client = require("tdlua")()
local me = client:execute({_ = "getMe"}, 1.0)
client:close()
assert(client:isClosed())Asynchronous requests keep the raw send/receive API available while adding
callbacks and update handlers:
client:request({_ = "getMe"}, function(result, context)
print(result.first_name, context.origin)
end, {origin = "startup"})
client:on("updateNewMessage", function(update)
print(update.message.id)
end)
client:receive(1.0)await is cooperative and must run inside a coroutine. A normal receive()
call, or its poll() alias, resumes it when the response arrives:
local co = coroutine.create(function()
local me = client:await({_ = "getMe"})
print(me.first_name)
end)
coroutine.resume(co)
client:receive(1.0)The callback context is kept locally by TDLua and is never sent to TDLib.
Internal request markers are removed before the response is exposed to Lua;
the caller's original @extra is restored. _execute remains available as a
legacy alias, while executeSync names the direct TDLib td_execute call.
Dynamic TDLib helpers also accept the asynchronous form. A callback is detected by its Lua function type:
client:getMe(function(result)
print(result.first_name)
end)
client:getChat({chat_id = chat_id}, function(result, context)
print(context.origin, result.title)
end, {origin = "startup"})Without a callback, the legacy blocking behavior remains available:
local me = client:getMe()Inside a coroutine, a helper without a callback waits cooperatively and is
resumed by receive() or poll():
local co = coroutine.create(function()
local me = client:getMe()
print(me.first_name)
end)
coroutine.resume(co)
while coroutine.status(co) ~= "dead" do
client:poll(1.0)
endUpdate handlers can be registered explicitly or through a property:
client:on("updateNewMessage", handle_message)
client.onUpdateNewMessage = handle_message
client.onUpdateNewMessage = nilRun the regression tests with:
ctest --test-dir build -R '^tdlua_' --output-on-failure