fork of https://gitlab.com/grom-gleam/grom altered to work with https://fluxer.app
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sharding, fixed :)

* make sharding actually work
* make your first bot actually your first bot
* complete overhaul of the gateway API
* add mise

+53 -102
+6 -75
examples/your_first_bot/src/your_first_bot.gleam
··· 1 1 import dotenv_gleam 2 2 import envoy 3 - import gleam/erlang/process.{type Subject} 4 - import gleam/option.{None, Some} 3 + import gleam/erlang/process 4 + import gleam/option.{Some} 5 5 import gleam/string 6 6 import grom 7 - import grom/activity 8 7 import grom/command 9 8 import grom/gateway 10 9 import grom/gateway/intent ··· 12 11 import logging 13 12 14 13 type State { 15 - State(client: grom.Client, gateway: Subject(gateway.Message)) 14 + State(client: grom.Client) 16 15 } 17 16 18 17 pub fn main() -> Nil { ··· 30 29 let assert Ok(data) = gateway.get_data(client) 31 30 32 31 let gateway_start_result = 33 - gateway.new_with_initializer( 34 - fn(subject) { 35 - let state = State(client, subject) 36 - Ok(state) 37 - }, 38 - identify, 39 - data, 40 - ) 32 + gateway.new(State(client), identify, data) 41 33 |> gateway.on_event(do: on_event) 42 34 |> gateway.start 43 35 ··· 61 53 logging.log(logging.Warning, string.inspect(error)) 62 54 gateway.continue(state) 63 55 } 64 - gateway.ReadyEvent(ready) -> on_ready(state, ready) 56 + gateway.AllShardsReadyEvent(ready) -> on_ready(state, ready) 65 57 gateway.InteractionCreatedEvent(interaction) -> 66 58 on_interaction_created(state, interaction) 67 59 _ -> gateway.continue(state) 68 60 } 69 61 } 70 62 71 - fn on_ready(state: State, ready: gateway.ReadyMessage) { 63 + fn on_ready(state: State, ready: gateway.AllShardsReadyMessage) { 72 64 logging.log(logging.Info, "Ready!") 73 65 74 66 let global_commands = [ ··· 100 92 } 101 93 } 102 94 103 - state.gateway 104 - |> gateway.update_presence(using: gateway.UpdatePresenceMessage( 105 - status: gateway.Online, 106 - since: None, 107 - activities: [ 108 - activity.new(named: "the gateway connection", type_: activity.Watching), 109 - ], 110 - is_afk: False, 111 - )) 112 - 113 95 gateway.continue(state) 114 96 } 115 97 ··· 140 122 ) { 141 123 case command.name { 142 124 "ping" -> on_ping_command(state, interaction) 143 - "soundboards" -> on_soundboards_command(state, interaction) 144 - "join" -> on_join_command(state, interaction) 145 125 _ -> gateway.continue(state) 146 126 } 147 - } 148 - 149 - fn on_join_command( 150 - state: State, 151 - interaction: Interaction, 152 - ) -> gateway.Next(State) { 153 - state.gateway 154 - |> gateway.update_voice_state(using: gateway.UpdateVoiceStateMessage( 155 - "1155216444691325049", 156 - Some("1155216445211422795"), 157 - False, 158 - False, 159 - )) 160 - 161 - let _response_result = 162 - state.client 163 - |> interaction.respond( 164 - to: interaction, 165 - using: interaction.RespondWithChannelMessageWithSource( 166 - interaction.ResponseMessage( 167 - ..interaction.new_response_message(), 168 - content: Some("Joined!"), 169 - ), 170 - ), 171 - ) 172 - 173 - gateway.continue(state) 174 - } 175 - 176 - fn on_soundboards_command( 177 - state: State, 178 - interaction: Interaction, 179 - ) -> gateway.Next(State) { 180 - state.gateway 181 - |> gateway.request_soundboard_sounds(for: ["1155216444691325049"]) 182 - 183 - let _response_result = 184 - state.client 185 - |> interaction.respond( 186 - to: interaction, 187 - using: interaction.RespondWithChannelMessageWithSource( 188 - interaction.ResponseMessage( 189 - ..interaction.new_response_message(), 190 - content: Some("See the console!"), 191 - ), 192 - ), 193 - ) 194 - 195 - gateway.continue(state) 196 127 } 197 128 198 129 fn on_ping_command(state: State, interaction: Interaction) {
+3
mise.toml
··· 1 + [tools] 2 + erlang = "latest" 3 + gleam = "latest"
+44 -27
src/grom/gateway.gleam
··· 772 772 ) 773 773 } 774 774 775 - pub opaque type ConnectionManagerMessage { 775 + type ConnectionManagerMessage { 776 776 UpdateWebsocket(to: Subject(stratus.InternalMessage(StratusUserMessage))) 777 777 SendUserMessage(message: StratusUserMessage) 778 778 } 779 779 780 - pub opaque type Connection { 780 + type ConnectionManagerState { 781 + ConnectionManagerState( 782 + websocket: Option(Subject(stratus.InternalMessage(StratusUserMessage))), 783 + queued_messages: List(StratusUserMessage), 784 + ) 785 + } 786 + 787 + type Connection { 781 788 GettingReady( 782 789 gateway_url: String, 783 790 manager: Subject(ConnectionManagerMessage), ··· 812 819 UserMessage(UserMessage) 813 820 } 814 821 815 - pub opaque type UserMessage { 822 + type UserMessage { 816 823 StartPresenceUpdate(UpdatePresenceMessage) 817 824 StartVoiceStateUpdate(UpdateVoiceStateMessage) 818 825 StartGuildMembersRequest(RequestGuildMembersMessage) ··· 2384 2391 Some(count) -> count 2385 2392 None -> builder.data.recommended_shards 2386 2393 } 2394 + 2387 2395 let max_concurrency = 2388 2396 builder.data.session_start_limits.max_identify_requests_per_5_seconds 2389 2397 let supervisor = static_supervisor.new(static_supervisor.OneForOne) 2390 2398 2391 - let shard_ids = list.range(from: 0, to: shard_count) 2399 + let shard_ids = list.range(from: 0, to: shard_count - 1) 2392 2400 let shards = 2393 2401 shard_ids 2394 2402 |> list.map(fn(id) { Shard(id, shard_count) }) ··· 2399 2407 |> list.index_map(fn(shards, bucket) { 2400 2408 shards 2401 2409 |> list.map(fn(shard) { 2402 - BucketedShard(duration.seconds(max_concurrency * bucket), shard) 2410 + BucketedShard(duration.seconds(5 * bucket), shard) 2403 2411 }) 2404 2412 }) 2405 2413 ··· 2422 2430 process.new_selector() 2423 2431 |> process.select(subject) 2424 2432 2425 - bucketed_shards 2426 - |> list.each(fn(shards) { 2427 - shards 2428 - |> list.each(fn(shard) { 2433 + let supervisor = 2434 + bucketed_shards 2435 + |> list.flatten 2436 + |> list.fold(supervisor, fn(supervisor, shard) { 2429 2437 supervisor 2430 2438 |> static_supervisor.add(supervised_shard_spawner( 2431 2439 builder, ··· 2433 2441 subject, 2434 2442 )) 2435 2443 }) 2436 - }) 2437 2444 2438 2445 use _supervisor <- result.try( 2439 2446 supervisor ··· 2647 2654 ) 2648 2655 2649 2656 use connection_manager <- result.try( 2650 - actor.new(None) 2657 + actor.new(ConnectionManagerState(None, [])) 2651 2658 |> actor.on_message(on_connection_manager_message) 2652 2659 |> actor.start 2653 2660 |> result.map_error(grom.CouldNotStartActor), ··· 2848 2855 } 2849 2856 2850 2857 fn on_connection_manager_message( 2851 - current: Option(Subject(stratus.InternalMessage(StratusUserMessage))), 2858 + current: ConnectionManagerState, 2852 2859 message: ConnectionManagerMessage, 2853 - ) -> actor.Next(Option(Subject(stratus.InternalMessage(StratusUserMessage))), a) { 2854 - case current { 2855 - Some(manager) -> { 2856 - case message { 2857 - SendUserMessage(user_message) -> { 2858 - user_message 2859 - |> stratus.to_user_message 2860 - |> process.send(manager, _) 2860 + ) { 2861 + case message { 2862 + UpdateWebsocket(to: new) -> { 2863 + list.each(current.queued_messages, fn(msg) { 2864 + msg 2865 + |> stratus.to_user_message 2866 + |> process.send(new, _) 2867 + }) 2861 2868 2869 + actor.continue( 2870 + ConnectionManagerState(websocket: Some(new), queued_messages: []), 2871 + ) 2872 + } 2873 + SendUserMessage(msg) -> 2874 + case current.websocket { 2875 + Some(ws) -> { 2876 + msg 2877 + |> stratus.to_user_message 2878 + |> process.send(ws, _) 2862 2879 actor.continue(current) 2863 2880 } 2864 - UpdateWebsocket(to: new) -> actor.continue(Some(new)) 2865 - } 2866 - } 2867 - None -> 2868 - case message { 2869 - SendUserMessage(_) -> actor.continue(current) 2870 - UpdateWebsocket(to: new) -> actor.continue(Some(new)) 2881 + None -> 2882 + actor.continue( 2883 + ConnectionManagerState(..current, queued_messages: [ 2884 + msg, 2885 + ..current.queued_messages 2886 + ]), 2887 + ) 2871 2888 } 2872 2889 } 2873 2890 }