Discord.ml: Eio-based Discord library with voice support

Hi. I’m writing a Discord library, Discord.ml, in OCaml for my personal project. As of now, it supports voice functionality as well as text one, and you can write, for example, a music bot with this library.

I used Eio to write this library and wrote a simple Erlang-like actor model implementation (actaa). Also, I used Cohttp-eio (beta1) with ocaml-websocket to communicate with the Discord’s server (gateway).

I hope someone may be interested in this library. Any feedback would be appreciated!

11 Likes

Nice work.

Looking at the code, the use of Object for a user defined module was a bit weird, I expected it to be the Obj from the stdlib. Then the pattern matching code for handle_event:

let handle_event token env ~sw:_ agent state =
  let open Discord.Event in
  function
  | Dispatch (MESSAGE_CREATE msg) -> (
      let guild_id = Option.get msg.guild_id in
      let parsed = String.split_on_char ' ' msg.content in
      match parsed with
      | [ "!ping" ] ->
          Logs.info (fun m -> m "ping");

I would replace the string matching with an ADT, the would handle the error case in a type safe way.

I hope a version of the actor model gets implemented and adopted for OCaml 5.*. It is a convenient way to represent certain kinds of problems.

2 Likes

Thanks for your feedback!

the use of Object for a user defined module was a bit weird, I expected it to be the Obj from the stdlib.

Indeed. Probably I should rename it to Entity or something.

I would replace the string matching with an ADT, the would handle the error case in a type safe way.

Could you elaborate on this? The message sent from Discord is a string, and the string matching like my code seems inevitable to me.

I hope a version of the actor model gets implemented and adopted for OCaml 5.*. It is a convenient way to represent certain kinds of problems.

I hope so too! I feel that Eio allows us to make some sort of typed Erlang/OTP in OCaml, which is nice.

1 Like

I would typically transform the string from Discord into an ADT of known values and deal with those internally. But that only makes sense if that is a limited know set of values. eg the match on "!ping" I would make into a variant type

type event = 
 | Ping 
 | Join
...

and have a function parse : string -> (err, event) result.

2 Likes

Ah, I see. Thanks for your comments! I’ll fix my code later.

1 Like

I feel that Eio allows us to make some sort of typed Erlang/OTP in OCaml, which is nice.

A while ago I partially ported ejabberd from Erlang to OCaml/Lwt, and recently, to get myself acquainted with Eio, replaced Lwt with Eio: jamler/eio. With a single domain it works great, but for multiple domains I don’t see how to implement process migration to balance load.

2 Likes

@ostera has been exploring that space with GitHub - leostera/riot: An actor-model multi-core scheduler for OCaml 5 🐫 (not eio based)

2 Likes

Thanks, that looks very promising, I will give it a try.

2 Likes

There was a previous attempt at it called disml. I have used for a discord bot, and it works well, but uses async and was not updated since 2020. Maybe you could give it a look, i think it supports more of the routes and types than your probably more up to date library.

I would be quite happy to switch my bot to this once it has the features I need. Maybe I will even find time to contribute.

1 Like

Yeah, I know about dis.ml, but its README says it doesn’t support voice, which I absolutely needed to make my voice bot (Yomer). I was also interested in Eio, so I wrote discord.ml.

Discord.ml currently only supports the features needed for Yomer, but I’d like to expand it for completeness. Any contribution is welcome!

1 Like