Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ gleam = ">= 1.0.0"

[dependencies]
gleam_stdlib = "~> 0.34 or ~> 1.0"
stratus = "~> 0.5"
stratus = "~> 0.9"
gleam_hackney = "~> 1.2"
gleam_json = "~> 1.0"
gleam_http = "~> 3.6"
gleam_otp = "~> 0.10"
gleam_erlang = "~> 0.24"
logging = "~> 1.0"
prng = "~> 3.0"
carpenter = "~> 0.2"
carpenter = "~> 0.3"
gleam_community_colour = "~> 1.4"

[dev-dependencies]
Expand Down
26 changes: 13 additions & 13 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,35 @@
# You typically do not need to edit this file

packages = [
{ name = "carpenter", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "carpenter", source = "hex", outer_checksum = "C9736B264C8BEEB1BE3DD2F95CA3CD4706AD1559298A0D843C7C2495CBBA5183" },
{ name = "carpenter", version = "0.3.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "carpenter", source = "hex", outer_checksum = "7F5AF15A315CF32E8EDD0700BC1E6711618F8049AFE66DFCE82D1161B33F7F1B" },
{ name = "certifi", version = "2.12.0", build_tools = ["rebar3"], requirements = [], otp_app = "certifi", source = "hex", outer_checksum = "EE68D85DF22E554040CDB4BE100F33873AC6051387BAF6A8F6CE82272340FF1C" },
{ name = "gleam_bitwise", version = "1.3.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "B36E1D3188D7F594C7FD4F43D0D2CE17561DE896202017548578B16FE1FE9EFC" },
{ name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" },
{ name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" },
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
{ name = "gleam_hackney", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib", "hackney"], otp_app = "gleam_hackney", source = "hex", outer_checksum = "066B1A55D37DBD61CC72A1C4EDE43C6015B1797FAF3818C16FE476534C7B6505" },
{ name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" },
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" },
{ name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" },
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" },
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
{ name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" },
{ name = "gramps", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "E4E6C0DB2A0527570DF3080706976BE47DEAABC4A7F57C9FE436FF619C27DC9E" },
{ name = "gleam_stdlib", version = "0.38.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "663CF11861179AF415A625307447775C09404E752FF99A24E2057C835319F1BE" },
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
{ name = "gramps", version = "2.0.3", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "3CCAA6E081225180D95C79679D383BBF51C8D1FDC1B84DA1DA444F628C373793" },
{ name = "hackney", version = "1.20.1", build_tools = ["rebar3"], requirements = ["certifi", "idna", "metrics", "mimerl", "parse_trans", "ssl_verify_fun", "unicode_util_compat"], otp_app = "hackney", source = "hex", outer_checksum = "FE9094E5F1A2A2C0A7D10918FEE36BFEC0EC2A979994CFF8CFE8058CD9AF38E3" },
{ name = "idna", version = "6.1.1", build_tools = ["rebar3"], requirements = ["unicode_util_compat"], otp_app = "idna", source = "hex", outer_checksum = "92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA" },
{ name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" },
{ name = "logging", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "FCB111401BDB4703A440A94FF8CC7DA521112269C065F219C2766998333E7738" },
{ name = "metrics", version = "1.0.1", build_tools = ["rebar3"], requirements = [], otp_app = "metrics", source = "hex", outer_checksum = "69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16" },
{ name = "mimerl", version = "1.2.0", build_tools = ["rebar3"], requirements = [], otp_app = "mimerl", source = "hex", outer_checksum = "F278585650AA581986264638EBF698F8BB19DF297F66AD91B18910DFC6E19323" },
{ name = "mimerl", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "mimerl", source = "hex", outer_checksum = "A1E15A50D1887217DE95F0B9B0793E32853F7C258A5CD227650889B38839FE9D" },
{ name = "parse_trans", version = "3.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "parse_trans", source = "hex", outer_checksum = "620A406CE75DADA827B82E453C19CF06776BE266F5A67CFF34E1EF2CBB60E49A" },
{ name = "prng", version = "3.0.2", build_tools = ["gleam"], requirements = ["gleam_bitwise", "gleam_stdlib"], otp_app = "prng", source = "hex", outer_checksum = "C61B103F9AF5031ADAA35187CCE7130845EF5088D88FD084E5995D4FBEC9D745" },
{ name = "prng", version = "3.0.3", build_tools = ["gleam"], requirements = ["gleam_bitwise", "gleam_stdlib"], otp_app = "prng", source = "hex", outer_checksum = "53006736FE23A0F61828C95B505193E10905D8DB76E128F1642D3E571E08F589" },
{ name = "ssl_verify_fun", version = "1.1.7", build_tools = ["mix", "rebar3", "make"], requirements = [], otp_app = "ssl_verify_fun", source = "hex", outer_checksum = "FE4C190E8F37401D30167C8C405EDA19469F34577987C76DDE613E838BBC67F8" },
{ name = "stratus", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gramps", "logging"], otp_app = "stratus", source = "hex", outer_checksum = "09DD25B2D59B0387159081C0456765178922AACCB4F0F0BB0F84371B12CD8D1F" },
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
{ name = "stratus", version = "0.9.0", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gramps", "logging"], otp_app = "stratus", source = "hex", outer_checksum = "4C1F14C801D1499E97A208F3EA82928DC1AFAF463DEA9F506F62BBE3E1D2C535" },
{ name = "thoas", version = "1.2.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A" },
{ name = "unicode_util_compat", version = "0.7.0", build_tools = ["rebar3"], requirements = [], otp_app = "unicode_util_compat", source = "hex", outer_checksum = "25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521" },
]

[requirements]
carpenter = { version = "~> 0.2" }
gleam_community_colour = { version = "~> 1.4"}
carpenter = { version = "~> 0.3" }
gleam_community_colour = { version = "~> 1.4" }
gleam_erlang = { version = "~> 0.24" }
gleam_hackney = { version = "~> 1.2" }
gleam_http = { version = "~> 3.6" }
Expand All @@ -40,4 +40,4 @@ gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
gleeunit = { version = "~> 1.0" }
logging = { version = "~> 1.0" }
prng = { version = "~> 3.0" }
stratus = { version = "~> 0.5" }
stratus = { version = "~> 0.9" }
13 changes: 9 additions & 4 deletions src/glyph/clients/bot.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

import gleam/erlang/process
import gleam/int
import gleam/io
import gleam/json
import gleam/list
import gleam/result
import gleam/otp/supervisor
import glyph/models/discord.{type BotClient, type GatewayIntent}
import gleam/result
import glyph/internal/cache
import glyph/internal/encoders
import glyph/internal/decoders
import glyph/internal/encoders
import glyph/internal/network/gateway
import glyph/internal/network/rest
import glyph/models/discord.{type BotClient, type GatewayIntent}

/// Generic bot error
pub type BotError {
Expand Down Expand Up @@ -39,7 +40,11 @@ pub fn new(

/// Initialize a supervisor that manages the WebSocket process (aka the bot)
pub fn initialize(bot: BotClient) -> Result(BotClient, BotError) {
let cache = cache.initialize()
use cache <- result.try(
cache.initialize()
|> result.replace_error(BotError("Encountered error initializing cache")),
)

use gateway_info <- result.try(get_gateway_info(bot))

let supervisor_gateway_subj = process.new_subject()
Expand Down
4 changes: 1 addition & 3 deletions src/glyph/internal/cache.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
import carpenter/table
import gleam/int
import gleam/list
import gleam/option
import gleam/pair
import gleam/result

/// Build a new ETS table
pub fn initialize() -> table.Set(String, String) {
pub fn initialize() -> Result(table.Set(String, String), Nil) {
table.build("glyph_session")
|> table.privacy(table.Public)
|> table.write_concurrency(table.AutoWriteConcurrency)
Expand All @@ -22,7 +21,6 @@ pub fn initialize() -> table.Set(String, String) {
fn get(cache: table.Set(String, String), key: String, default: String) -> String {
cache
|> table.lookup(key)
|> option.unwrap(or: [#("", default)])
|> list.first
|> result.unwrap(or: #("", default))
|> pair.second
Expand Down
73 changes: 44 additions & 29 deletions src/glyph/internal/network/gateway.gleam
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
//// This handles the logic for communicating with the [Discord Gateway API](https://discord.com/developers/docs/topics/gateway).

import carpenter/table
import gleam/dynamic
import gleam/erlang/process
import gleam/float
import gleam/function
import gleam/json
import gleam/option.{type Option, None, Some}
import gleam/http/request
import gleam/int
import gleam/io
import gleam/json
import gleam/option.{type Option, None, Some}
import gleam/otp/actor
import gleam/result
import gleam/string
import glyph/internal/cache
import glyph/internal/network/rest
import glyph/internal/decoders
import glyph/internal/network/rest
import glyph/models/discord
import stratus
import logging
import prng/random.{type Generator}
import carpenter/table
import stratus

pub type Msg {
Close
Expand Down Expand Up @@ -73,7 +74,7 @@ fn handle_gateway_recv(
case ready {
Ok(ev) -> {
state.session_cache
|> table.insert("resume_gateway_url", ev.resume_gateway_url)
|> table.insert([#("resume_gateway_url", ev.resume_gateway_url)])
ActorState(..state, bot_id: ev.user.id)
}
Error(_) -> {
Expand Down Expand Up @@ -133,7 +134,7 @@ fn handle_gateway_recv(
logging.log(logging.Debug, "Received Reconnect request from gateway")

state.session_cache
|> table.insert("should_resume", "true")
|> table.insert([#("should_resume", "true")])

process.send(state.self, Close)
state
Expand Down Expand Up @@ -181,7 +182,7 @@ fn handle_gateway_recv(
logging.Error,
"An unknown error occurred. Attempting reconnect.",
)
table.insert(state.session_cache, "should_resume", "true")
table.insert(state.session_cache, [#("should_resume", "true")])
process.send(state.self, Close)
state
}
Expand All @@ -190,19 +191,19 @@ fn handle_gateway_recv(
logging.Error,
"You sent an invalid opcode or an invalid payload for an opcode.",
)
table.insert(state.session_cache, "should_resume", "true")
table.insert(state.session_cache, [#("should_resume", "true")])
process.send(state.self, Close)
state
}
4002 -> {
logging.log(logging.Error, "You sent an invalid payload.")
table.insert(state.session_cache, "should_resume", "true")
table.insert(state.session_cache, [#("should_resume", "true")])
process.send(state.self, Close)
state
}
4003 -> {
logging.log(logging.Error, "You sent a payload prior to identifying.")
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, [#("should_resume", "false")])
process.send(state.self, Close)
state
}
Expand All @@ -211,14 +212,16 @@ fn handle_gateway_recv(
logging.Error,
"The account token sent with your identify payload is incorrect.",
)
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, "invalid_session", "true")
table.insert(state.session_cache, [
#("should_resume", "false"),
#("invalid_session", "true"),
])
process.send(state.self, Close)
state
}
4005 -> {
logging.log(logging.Error, "You send more than one identify payload.")
table.insert(state.session_cache, "should_resume", "true")
table.insert(state.session_cache, [#("should_resume", "true")])
process.send(state.self, Close)
state
}
Expand All @@ -227,7 +230,7 @@ fn handle_gateway_recv(
logging.Error,
"Invalid sequence sent when resuming the session.",
)
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, [#("should_resume", "false")])
process.send(state.self, Close)
state
}
Expand All @@ -236,20 +239,22 @@ fn handle_gateway_recv(
logging.Error,
"You have been rate limited for sending too many requests.",
)
table.insert(state.session_cache, "should_resume", "true")
table.insert(state.session_cache, [#("should_resume", "true")])
process.send(state.self, Close)
state
}
4009 -> {
logging.log(logging.Error, "Session timed out.")
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, [#("should_resume", "false")])
process.send(state.self, Close)
state
}
4010 -> {
logging.log(logging.Error, "You sent an invalid shard when identifying.")
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, "invalid_session", "true")
table.insert(state.session_cache, [
#("should_resume", "false"),
#("invalid_session", "true"),
])
process.send(state.self, Close)
state
}
Expand All @@ -258,15 +263,19 @@ fn handle_gateway_recv(
logging.Error,
"The session would have handled too many guilds - shard your connection to connect.",
)
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, "invalid_session", "true")
table.insert(state.session_cache, [
#("should_resume", "false"),
#("invalid_session", "true"),
])
process.send(state.self, Close)
state
}
4012 -> {
logging.log(logging.Error, "You sent an invalid version for the gateway.")
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, "invalid_session", "true")
table.insert(state.session_cache, [
#("should_resume", "false"),
#("invalid_session", "true"),
])
process.send(state.self, Close)
state
}
Expand All @@ -275,8 +284,10 @@ fn handle_gateway_recv(
logging.Error,
"You sent an invalid intent for a Gateway Intent. You may have incorrectly calculated the bitwise value.",
)
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, "invalid_session", "true")
table.insert(state.session_cache, [
#("should_resume", "false"),
#("invalid_session", "true"),
])
process.send(state.self, Close)
state
}
Expand All @@ -285,8 +296,10 @@ fn handle_gateway_recv(
logging.Error,
"You sent a disallowed intent for a Gateway Intent. You may have tried to specify an intent that you have not enabled or are not approved for.",
)
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, "invalid_session", "true")
table.insert(state.session_cache, [
#("should_resume", "false"),
#("invalid_session", "true"),
])
process.send(state.self, Close)
state
}
Expand All @@ -306,7 +319,9 @@ pub fn start_gateway_actor(
url: String,
session_cache: table.Set(String, String),
) -> Result(process.Subject(stratus.InternalMessage(Msg)), actor.StartError) {
let init_req = determine_url(session_cache, url)
let init_req =
determine_url(session_cache, url)
|> io.debug
let builder =
stratus.websocket(
request: init_req,
Expand Down Expand Up @@ -366,7 +381,7 @@ pub fn start_gateway_actor(
conn,
resume_json(bot.token, session_id, seq),
)
table.insert(state.session_cache, "should_resume", "false")
table.insert(state.session_cache, [#("should_resume", "false")])
actor.continue(state)
}
stratus.User(Close), _ -> {
Expand Down