Kilogram - a simple way to communicate with Telegram
As mentioned before, Microgram relies on a proxy server that does the heavy lifting for it. I call this proxy server Kilogram. It can be considered a separate product that can be used for all kinds of work with Telegram. Telegram's feature list is very, very long and new features are added every month. If you want to work with Telegram as a simple messenger, sending and receiving texts, photos and videos 1:1 or in groups, you can easily be overwhelmed by the sheer amount of stuff to handle.
- There are not only text/video/photo messages. There are currently 45 types of messages.
- There are not only 1:1 chats, but also channels, groups, supergroups, secret chats.
- Messages do not only have an author, but maybe a forwarder, or maybe the author's user info is not available. There are six different types of chat members.
- There are spoilers and all kinds of text formatting, there are messages that are automatically deleted after a period of time, manually deleted or edited.
- …and so forth, you get the idea.
Even if you want to support just basic text conversation (and this is what I am focussing on at the moment), the Telegram API is built with all its features carefully laid out, so there is a lot of work to be done to rule out most of them to get to a basic functionality that I want.
Kilogram
To get from the interaction with Telegram to a simple, JSON-based API, we have Kilogram. Kilogram is a server in the middle between Microgram (and possibly other lightweight client apps) and Telegram itself. It is written in Javascript and is based on gram.js. It can be hosted by anyone who knows how to run a deno application (or a Docker container). You can point your Microgram app to any Kilogram URL in its configuration dialog.
The API
I hestitate to call the API RESTful, since their exist a ton of rules when to call your API really RESTful. Let's just say: You can call any API endpoint in any order and it should always work (you have to authenticate once to get your session string). You send the credentials with every request (it is not stored in Kilogram). And we use more than just GET as HTTP method.
Anyhow, these are the methods currently implemented:
GET /
Human readable text with basic infos about the serverGET /version
Version info, example:{"result":"ok","version":"0.0.1"}
POST /auth
Authenticate. Provide telephone number to start. Receive authentication states like "need_pass" or "need_code" and provide these additional infos in subsequent calls until you receive the state "logged_in" and a "sessionString" that from now on has to be the value of your "autherization" header, along the telephone number in the "number" header field.
First request:{"number": "+12345678"}
First response:{"result":"ok","state":"NEED_CODE","phoneCodeHash":"abcdef1234567890"}
Now, you receive the authentication code on your other device (via Telegram app or SMS).
Second request:{"number": "+12345678", "phoneCodeHash":"abcdef1234567890", "code":"12345"}
Second response:{"result": "ok", "state":"LOGGED_IN", "sessionString": "abcd…"}
From now on, every request must have two header fields, "number" with the telephone number and "authorization" with the session string. All following endpoints require this authentication.GET /chats
Get id, title, unreadCount, date and pinned (yes or no) info for the top 100 dialogs (that is chats, groups, channels etc.).GET /chat?chatId=xxx
Get the last 100 messages of a chat (or channel, or group…), with id, message text, sender ID and name.POST /sendMessage
Post a text message in a chat like this:{"chatId":"12345678", "text": "message text"}
. You receive back the sent message in the same format that you get with GET /chat?chatId=123, so you can just append the result to the chat.GET /update
When there is a new message or a deleted message for the user, this endpoint will provide the new message and the chat it belongs to or the ID of the deleted message. The request will remain open until the update is received (a method called "long polling").- Error handling: Every response has the format
{"result": "ok", …}
or{"result": "error", "message":"an error message"}
And that's it for the moment. No contact list, no images or other media, no new chat etc. Still, I think this server is worthy to have a proper name and serves a purpose potentially much larger than just a hack to make Telegram work on old Java phones. I am working on a OpenAPI documentation and will release the whole thing, of course, as open source along the J2ME client as soon as I have something to release.