diff --git a/src/discord_gleam.gleam b/src/discord_gleam.gleam index 08b95a8..cb80c7a 100644 --- a/src/discord_gleam.gleam +++ b/src/discord_gleam.gleam @@ -1,9 +1,22 @@ import discord_gleam/event_handler +import discord_gleam/http/endpoints +import discord_gleam/types/bot +import discord_gleam/types/message import discord_gleam/ws/event_loop +pub fn bot(token: String) -> bot.Bot { + bot.Bot(token: token) +} + pub fn run( - token: String, + bot: bot.Bot, event_handlers: List(event_handler.EventHandler), ) -> Nil { - event_loop.main(token, event_handlers) + event_loop.main(bot, event_handlers) +} + +pub fn send_message(bot: bot.Bot, message: String, channel_id: String) -> Nil { + let msg = message.Message(content: message) + + endpoints.send_message(bot.token, msg, channel_id) } diff --git a/src/discord_gleam/event_handler.gleam b/src/discord_gleam/event_handler.gleam index 050dbb6..a446164 100644 --- a/src/discord_gleam/event_handler.gleam +++ b/src/discord_gleam/event_handler.gleam @@ -1,3 +1,4 @@ +import discord_gleam/types/bot import discord_gleam/ws/packets/generic import discord_gleam/ws/packets/message import discord_gleam/ws/packets/ready @@ -5,7 +6,7 @@ import gleam/list import gleam/result pub type EventHandler = - fn(Packet) -> Nil + fn(bot.Bot, Packet) -> Nil pub type Packet { MessagePacket(message.MessagePacket) @@ -13,10 +14,14 @@ pub type Packet { UnknownPacket(generic.GenericPacket) } -pub fn handle_event(msg: String, handlers: List(EventHandler)) -> Nil { +pub fn handle_event( + bot: bot.Bot, + msg: String, + handlers: List(EventHandler), +) -> Nil { let packet = decode_packet(msg) - list.each(handlers, fn(handler) { handler(packet) }) + list.each(handlers, fn(handler) { handler(bot, packet) }) } fn decode_packet(msg: String) -> Packet { diff --git a/src/discord_gleam/http/endpoints.gleam b/src/discord_gleam/http/endpoints.gleam index 32ea83e..96f56c7 100644 --- a/src/discord_gleam/http/endpoints.gleam +++ b/src/discord_gleam/http/endpoints.gleam @@ -1,10 +1,13 @@ import discord_gleam/http/request import discord_gleam/internal/error +import discord_gleam/types/message import discord_gleam/types/user import gleam/dynamic import gleam/hackney import gleam/http import gleam/http/response +import gleam/io +import logging pub fn me(token: String) -> Result(user.User, error.DiscordError) { let request = request.new_auth(http.Get, "/users/@me", token) @@ -29,3 +32,36 @@ pub fn me(token: String) -> Result(user.User, error.DiscordError) { Error(err) -> Error(error.HttpError(err)) } } + +pub fn send_message( + token: String, + message: message.Message, + channel_id: String, +) -> Nil { + let data = message.to_string(message) + + io.debug(data) + + logging.log(logging.Debug, "Sending message: " <> message.content) + + let request = + request.new_auth_post( + http.Post, + "/channels/" <> channel_id <> "/messages", + token, + data, + ) + case hackney.send(request) { + Ok(resp) -> { + io.debug(resp) + + Nil + } + Error(err) -> { + logging.log(logging.Error, "Failed to send message: ") + io.debug(err) + + Nil + } + } +} diff --git a/src/discord_gleam/http/request.gleam b/src/discord_gleam/http/request.gleam index 798ca77..f11eea8 100644 --- a/src/discord_gleam/http/request.gleam +++ b/src/discord_gleam/http/request.gleam @@ -9,7 +9,7 @@ pub fn new(method: http.Method, path: String) -> request.Request(String) { |> request.prepend_header("accept", "application/json") |> request.prepend_header( "User-Agent", - "DiscordBot using Gleam and cyteon/discord_gleam", + "DiscordBot (https://github.com/cyteon/discord_gleam, 0.0.0)", ) } @@ -22,3 +22,16 @@ pub fn new_auth( new(method, path) |> request.prepend_header("Authorization", "Bot " <> token) } + +/// We have this to send post requests with token authentication +pub fn new_auth_post( + method: http.Method, + path: String, + token: String, + data: String, +) -> request.Request(String) { + new(method, path) + |> request.prepend_header("Authorization", "Bot " <> token) + |> request.set_body(data) + |> request.prepend_header("Content-Type", "application/json") +} diff --git a/src/discord_gleam/types/bot.gleam b/src/discord_gleam/types/bot.gleam new file mode 100644 index 0000000..b6cd0aa --- /dev/null +++ b/src/discord_gleam/types/bot.gleam @@ -0,0 +1,3 @@ +pub type Bot { + Bot(token: String) +} diff --git a/src/discord_gleam/types/message.gleam b/src/discord_gleam/types/message.gleam new file mode 100644 index 0000000..a5293a1 --- /dev/null +++ b/src/discord_gleam/types/message.gleam @@ -0,0 +1,10 @@ +import gleam/json + +pub type Message { + Message(content: String) +} + +pub fn to_string(msg: Message) -> String { + json.object([#("content", json.string(msg.content))]) + |> json.to_string +} diff --git a/src/discord_gleam/ws/event_loop.gleam b/src/discord_gleam/ws/event_loop.gleam index 9a5707a..630fb8a 100644 --- a/src/discord_gleam/ws/event_loop.gleam +++ b/src/discord_gleam/ws/event_loop.gleam @@ -1,4 +1,5 @@ import discord_gleam/event_handler +import discord_gleam/types/bot import discord_gleam/ws/packets/hello import discord_gleam/ws/packets/identify import gleam/erlang/process @@ -21,7 +22,7 @@ pub type State { State(has_received_hello: Bool, sequence: Int) } -pub fn main(token: String, event_handlers: List(event_handler.EventHandler)) { +pub fn main(bot: bot.Bot, event_handlers: List(event_handler.EventHandler)) { logging.log(logging.Debug, "Requesting gateway") let req = @@ -54,7 +55,7 @@ pub fn main(token: String, event_handlers: List(event_handler.EventHandler)) { logging.log(logging.Debug, msg) case state.has_received_hello { False -> { - let identify = identify.create_packet(token) + let identify = identify.create_packet(bot.token) let _ = stratus.send_text_message(conn, identify) let new_state = State(has_received_hello: True, sequence: 0) @@ -83,7 +84,7 @@ pub fn main(token: String, event_handlers: List(event_handler.EventHandler)) { actor.continue(new_state) } True -> { - event_handler.handle_event(msg, event_handlers) + event_handler.handle_event(bot, msg, event_handlers) actor.continue(state) } diff --git a/src/discord_gleam/ws/packets/message.gleam b/src/discord_gleam/ws/packets/message.gleam index 3cd3373..66166d8 100644 --- a/src/discord_gleam/ws/packets/message.gleam +++ b/src/discord_gleam/ws/packets/message.gleam @@ -31,8 +31,8 @@ pub fn string_to_data(encoded: String) -> Result(MessagePacket, String) { 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("channel_id", of: dynamic.string), dynamic.field( "author", of: dynamic.decode2( diff --git a/test/example_bot.gleam b/test/example_bot.gleam index 8822df4..62044e1 100644 --- a/test/example_bot.gleam +++ b/test/example_bot.gleam @@ -4,24 +4,26 @@ import logging pub fn main(token: String) { logging.configure() - logging.set_level(logging.Info) + logging.set_level(logging.Debug) - discord_gleam.run(token, [event_handler]) + let bot = discord_gleam.bot(token) + + discord_gleam.run(bot, [event_handler]) } -fn event_handler(packet: event_handler.Packet) { +fn event_handler(bot, 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, - ) + logging.log(logging.Info, "Message: " <> message.d.content) + case message.d.content { + "!ping" -> { + discord_gleam.send_message(bot, "Pong!", message.d.channel_id) + } + _ -> Nil + } } _ -> Nil }