Skip to content

Commit

Permalink
event handler (only ready and message event)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyteon committed Jul 17, 2024
1 parent 0f155a0 commit db2558a
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 7 deletions.
8 changes: 6 additions & 2 deletions src/discord_gleam.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import discord_gleam/event_handler
import discord_gleam/ws/event_loop

pub fn run(token: String) -> Nil {
event_loop.main(token)
pub fn run(
token: String,
event_handlers: List(event_handler.EventHandler),
) -> Nil {
event_loop.main(token, event_handlers)
}
35 changes: 35 additions & 0 deletions src/discord_gleam/event_handler.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import discord_gleam/ws/packets/generic
import discord_gleam/ws/packets/message
import discord_gleam/ws/packets/ready
import gleam/list
import gleam/result

pub type EventHandler =
fn(Packet) -> Nil

pub type Packet {
MessagePacket(message.MessagePacket)
ReadyPacket(ready.ReadyPacket)
UnknownPacket(generic.GenericPacket)
}

pub fn handle_event(msg: String, handlers: List(EventHandler)) -> Nil {
let packet = decode_packet(msg)

list.each(handlers, fn(handler) { handler(packet) })
}

fn decode_packet(msg: String) -> Packet {
let generic_packet = generic.string_to_data(msg)
case generic_packet.t {
"MESSAGE_CREATE" ->
message.string_to_data(msg)
|> result.map(MessagePacket)
|> result.unwrap(UnknownPacket(generic_packet))
"READY" ->
ready.string_to_data(msg)
|> result.map(ReadyPacket)
|> result.unwrap(UnknownPacket(generic_packet))
_ -> UnknownPacket(generic_packet)
}
}
5 changes: 4 additions & 1 deletion src/discord_gleam/ws/event_loop.gleam
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import discord_gleam/event_handler
import discord_gleam/ws/packets/hello
import discord_gleam/ws/packets/identify
import gleam/erlang/process
Expand All @@ -20,7 +21,7 @@ pub type State {
State(has_received_hello: Bool, sequence: Int)
}

pub fn main(token: String) {
pub fn main(token: String, event_handlers: List(event_handler.EventHandler)) {
logging.log(logging.Debug, "Requesting gateway")

let req =
Expand Down Expand Up @@ -82,6 +83,8 @@ pub fn main(token: String) {
actor.continue(new_state)
}
True -> {
event_handler.handle_event(msg, event_handlers)

actor.continue(state)
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/discord_gleam/ws/packets/generic.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import gleam/dynamic
import gleam/json

pub type GenericPacket {
GenericPacket(t: String, s: Int, op: Int)
}

pub fn string_to_data(encoded: String) -> GenericPacket {
let decoder =
dynamic.decode3(
GenericPacket,
dynamic.field("t", of: dynamic.string),
dynamic.field("s", of: dynamic.int),
dynamic.field("op", of: dynamic.int),
)

let data = json.decode(from: encoded, using: decoder)

case data {
Ok(decoded) -> decoded
Error(_) -> GenericPacket("error", 0, 0)
}
}
2 changes: 1 addition & 1 deletion src/discord_gleam/ws/packets/identify.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn create_packet(token: String) -> String {
op: 2,
d: IndentifyData(
token,
513,
33_281,
IdentifyProperties("unix", "discord_gleam", "discord_gleam"),
),
)
Expand Down
49 changes: 48 additions & 1 deletion src/discord_gleam/ws/packets/message.gleam
Original file line number Diff line number Diff line change
@@ -1,3 +1,50 @@
import gleam/dynamic
import gleam/json
import gleam/result

pub type MessageAuthor {
MessageAuthor(id: String, username: String)
}

pub type MessagePacketData {
MessagePacketData(content: String, guild_id: String, channel_id: String)
MessagePacketData(
content: String,
guild_id: String,
channel_id: String,
author: MessageAuthor,
)
}

pub type MessagePacket {
MessagePacket(t: String, s: Int, op: Int, d: MessagePacketData)
}

pub fn string_to_data(encoded: String) -> Result(MessagePacket, String) {
let decoder =
dynamic.decode4(
MessagePacket,
dynamic.field("t", of: dynamic.string),
dynamic.field("s", of: dynamic.int),
dynamic.field("op", of: dynamic.int),
dynamic.field(
"d",
of: dynamic.decode4(
MessagePacketData,
dynamic.field("content", of: dynamic.string),
dynamic.field("channel_id", of: dynamic.string),
dynamic.field("guild_id", of: dynamic.string),
dynamic.field(
"author",
of: dynamic.decode2(
MessageAuthor,
dynamic.field("id", of: dynamic.string),
dynamic.field("username", of: dynamic.string),
),
),
),
),
)

json.decode(from: encoded, using: decoder)
|> result.map_error(fn(_) { "Failed to decode MessagePacket" })
}
43 changes: 43 additions & 0 deletions src/discord_gleam/ws/packets/ready.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import gleam/dynamic
import gleam/json
import gleam/result
import logging

pub type ReadyUser {
ReadyUser(username: String)
}

pub type ReadyData {
ReadyData(v: Int, user: ReadyUser)
}

pub type ReadyPacket {
ReadyPacket(t: String, s: Int, op: Int, d: ReadyData)
}

pub fn string_to_data(encoded: String) -> Result(ReadyPacket, String) {
let decoder =
dynamic.decode4(
ReadyPacket,
dynamic.field("t", of: dynamic.string),
dynamic.field("s", of: dynamic.int),
dynamic.field("op", of: dynamic.int),
dynamic.field(
"d",
of: dynamic.decode2(
ReadyData,
dynamic.field("v", of: dynamic.int),
dynamic.field(
"user",
of: dynamic.decode1(
ReadyUser,
dynamic.field("username", of: dynamic.string),
),
),
),
),
)

json.decode(from: encoded, using: decoder)
|> result.map_error(fn(_) { "Failed to decode MessagePacket" })
}
23 changes: 21 additions & 2 deletions test/example_bot.gleam
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
import discord_gleam
import discord_gleam/event_handler
import logging

pub fn main(token: String) {
logging.configure()
logging.set_level(logging.Debug)
logging.set_level(logging.Info)

discord_gleam.run(token)
discord_gleam.run(token, [event_handler])
}

fn event_handler(packet: event_handler.Packet) {
case packet {
event_handler.ReadyPacket(ready) -> {
logging.log(logging.Info, "Logged in as " <> ready.d.user.username)
}
event_handler.MessagePacket(message) -> {
logging.log(
logging.Info,
"Received message: '"
<> message.d.content
<> "' from "
<> message.d.author.username,
)
}
_ -> Nil
}
}

0 comments on commit db2558a

Please sign in to comment.