Commit 8d5e98f2 authored by Daniel García Moreno's avatar Daniel García Moreno

api: Use md5 as unique message id instead of i32

We were using an integer for the message id when we were sending a
message. This id was incremented with each message sent.

Reading the matrix server documentation I've discovered that this id
should be unique:

> Clients should generate an ID unique across requests with the same
> access token; it will be used by the server to ensure idempotency of
> requests.

So this was a problem. I think that this is because some messages never
got sent to the server and we don't get any error back.

To fix that now we generate an unique id for each message using the room
id, the message body and the message date, we concatenate that and make
an md5 sum, so this should be unique.

See #201
parent 861599ad
......@@ -22,6 +22,7 @@ tree_magic = "0.2.0"
url = "1.7.0"
unicode-segmentation = "1.2.0"
urlencoding = "1.0.0"
md5 = "0.3.7"
features = ["png"]
......@@ -36,7 +36,6 @@ impl Backend {
access_token: String::from(""),
server_url: String::from(""),
since: String::from(""),
msgid: 1,
rooms_since: String::from(""),
join_to_room: String::from(""),
......@@ -204,13 +204,7 @@ pub fn get_message_context(bk: &Backend, msg: Message) -> Result<(), Error> {
pub fn send_msg(bk: &Backend, msg: Message) -> Result<(), Error> {
let roomid =;
let msgid;
let mut data =;
data.msgid = data.msgid + 1;
msgid = data.msgid;
let msgid = msg.get_txn_id();
let url = bk.url(&format!("rooms/{}/send/{}", roomid, msgid), vec![])?;
......@@ -136,7 +136,6 @@ pub struct BackendData {
pub access_token: String,
pub server_url: String,
pub since: String,
pub msgid: i32,
pub rooms_since: String,
pub join_to_room: String,
extern crate md5;
extern crate chrono;
use self::chrono::prelude::*;
......@@ -50,3 +51,16 @@ impl Default for Message {
impl Message {
/// Generates an unique transaction id for this message
/// The txn_id is generated using the md5sum of a concatenation of the message room id, the
/// message body and the date.
pub fn get_txn_id(&self) -> String {
let msg = format!("{}{}{}",, self.body,;
  • @danigm If someone manages to type a<Enter>a<Enter> in the space of one second, the generated IDs for both messages will be identical, and since they "will be used by the server to ensure idempotency", I assume the second message will be discarded by the server, correct?

    If yes, that doesn't seem right. Probably better to keep the incrementing msgid and make that part of the hash calculation as well.

  • That's possible, but it's a rare case. At first I thought that we can use a random hash, but the problem with that is that if we add in the future a retry send or something like that, the ramdon will be a problem.

    As you said we can keep the incremental integer and attach to the hash, or we can add a new field to the Message structure and store the txnid there so we'll generate only one time and then we can keep track of that message.

Please register or sign in to reply
let digest = md5::compute(msg.as_bytes());
format!("{:x}", digest)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment