diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 2529afe..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: terisback # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f9ae180..fdfe5fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,47 +1,27 @@ name: CI -on: [push, pull_request] +on: + push: + paths-ignore: + - '**.md' + pull_request: + paths-ignore: + - "**.md" jobs: - # code-formatting: - # runs-on: ubuntu-latest - # steps: - # - name: Checkout V - # uses: actions/checkout@v2 - # with: - # repository: vlang/v - # - name: Checkout VPM - # uses: actions/checkout@v2 - # with: - # path: vpm - # - name: Build V - # run: make - # - name: v fmt -verify - # run: | - # cd vpm - # ../v fmt -verify vpm.v user.v token.v package.v login.v db.v - - ubuntu: - runs-on: ubuntu-18.04 + compile: + name: Ping-pong example + runs-on: ubuntu-latest + timeout-minutes: 5 steps: - - name: Checkout V + - name: Checkout uses: actions/checkout@v2 with: - repository: vlang/v - - name: Build V - run: make - - name: Checkout discord.v - uses: actions/checkout@v2 + path: discordv + - name: Set up V version latest + uses: nocturlab/setup-vlang-action@v1 with: - path: terisback/discordv - - name: Install dependencies - run: sudo apt-get install --quiet -y libssl-dev - - name: Build ping-pong example - run: | - ./v ./terisback/discordv/examples/ping-pong/main.v - - name: Build send-embed example - run: | - ./v ./terisback/discordv/examples/send-embed/main.v - - name: Build upload-image example - run: | - ./v ./terisback/discordv/examples/upload-image/main.v + v-version: latest + id: v + - name: Compile + run: v discordv/examples/ping-pong \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0b12487..57df641 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,9 @@ -main -build -discordv +/main +/build +/discordv *.exe *.ilk *.pdb *.so *.dylib -*.dll - -.vscode \ No newline at end of file +*.dll \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..62796ad --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "vlanguage.vscode-vlang", + "ms-vscode.cpptools" + ], + "unwantedRecommendations": [] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index f0206e7..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,30 +0,0 @@ - -## discord.[v](https://github.com/Terisback/discord.v) 0.1.0 - *kinda major* -*04 Jan 2021* -- Separate `client` module - - Gateway can be imported and used anywhere as module. - - Client implemented in root module (discord.v) -- Delete `sharding` module -- Implement Sharding in Client -- Delete `structs` module -- All structs implemented in root module (discord.v) -- Implement all events from Gateway -- Concat all struct files into [one](https://github.com/Terisback/discord.v/blob/master/structs.v) -- Implement some REST - - Rate Limiting with buckets - - `multipart/form-data` for file uploading - - `channel_message_send` request can send text, embeds, images -- Create 3 examples - - Simplest [Ping-Pong Bot](https://github.com/Terisback/discord.v/blob/master/examples/ping-pong/main.v) - - Embed [example](https://github.com/Terisback/discord.v/blob/master/examples/send-embed/main.v) - - Upload image [example](https://github.com/Terisback/discord.v/blob/master/examples/upload-image/main.v) -- New [FancyLog](https://github.com/Terisback/discord.v/blob/master/fancylog/log.v) for internal logging -- Get rid of `util` module, now snowflake accessible by `discordv.snowflake` - - -## discord.[v](https://github.com/Terisback/discord.v) 0.0.1 - *doo doo* -*13 Nov 2020* -- Established a connection to the Discord gateway -- Rewrited EventBus from vlib to fit our needs (custom EventHandlerFn) -- We have Ready, MessageCreate, MessageUpdate, MessageDelete events to subscribe -- Sharding barebones \ No newline at end of file diff --git a/client.v b/client.v index ab79ca3..9c4bee6 100644 --- a/client.v +++ b/client.v @@ -52,13 +52,13 @@ pub fn new(config Config) ?&Client { } client.log = m_log for i in 0 .. config.shard_count { - mut shard := gateway.new_shard( + mut shard := gateway.new_shard(gateway.Config{ token: config.token intents: config.intents shard_id: i shards_in_total: config.shard_count dispatchers: config.dispatchers_on_shard - ) ? + }) shard.log = client.log $if dv_ws_debug ? { shard.set_ws_log_level(.debug) diff --git a/events.v b/events.v index c275828..ade4f7b 100644 --- a/events.v +++ b/events.v @@ -1,7 +1,8 @@ module discordv import time -import x.json2 as json +import json +import x.json2 import gateway.packets import snowflake @@ -18,15 +19,11 @@ pub mut: last_pin_timestamp time.Time } -pub fn (mut cpu ChannelPinsUpdate) from_json(f map[string]json.Any) { +pub fn (mut cpu ChannelPinsUpdate) from_json(data string) { + obj := json2.raw_decode(data) or { return } + f := obj.as_map() for k, v in f { match k { - 'guild_id' { - cpu.guild_id = v.str() - } - 'channel_id' { - cpu.channel_id = v.str() - } 'last_pin_timestamp' { cpu.last_pin_timestamp = time.parse_iso8601(v.str()) or { time.unix(int(snowflake.discord_epoch / 1000)) @@ -47,20 +44,6 @@ pub mut: user User } -pub fn (mut gb GuildBan) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'guild_id' { - gb.guild_id = v.str() - } - 'user' { - gb.user = from_json(v.as_map()) - } - else {} - } - } -} - pub type GuildBanAdd = GuildBan pub type GuildBanRemove = GuildBan @@ -70,62 +53,23 @@ pub mut: emojis []Emoji } -pub fn (mut geu GuildEmojisUpdate) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'guild_id' { - geu.guild_id = v.str() - } - 'emojis' { - geu.emojis = from_json_arr(v.arr()) - } - else {} - } - } -} - pub struct GuildIntegrationsUpdate { pub mut: guild_id string } -pub fn (mut geu GuildIntegrationsUpdate) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'guild_id' { - geu.guild_id = v.str() - } - else {} - } - } -} - pub struct GuildMemberAdd { pub mut: guild_id string member Member } -pub fn (mut gma GuildMemberAdd) from_json(f map[string]json.Any) { - if 'guild_id' in f { - gma.guild_id = f['guild_id'].str() - } - gma.member.from_json(f) -} - pub struct GuildMemberRemove { pub mut: guild_id string user User } -pub fn (mut gmr GuildMemberRemove) from_json(f map[string]json.Any) { - if 'guild_id' in f { - gmr.guild_id = f['guild_id'].str() - } - gmr.user.from_json(f['user'].as_map()) -} - pub struct GuildMemberUpdate { pub mut: guild_id string @@ -136,24 +80,11 @@ pub mut: premium_since time.Time } -pub fn (mut gmu GuildMemberUpdate) from_json(f map[string]json.Any) { +pub fn (mut gmu GuildMemberUpdate) from_json(data string) { + obj := json2.raw_decode(data) or { return } + f := obj.as_map() for k, v in f { match k { - 'guild_id' { - gmu.guild_id = v.str() - } - 'roles' { - mut roles := v.arr() - for role in roles { - gmu.roles << role.str() - } - } - 'user' { - gmu.user = from_json(v.as_map()) - } - 'nick' { - gmu.nick = v.str() - } 'joined_at' { gmu.joined_at = time.parse_iso8601(v.str()) or { time.unix(int(snowflake.discord_epoch / 1000)) @@ -180,58 +111,12 @@ pub mut: nonce string } -pub fn (mut gmc GuildMembersChunk) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'guild_id' { - gmc.guild_id = v.str() - } - 'members' { - gmc.members = from_json_arr(v.arr()) - } - 'chunk_index' { - gmc.chunk_index = v.int() - } - 'chunk_count' { - gmc.chunk_count = v.int() - } - 'not_found' { - mut ids := v.arr() - for id in ids { - gmc.not_found << id.str() - } - } - 'presences' { - gmc.presences = from_json_arr(v.arr()) - } - 'nonce' { - gmc.nonce = v.str() - } - else {} - } - } -} - struct GuildRole { pub mut: guild_id string role Role } -pub fn (mut gr GuildRole) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'guild_id' { - gr.guild_id = v.str() - } - 'role' { - gr.role = from_json(v.as_map()) - } - else {} - } - } -} - pub type GuildRoleCreate = GuildRole pub type GuildRoleUpdate = GuildRole @@ -241,20 +126,6 @@ pub mut: role_id string } -pub fn (mut grd GuildRoleDelete) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'guild_id' { - grd.guild_id = v.str() - } - 'role_id' { - grd.role_id = v.str() - } - else {} - } - } -} - pub struct InviteCreate { pub mut: channel_id string @@ -269,42 +140,12 @@ pub mut: uses int } -pub fn (mut ic InviteCreate) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'channel_id' { - ic.channel_id = v.str() - } - 'code' { - ic.code = v.str() - } - 'created_at' { - ic.created_at = time.parse_iso8601(v.str()) or { - time.unix(int(snowflake.discord_epoch / 1000)) - } - } - 'guild_id' { - ic.guild_id = v.str() - } - 'inviter' { - ic.inviter = from_json(v.as_map()) - } - 'max_age' { - ic.max_age = v.int() - } - 'max_uses' { - ic.max_uses = v.int() - } - 'target_user' { - ic.target_user = from_json(v.as_map()) - } - 'temporary' { - ic.temporary = v.bool() - } - 'uses' { - ic.uses = v.int() - } - else {} +pub fn (mut ic InviteCreate) from_json(data string) { + obj := json2.raw_decode(data) or { return } + mmm := obj.as_map() + if 'created_at' in mmm { + ic.created_at = time.parse_iso8601(mmm['created_at'].str()) or { + time.unix(int(snowflake.discord_epoch / 1000)) } } } @@ -316,23 +157,6 @@ pub mut: code string } -pub fn (mut id InviteDelete) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'channel_id' { - id.channel_id = v.str() - } - 'guild_id' { - id.guild_id = v.str() - } - 'code' { - id.code = v.str() - } - else {} - } - } -} - pub type MessageCreate = Message pub type MessageUpdate = Message pub type MessageDelete = Message @@ -344,26 +168,6 @@ pub mut: guild_id string } -pub fn (mut mdb MessageDeleteBulk) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'ids' { - mut ids := v.arr() - for id in ids { - mdb.ids << id.str() - } - } - 'channel_id' { - mdb.channel_id = v.str() - } - 'guild_id' { - mdb.guild_id = v.str() - } - else {} - } - } -} - pub struct MessageReactionAdd { pub mut: user_id string @@ -374,32 +178,6 @@ pub mut: emoji Emoji } -pub fn (mut mra MessageReactionAdd) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'user_id' { - mra.user_id = v.str() - } - 'channel_id' { - mra.channel_id = v.str() - } - 'message_id' { - mra.message_id = v.str() - } - 'guild_id' { - mra.guild_id = v.str() - } - 'member' { - mra.member = from_json(v.as_map()) - } - 'emoji' { - mra.emoji = from_json(v.as_map()) - } - else {} - } - } -} - pub struct MessageReactionRemove { pub mut: user_id string @@ -409,29 +187,6 @@ pub mut: emoji Emoji } -pub fn (mut mra MessageReactionRemove) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'user_id' { - mra.user_id = v.str() - } - 'channel_id' { - mra.channel_id = v.str() - } - 'message_id' { - mra.message_id = v.str() - } - 'guild_id' { - mra.guild_id = v.str() - } - 'emoji' { - mra.emoji = from_json(v.as_map()) - } - else {} - } - } -} - pub struct MessageReactionRemoveAll { pub mut: channel_id string @@ -439,23 +194,6 @@ pub mut: guild_id string } -pub fn (mut mra MessageReactionRemoveAll) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'channel_id' { - mra.channel_id = v.str() - } - 'message_id' { - mra.message_id = v.str() - } - 'guild_id' { - mra.guild_id = v.str() - } - else {} - } - } -} - pub struct MessageReactionRemoveEmoji { pub mut: channel_id string @@ -464,26 +202,6 @@ pub mut: emoji Emoji } -pub fn (mut mra MessageReactionRemoveEmoji) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'channel_id' { - mra.channel_id = v.str() - } - 'message_id' { - mra.message_id = v.str() - } - 'guild_id' { - mra.guild_id = v.str() - } - 'emoji' { - mra.emoji = from_json(v.as_map()) - } - else {} - } - } -} - pub struct TypingStart { pub mut: channel_id string @@ -493,29 +211,6 @@ pub mut: member Member } -pub fn (mut ts TypingStart) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'channel_id' { - ts.channel_id = v.str() - } - 'guild_id' { - ts.guild_id = v.str() - } - 'user_id' { - ts.user_id = v.str() - } - 'timestamp' { - ts.timestamp = v.int() - } - 'member' { - ts.member = from_json(v.as_map()) - } - else {} - } - } -} - pub type UserUpdate = User pub type VoiceStateUpdate = VoiceState @@ -526,43 +221,12 @@ pub mut: endpoint string } -pub fn (mut vsu VoiceServerUpdate) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'token' { - vsu.token = v.str() - } - 'guild_id' { - vsu.guild_id = v.str() - } - 'endpoint' { - vsu.endpoint = v.str() - } - else {} - } - } -} - pub struct WebhooksUpdate { pub mut: guild_id string channel_id string } -pub fn (mut wu WebhooksUpdate) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'guild_id' { - wu.guild_id = v.str() - } - 'channel_id' { - wu.channel_id = v.str() - } - else {} - } - } -} - pub type InteractionCreate = Interaction // Publishing hello event to client eventbus @@ -573,81 +237,68 @@ fn on_hello(mut client Client, hello &packets.Hello) { // Deals with packets from gateway. Publishing to client eventbus fn on_dispatch(mut client Client, packet &packets.Packet) { event_name := packet.event.to_lower() - mut data := packet.data.as_map() + data := packet.data client.events.publish('dispatch', client, packet) match event_name { 'ready' { - mut obj := Ready{} - obj.from_json(data) + obj := json.decode(Ready, data) or { return } client.events.publish(event_name, client, obj) } 'channel_create' { - mut obj := ChannelCreate{} - obj.from_json(data) + obj := json.decode(ChannelCreate, data) or { return } client.events.publish(event_name, client, obj) } 'channel_update' { - mut obj := ChannelUpdate{} - obj.from_json(data) + obj := json.decode(ChannelUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'channel_delete' { - mut obj := ChannelDelete{} - obj.from_json(data) + obj := json.decode(ChannelDelete, data) or { return } client.events.publish(event_name, client, obj) } 'channel_pins_update' { - mut obj := ChannelPinsUpdate{} + mut obj := json.decode(ChannelPinsUpdate, data) or { return } obj.from_json(data) client.events.publish(event_name, client, obj) } 'guild_create' { - mut obj := GuildCreate{} - obj.from_json(data) + obj := json.decode(GuildCreate, data) or { return } client.events.publish(event_name, client, obj) } 'guild_update' { - mut obj := GuildUpdate{} - obj.from_json(data) + obj := json.decode(GuildUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'guild_delete' { - mut obj := GuildDelete{} - obj.from_json(data) + obj := json.decode(GuildDelete, data) or { return } client.events.publish(event_name, client, obj) } 'guild_ban_add' { - mut obj := GuildBanAdd{} - obj.from_json(data) + obj := json.decode(GuildBanAdd, data) or { return } client.events.publish(event_name, client, obj) } 'guild_ban_remove' { - mut obj := GuildBanRemove{} - obj.from_json(data) + obj := json.decode(GuildBanRemove, data) or { return } client.events.publish(event_name, client, obj) } 'guild_emojis_update' { - mut obj := GuildEmojisUpdate{} - obj.from_json(data) + obj := json.decode(GuildEmojisUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'guild_integrations_update' { - mut obj := GuildIntegrationsUpdate{} - obj.from_json(data) + obj := json.decode(GuildIntegrationsUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'guild_member_add' { - mut obj := GuildMemberAdd{} - obj.from_json(data) + obj := json.decode(GuildMemberAdd, data) or { return } client.events.publish(event_name, client, obj) } 'guild_member_remove' { - mut obj := GuildMemberRemove{} - obj.from_json(data) + obj := json.decode(GuildMemberRemove, data) or { return } client.events.publish(event_name, client, obj) } 'guild_member_update' { - mut obj := GuildMemberUpdate{} + mut obj := json.decode(GuildMemberUpdate, data) or { return } obj.from_json(data) client.events.publish(event_name, client, obj) } @@ -655,103 +306,84 @@ fn on_dispatch(mut client Client, packet &packets.Packet) { // TODO: Handle by nonce, return to rest } 'guild_role_create' { - mut obj := GuildRoleCreate{} - obj.from_json(data) + obj := json.decode(GuildRoleCreate, data) or { return } client.events.publish(event_name, client, obj) } 'guild_role_update' { - mut obj := GuildRoleUpdate{} - obj.from_json(data) + obj := json.decode(GuildRoleUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'guild_role_delete' { - mut obj := GuildRoleDelete{} - obj.from_json(data) + obj := json.decode(GuildRoleDelete, data) or { return } client.events.publish(event_name, client, obj) } 'invite_create' { - mut obj := InviteCreate{} + mut obj := json.decode(InviteCreate, data) or { return } obj.from_json(data) client.events.publish(event_name, client, obj) } 'invite_delete' { - mut obj := InviteDelete{} - obj.from_json(data) + obj := json.decode(InviteDelete, data) or { return } client.events.publish(event_name, client, obj) } 'message_create' { - mut obj := MessageCreate{} - obj.from_json(data) + obj := json.decode(MessageCreate, data) or { return } client.events.publish(event_name, client, obj) } 'message_update' { - mut obj := MessageUpdate{} - obj.from_json(data) + obj := json.decode(MessageUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'message_delete' { - mut obj := MessageDelete{} - obj.from_json(data) + obj := json.decode(MessageDelete, data) or { return } client.events.publish(event_name, client, obj) } 'message_delete_bulk' { - mut obj := MessageDeleteBulk{} - obj.from_json(data) + obj := json.decode(MessageDeleteBulk, data) or { return } client.events.publish(event_name, client, obj) } 'message_reaction_add' { - mut obj := MessageReactionAdd{} - obj.from_json(data) + obj := json.decode(MessageReactionAdd, data) or { return } client.events.publish(event_name, client, obj) } 'message_reaction_remove' { - mut obj := MessageReactionRemove{} - obj.from_json(data) + obj := json.decode(MessageReactionRemove, data) or { return } client.events.publish(event_name, client, obj) } 'message_reaction_remove_all' { - mut obj := MessageReactionRemoveAll{} - obj.from_json(data) + obj := json.decode(MessageReactionRemoveAll, data) or { return } client.events.publish(event_name, client, obj) } 'message_reaction_remove_emoji' { - mut obj := MessageReactionRemoveEmoji{} - obj.from_json(data) + obj := json.decode(MessageReactionRemoveEmoji, data) or { return } client.events.publish(event_name, client, obj) } 'presence_update' { - mut obj := PresenceUpdate{} - obj.from_json(data) + obj := json.decode(PresenceUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'typing_start' { - mut obj := TypingStart{} - obj.from_json(data) + obj := json.decode(TypingStart, data) or { return } client.events.publish(event_name, client, obj) } 'user_update' { - mut obj := UserUpdate{} - obj.from_json(data) + obj := json.decode(UserUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'voice_state_update' { - mut obj := VoiceStateUpdate{} - obj.from_json(data) + obj := json.decode(VoiceStateUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'voice_server_update' { - mut obj := VoiceServerUpdate{} - obj.from_json(data) + obj := json.decode(VoiceServerUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'webhooks_update' { - mut obj := WebhooksUpdate{} - obj.from_json(data) + obj := json.decode(WebhooksUpdate, data) or { return } client.events.publish(event_name, client, obj) } 'interaction_create' { - mut obj := InteractionCreate{} - obj.from_json(data) + obj := json.decode(InteractionCreate, data) or { return } client.events.publish(event_name, client, obj) } else { diff --git a/examples/ping-pong/main.v b/examples/ping-pong/main.v index ea37f47..8ab5c33 100644 --- a/examples/ping-pong/main.v +++ b/examples/ping-pong/main.v @@ -1,7 +1,8 @@ module main import os -import terisback.discordv +import json +import Terisback.discordv fn main() { // Getting token from env variable @@ -10,8 +11,11 @@ fn main() { println('Please provide bot token via environment variable BOT_TOKEN') return } + config := discordv.Config{ + token: token + } // Creating new client - mut client := discordv.new(token: token) ? + mut client := discordv.new(config) // Add message create handler client.on_message_create(on_ping) // Open connection and wait till close @@ -24,5 +28,18 @@ fn on_ping(mut client discordv.Client, evt &discordv.MessageCreate) { if evt.content == '!ping' { // Send message to channel client.channel_message_send(evt.channel_id, content: 'pong!') or {} + + al := client.guild_audit_log(evt.guild_id, limit: 16) or { + client.channel_message_send(evt.channel_id, content: 'something went wrong') or {} + return + } + + mut txt := json.encode_pretty(al) + + if txt.len > 2000 { + txt = txt[..2000] + } + + client.channel_message_send(evt.channel_id, content: txt) or {} } } diff --git a/gateway/commands.v b/gateway/commands.v index b8509cb..fe2b957 100644 --- a/gateway/commands.v +++ b/gateway/commands.v @@ -1,6 +1,7 @@ module gateway -import x.json2 as json +import json +import x.json2 import gateway.packets // request_guild_members arguments @@ -13,11 +14,11 @@ pub struct RequestGuildMembersArgs { nonce string } -pub fn (req RequestGuildMembersArgs) to_json() json.Any { - mut obj := map[string]json.Any{} +pub fn (req RequestGuildMembersArgs) args() string { + mut obj := map[string]json2.Any{} obj['guild_id'] = req.guild_id if req.user_ids.len != 0 { - mut usr_ids := []json.Any{} + mut usr_ids := []json2.Any{} for usr in req.user_ids { usr_ids << usr } @@ -28,16 +29,16 @@ pub fn (req RequestGuildMembersArgs) to_json() json.Any { obj['limit'] = req.limit obj['presences'] = req.presences obj['nonce'] = req.nonce - return obj + return obj.str() } // Request guild members (It will wait answer from websocket) pub fn (mut shard Shard) request_guild_members(args RequestGuildMembersArgs) { - mut command := packets.Packet{ + command := packets.Packet{ op: .request_guild_members - data: args.to_json() - }.str() - shard.ws.write_string(command) or { panic(err) } + data: args.args() + } + shard.ws.write_string(json.encode(command)) or { panic(err) } } struct VoiceChannelJoinData { @@ -47,27 +48,18 @@ struct VoiceChannelJoinData { self_deaf bool } -pub fn (data VoiceChannelJoinData) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['guild_id'] = data.guild_id - obj['channel_id'] = data.channel_id - obj['self_mute'] = data.self_mute - obj['self_deaf'] = data.self_deaf - return obj -} - // initiates a voice session to a voice channel, but does not complete it. -// if channel_id is empty, bot gonna disconnect. +// if channel_id is empty, bot gonna disconnect from voice channel. pub fn (mut shard Shard) channel_voice_join_manual(guild_id string, channel_id string, mute bool, deaf bool) ? { - mut command := packets.Packet{ + command := packets.Packet{ op: .voice_state_update - data: VoiceChannelJoinData{ + data: json.encode(VoiceChannelJoinData{ guild_id: guild_id channel_id: channel_id self_mute: mute self_deaf: deaf - }.to_json() - }.str() - shard.ws.write_string(command) ? + }) + } + shard.ws.write_string(json.encode(command)) ? shard.log.info('Connected to voice channel [guild_id: $guild_id, channel_id: $channel_id]') } diff --git a/gateway/handlers.v b/gateway/handlers.v index 8c9b381..3822a00 100644 --- a/gateway/handlers.v +++ b/gateway/handlers.v @@ -1,35 +1,37 @@ module gateway import time +import json import gateway.packets // Handles hello from Websocket fn (mut shard Shard) handle_hello(packet packets.Packet) { - mut hello := packets.Hello{} - hello.from_json(packet.data) + hello := json.decode(packets.Hello, packet.data) or { + // shard log error + return + } shard.heartbeat_interval = hello.heartbeat_interval if shard.resuming { - mut resume := packets.Resume{ - token: shard.token - session_id: shard.session_id - sequence: shard.sequence - } message := packets.Packet{ op: .resume - data: resume.to_json_any() - }.to_json() - shard.ws.write_string(message) or { panic(err) } + data: json.encode(packets.Resume{ + token: shard.token + session_id: shard.session_id + sequence: shard.sequence + }) + } + shard.ws.write_string(json.encode(message)) or { panic(err) } shard.resuming = false } else { message := packets.Packet{ op: .identify - data: packets.Identify{ + data: json.encode(packets.Identify{ token: shard.token intents: shard.intents shard: [shard.id, shard.total_count] - }.to_json_any() - }.to_json() - shard.ws.write_string(message) or { panic(err) } + }) + } + shard.ws.write_string(json.encode(message)) or { panic(err) } } shard.last_heartbeat = time.now().unix_time_milli() } @@ -43,3 +45,10 @@ fn (mut shard Shard) handle_heartbeat_ack(packet packets.Packet) { fn (mut shard Shard) handle_invalid_session(packet packets.Packet) { shard.resuming = packet.data.bool() } + +fn (mut shard Shard) handle_reconnect(packet packets.Packet) { + shard.resuming = true + shard.ws.close(int(CloseCode.normal_closure), 'Reconnect') or { + shard.log.info('#$shard.id Unhandled opcode: ${int(packet.op)} ($packet.op)') + } +} diff --git a/gateway/packets/hello.v b/gateway/packets/hello.v index 1aeeeca..61d2bf2 100644 --- a/gateway/packets/hello.v +++ b/gateway/packets/hello.v @@ -1,19 +1,7 @@ module packets -import x.json2 as json - // Websocket Hello packet data pub struct Hello { -pub mut: +pub: heartbeat_interval u64 } - -pub fn (mut p Hello) from_json(f json.Any) { - mut obj := f.as_map() - for k, v in obj { - match k { - 'heartbeat_interval' { p.heartbeat_interval = v.str().u64() } - else {} - } - } -} diff --git a/gateway/packets/identify.v b/gateway/packets/identify.v index 10bddf6..be708cc 100644 --- a/gateway/packets/identify.v +++ b/gateway/packets/identify.v @@ -1,7 +1,6 @@ module packets import os -import x.json2 as json // Websocket Identify packet data pub struct Identify { @@ -9,36 +8,13 @@ pub: token string properties IdentifyProperties = IdentifyProperties{} intents int - shard []int + shard []int = [0, 1] } // Identify packet properies pub struct IdentifyProperties { pub: - os string = os.user_os() - browser string = 'discord.v' - device string = 'discord.v' -} - -pub fn (d Identify) to_json_any() json.Any { - mut obj := map[string]json.Any{} - obj['token'] = d.token - obj['intents'] = d.intents - if d.shard.len != 2 { - mut shards := []json.Any{} - shards << int(0) - shards << int(1) - obj['shard'] = shards - } else { - mut shards := []json.Any{} - shards << d.shard[0] - shards << d.shard[1] - obj['shard'] = shards - } - mut prop := map[string]json.Any{} - prop[r'$os'] = d.properties.os - prop[r'$browser'] = d.properties.browser - prop[r'$device'] = d.properties.device - obj['properties'] = prop - return obj + os string [json: '\$os'] = os.user_os() + browser string [json: '\$browser'] = 'discord.v' + device string [json: '\$device'] = 'discord.v' } diff --git a/gateway/packets/packet.v b/gateway/packets/packet.v index 7376d91..e1659bf 100644 --- a/gateway/packets/packet.v +++ b/gateway/packets/packet.v @@ -1,38 +1,10 @@ module packets -import x.json2 as json - // Websocket Packet pub struct Packet { -pub mut: - op Op - sequence int - event string - data json.Any -} - -pub fn (mut p Packet) from_json(f json.Any) { - mut obj := f.as_map() - for k, v in obj { - match k { - 'op' { p.op = Op(v.int()) } - 's' { p.sequence = v.int() } - 't' { p.event = v.str() } - 'd' { p.data = v } - else {} - } - } -} - -pub fn (p Packet) to_json() string { - mut obj := map[string]json.Any{} - obj['op'] = int(p.op) - obj['s'] = p.sequence - obj['t'] = p.event - obj['d'] = p.data - return obj.str() -} - -pub fn (p Packet) str() string { - return p.to_json() +pub: + op Op [json: op] + sequence int [json: s] + event string [json: t] + data string [json: d; raw] } diff --git a/gateway/packets/resume.v b/gateway/packets/resume.v index 8128f32..a821bda 100644 --- a/gateway/packets/resume.v +++ b/gateway/packets/resume.v @@ -1,19 +1,9 @@ module packets -import x.json2 as json - // Websocket Resume packet data pub struct Resume { pub: token string session_id string - sequence int -} - -pub fn (d Resume) to_json_any() json.Any { - mut resume := map[string]json.Any{} - resume['token'] = d.token - resume['session_id'] = d.session_id - resume['seq'] = d.sequence - return resume + sequence int [json: seq] } diff --git a/gateway/shard.v b/gateway/shard.v index 05ec1f5..6ad0c74 100644 --- a/gateway/shard.v +++ b/gateway/shard.v @@ -2,11 +2,12 @@ module gateway import time import log -import x.websocket +import json +import net.websocket import eventbus import gateway.packets -const ( +pub const ( default_gateway = 'wss://gateway.discord.gg/?v=8&encoding=json' ) @@ -124,10 +125,9 @@ fn (mut shard Shard) run_heartbeat() { } heartbeat := packets.Packet{ op: .heartbeat - data: shard.sequence + data: shard.sequence.str() } - message := heartbeat.to_json() - shard.ws.write_string(message) or { + shard.ws.write_string(json.encode(heartbeat)) or { shard.log.error('Something went when tried to write to websocket: $err') } shard.last_heartbeat = now diff --git a/gateway/websocket.v b/gateway/websocket.v index 9a35999..8c156fc 100644 --- a/gateway/websocket.v +++ b/gateway/websocket.v @@ -1,7 +1,7 @@ module gateway -import x.json2 as json -import x.websocket +import json +import net.websocket import gateway.packets // Handles open event for Websocket @@ -14,15 +14,24 @@ fn on_error(mut ws websocket.Client, error string, mut shard Shard) ? { shard.log.error('#$shard.id Gateway error: $error') } +// un 23 18:19:22 ubuntu vbot[49007]: 2021-06-23 18:19:22 [ERROR] #0 Gateway error: failed to read next message: net: socket error: 4 +// Jun 23 18:19:22 ubuntu vbot[49007]: 2021-06-23 18:19:22 [WARN ] #0 Websocket listen: net: socket error: 4 +// Jun 23 19:06:47 ubuntu vbot[49007]: 2021-06-23 19:06:47 [ERROR] #0 Gateway error: failed to read next message: net: socket error: 4 +// Jun 23 19:06:47 ubuntu vbot[49007]: 2021-06-23 19:06:47 [WARN ] #0 Websocket listen: net: socket error: 4 +// Jun 23 19:08:40 ubuntu vbot[49007]: 2021-06-23 19:08:40 [ERROR] #0 Gateway error: failed to read next message: net: socket error: 4 +// Jun 23 19:08:40 ubuntu vbot[49007]: 2021-06-23 19:08:40 [WARN ] #0 Websocket listen: net: socket error: 4 +// Jun 23 21:15:58 ubuntu vbot[49007]: 2021-06-23 21:15:58 [ERROR] #0 Gateway error: failed to read next message: net: socket error: 4 +// Jun 23 21:15:58 ubuntu vbot[49007]: 2021-06-23 21:15:58 [WARN ] #0 Websocket listen: net: socket error: 4 +// Jun 23 21:50:22 ubuntu vbot[49007]: 2021-06-23 21:50:22 [ERROR] #0 Gateway error: failed to read next message: net: socket error: 4 +// Jun 23 21:50:22 ubuntu vbot[49007]: 2021-06-23 21:50:22 [WARN ] #0 Websocket listen: net: socket error: 4 + // Handles message event for Websocket fn on_message(mut ws websocket.Client, msg &websocket.Message, mut shard Shard) ? { match msg.opcode { .text_frame { - mut obj := json.raw_decode(msg.payload.bytestr()) ? - mut packet := packets.Packet{} - packet.from_json(obj) + packet := json.decode(packets.Packet, msg.payload.bytestr()) ? shard.sequence = packet.sequence - match packets.Op(packet.op) { + match packet.op { .dispatch { shard.dispatch(&packet) } @@ -36,12 +45,10 @@ fn on_message(mut ws websocket.Client, msg &websocket.Message, mut shard Shard) shard.handle_invalid_session(packet) } .reconnect { - shard.resuming = true - shard.ws.close(int(CloseCode.normal_closure), 'Reconnect') ? + shard.handle_reconnect(packet) } else { - thing := packets.Op(packet.op) - shard.log.info('#$shard.id Unhandled opcode: $packet.op ($thing)') + shard.log.info('#$shard.id Unhandled opcode: ${int(packet.op)} ($packet.op)') } } } diff --git a/rest.v b/rest.v index 3e9a6ef..32483cf 100644 --- a/rest.v +++ b/rest.v @@ -34,7 +34,7 @@ pub fn (query GuildAuditLogQuery) query() string { // Returns an AuditLog struct for the guild. Requires the 'VIEW_AUDIT_LOG' permission. pub fn (mut client Client) guild_audit_log(guild_id string, query GuildAuditLogQuery) ?AuditLog { mut req := client.rest.req(.get, '/guilds/$guild_id/audit-logs') ? - req.url += '${query.query()}' + req.url += '$query.query()' resp := client.rest.do(req) ? if resp.status_code != 200 { @@ -44,7 +44,7 @@ pub fn (mut client Client) guild_audit_log(guild_id string, query GuildAuditLogQ return error(err_text) } - return json.decode(AuditLog, resp.text) + return json.decode(AuditLog, resp.text) or {} } // MessageSend stores all parameters you can send with channel_message_send. @@ -64,10 +64,10 @@ pub fn (ms MessageSend) to_json() json2.Any { obj['nonce'] = ms.nonce obj['tts'] = ms.tts if !ms.embed.iszero() { - obj['embed'] = ms.embed.to_json() + obj['embed'] = json.encode(ms.embed) } if !ms.reference.iszero() { - obj['message_reference'] = ms.reference.to_json() + obj['message_reference'] = json.encode(ms.reference) } return obj } diff --git a/rest/ratelimit.v b/rest/ratelimit.v index 31b3855..addc4ad 100644 --- a/rest/ratelimit.v +++ b/rest/ratelimit.v @@ -3,7 +3,6 @@ module rest import sync import time import net.http -import x.json2 as json [heap] struct RateLimiter { @@ -98,15 +97,3 @@ pub mut: retry_after f32 global bool } - -pub fn (mut tmr TooManyRequests) from_json(f json.Any) { - mut obj := f.as_map() - for k, v in obj { - match k { - 'message' { tmr.message = v.str() } - 'retry_after' { tmr.retry_after = v.f32() } - 'global' { tmr.global = v.bool() } - else {} - } - } -} diff --git a/rest/rest.v b/rest/rest.v index ee6e9c3..e2f5aa4 100644 --- a/rest/rest.v +++ b/rest/rest.v @@ -2,7 +2,7 @@ module rest import net.http import time -import x.json2 as json +import json const ( api = 'https://discord.com/api/v8' @@ -51,11 +51,9 @@ pub fn (mut rst REST) do(req http.Request) ?http.Response { } bucket.release(resp.header) if resp.status_code == 429 { - mut obj := json.raw_decode(resp.text.replace('\n', '')) or { panic(err) } - mut tmr := TooManyRequests{} - tmr.from_json(obj) - rst.rl.global = time.utc().unix_time_milli() + u64(tmr.retry_after) * 1000 - time.sleep(i64(tmr.retry_after) * 1000 * time.millisecond) + tmr := json.decode(TooManyRequests, resp.text.replace('\n', '')) or { panic(err) } + rst.rl.global = time.utc().unix_time_milli() + u64(tmr.retry_after * 1000) + time.sleep(i64(tmr.retry_after * 1000) * time.millisecond) return rst.do(req) } return resp @@ -64,7 +62,7 @@ pub fn (mut rst REST) do(req http.Request) ?http.Response { // REST API Error Message struct ApiErrorMessage { code int - errors json.Any + errors string [raw] message string } diff --git a/structs.v b/structs.v index cbb49da..c0f4e57 100644 --- a/structs.v +++ b/structs.v @@ -1,42 +1,23 @@ module discordv import time -import x.json2 as json +import json +import x.json2 import snowflake // Permission type pub type Permission = int pub struct AuditLog { -pub mut: +pub: webhooks []Webhook users []User audit_log_entries []AuditLogEntry integrations []Integration } -pub fn (mut al AuditLog) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'webhooks' { - al.webhooks = from_json_arr(v.arr()) - } - 'users' { - al.users = from_json_arr(v.arr()) - } - 'audit_log_entries' { - al.audit_log_entries = from_json_arr(v.arr()) - } - 'integrations' { - al.integrations = from_json_arr(v.arr()) - } - else {} - } - } -} - pub struct AuditLogEntry { -pub mut: +pub: target_id string changes []AuditLogChange user_id string @@ -46,59 +27,13 @@ pub mut: reason string } -pub fn (mut ale AuditLogEntry) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'target_id' { - ale.target_id = v.str() - } - 'changes' { - ale.changes = from_json_arr(v.arr()) - } - 'user_id' { - ale.user_id = v.str() - } - 'id' { - ale.id = v.str() - } - 'action_type' { - ale.action_type = AuditLogEvent(v.int()) - } - 'options' { - ale.options = from_json(v.as_map()) - } - 'reason' { - ale.reason = v.str() - } - else {} - } - } -} - pub struct AuditLogChange { -pub mut: - new_value json.Any [skip] - old_value json.Any [skip] +pub: + new_value string [raw] + old_value string [raw] key string // TODO: write module for managing audit log changes } -pub fn (mut alc AuditLogChange) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'new_value' { - alc.new_value = v - } - 'old_value' { - alc.old_value = v - } - 'key' { - alc.key = v.str() - } - else {} - } - } -} - pub enum AuditLogEvent { guild_update = 1 channel_create = 10 @@ -138,53 +73,21 @@ pub enum AuditLogEvent { } pub struct AuditEntryInfo { -pub mut: +pub: delete_member_days string members_removed string channel_id string message_id string count string id string - @type string + @type string [json: 'type'] role_name string } -pub fn (mut aei AuditEntryInfo) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'delete_member_days' { - aei.delete_member_days = v.str() - } - 'members_removed' { - aei.members_removed = v.str() - } - 'channel_id' { - aei.channel_id = v.str() - } - 'message_id' { - aei.message_id = v.str() - } - 'count' { - aei.count = v.str() - } - 'id' { - aei.id = v.str() - } - 'type' { - aei.@type = v.str() - } - 'role_name' { - aei.role_name = v.str() - } - else {} - } - } -} - pub struct Activity { -pub mut: +pub: name string - @type ActivityType + @type ActivityType [json: 'type'] url string created_at int timestamps []ActivityTimestamp @@ -199,56 +102,6 @@ pub mut: flags ActivityFlags } -pub fn (mut activity Activity) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'name' { - activity.name = v.str() - } - 'type' { - activity.@type = ActivityType(v.int()) - } - 'url' { - activity.url = v.str() - } - 'created_at' { - activity.created_at = v.int() - } - 'timestamps' { - activity.timestamps = from_json_arr(v.arr()) - } - 'application_id' { - activity.application_id = v.str() - } - 'details' { - activity.details = v.str() - } - 'state' { - activity.state = v.str() - } - 'emoji' { - activity.emoji = from_json(v.as_map()) - } - 'party' { - activity.party = from_json(v.as_map()) - } - 'assets' { - activity.assets = from_json(v.as_map()) - } - 'secrets' { - activity.secrets = from_json(v.as_map()) - } - 'instance' { - activity.instance = v.bool() - } - 'flags' { - activity.flags = ActivityFlags(v.int()) - } - else {} - } - } -} - pub enum ActivityType { game streaming @@ -258,97 +111,30 @@ pub enum ActivityType { } pub struct ActivityTimestamp { -pub mut: +pub: start int end int } -pub fn (mut at ActivityTimestamp) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'start' { - at.start = v.int() - } - 'end' { - at.end = v.int() - } - else {} - } - } -} - pub struct ActivityParty { -pub mut: +pub: id string - size [2]int -} - -pub fn (mut ap ActivityParty) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { - ap.id = v.str() - } - 'size' { - mut arr := v.arr() - ap.size[0] = arr[0].int() - ap.size[1] = arr[1].int() - } - else {} - } - } + size []int // length is 2 } pub struct ActivityAssets { -pub mut: +pub: large_image string large_text string small_image string small_text string } -pub fn (mut aa ActivityAssets) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'large_image' { - aa.large_image = v.str() - } - 'large_text' { - aa.large_text = v.str() - } - 'small_image' { - aa.small_image = v.str() - } - 'small_text' { - aa.small_text = v.str() - } - else {} - } - } -} - pub struct ActivitySecrets { -pub mut: +pub: join string spectate string - @match string -} - -pub fn (mut ass ActivitySecrets) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'join' { - ass.join = v.str() - } - 'spectate' { - ass.spectate = v.str() - } - 'match' { - ass.@match = v.str() - } - else {} - } - } + @match string [json: 'match'] } pub type ActivityFlags = int @@ -363,7 +149,7 @@ pub const ( ) pub struct Attachment { -pub mut: +pub: id string filename string size int @@ -373,46 +159,19 @@ pub mut: width int } -pub fn (mut at Attachment) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { at.id = v.str() } - 'filename' { at.filename = v.str() } - 'size' { at.size = v.int() } - 'url' { at.url = v.str() } - 'proxy_url' { at.proxy_url = v.str() } - 'height' { at.height = v.int() } - 'width' { at.width = v.int() } - else {} - } - } -} - enum PermissionOverwriteType { role user } struct PermissionOverwrite { -pub mut: +pub: id string - @type PermissionOverwriteType + @type PermissionOverwriteType [json: 'type'] allow string deny string } -pub fn (mut po PermissionOverwrite) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { po.id = v.str() } - 'type' { po.@type = PermissionOverwriteType(v.int()) } - 'allow' { po.allow = v.str() } - 'deny' { po.deny = v.str() } - else {} - } - } -} - enum ChannelType { guild_text dm @@ -424,29 +183,17 @@ enum ChannelType { } pub struct ChannelMention { -pub mut: +pub: id string guild_id string - @type ChannelType + @type ChannelType [json: 'type'] name string } -pub fn (mut cm ChannelMention) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { cm.id = v.str() } - 'guild_id' { cm.guild_id = v.str() } - 'type' { cm.@type = ChannelType(v.int()) } - 'name' { cm.name = v.str() } - else {} - } - } -} - pub struct Channel { -pub mut: +pub: id string - @type ChannelType + @type ChannelType [json: 'type'] guild_id string position int permission_overwrites PermissionOverwrite @@ -462,101 +209,49 @@ pub mut: owner_id string application_id string parent_id string - last_pin_timestamp time.Time +pub mut: + last_pin_timestamp time.Time } -pub fn (mut channel Channel) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { - channel.id = v.str() - } - 'type' { - channel.@type = ChannelType(v.int()) - } - 'guild_id' { - channel.guild_id = v.str() - } - 'position' { - channel.position = v.int() - } - 'permission_overwrites' { - channel.permission_overwrites = from_json(v.as_map()) - } - 'name' { - channel.name = v.str() - } - 'topic' { - channel.topic = v.str() - } - 'nsfw' { - channel.nsfw = v.bool() - } - 'last_message_id' { - channel.last_message_id = v.str() - } - 'bitrate' { - channel.bitrate = v.int() - } - 'user_limit' { - channel.user_limit = v.int() - } - 'rate_limit_per_user' { - channel.rate_limit_per_user = v.int() - } - 'recipients' { - channel.recipients = from_json_arr(v.arr()) - } - 'icon' { - channel.icon = v.str() - } - 'owner_id' { - channel.owner_id = v.str() - } - 'application_id' { - channel.application_id = v.str() - } - 'parent_id' { - channel.parent_id = v.str() - } - 'last_pin_timestamp' { - channel.last_pin_timestamp = time.parse_iso8601(v.str()) or { - time.unix(int(snowflake.discord_epoch / 1000)) - } - } - else {} +pub fn (mut channel Channel) from_json(data string) { + obj := json2.raw_decode(data) or { return } + f := obj.as_map() + if 'last_pin_timestamp' in f { + channel.last_pin_timestamp = time.parse_iso8601(f['last_pin_timestamp'].str()) or { + time.unix(int(snowflake.discord_epoch / 1000)) } } } pub struct Message { -pub mut: - id string - channel_id string - guild_id string - author User - member Member - content string - timestamp time.Time - edited_timestamp time.Time - tts bool - mention_everyone bool - mentions []User - mention_roles []string - mention_channels []ChannelMention - attachments []Attachment - embeds []Embed - reactions []Reaction - nonce string - pinned bool - webhook_id string - @type MessageType - activity MessageActivity - application MessageApplication - message_reference MessageReference - referenced_message &Message = voidptr(0) - stickers []Sticker - flags MessageFlag +pub: + id string + channel_id string + guild_id string + author User + member Member + content string + tts bool + mention_everyone bool + mentions []User + mention_roles []string + mention_channels []ChannelMention + attachments []Attachment + embeds []Embed + reactions []Reaction + nonce string + pinned bool + webhook_id string + @type MessageType [json: 'type'] + activity MessageActivity + application MessageApplication + message_reference MessageReference + // referenced_message &Message = voidptr(0) + stickers []Sticker + flags MessageFlag +pub mut: + timestamp time.Time + edited_timestamp time.Time } pub enum MessageType { @@ -587,23 +282,13 @@ pub enum MessageActivityType { } pub struct MessageActivity { -pub mut: - @type MessageActivityType +pub: + @type MessageActivityType [json: 'type'] party_id string } -fn (mut m MessageActivity) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'type' { m.@type = MessageActivityType(v.int()) } - 'party_id' { m.party_id = v.str() } - else {} - } - } -} - pub struct MessageApplication { -pub mut: +pub: id string cover_image string description string @@ -611,48 +296,16 @@ pub mut: name string } -fn (mut m MessageApplication) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { m.id = v.str() } - 'cover_image' { m.cover_image = v.str() } - 'description' { m.description = v.str() } - 'icon' { m.icon = v.str() } - 'name' { m.name = v.str() } - else {} - } - } -} - // Contains reference data with crossposted messages pub struct MessageReference { -pub mut: +pub: message_id string channel_id string guild_id string } -pub fn (mut m MessageReference) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'message_id' { m.message_id = v.str() } - 'channel_id' { m.channel_id = v.str() } - 'guild_id' { m.guild_id = v.str() } - else {} - } - } -} - -pub fn (m MessageReference) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['message_id'] = m.message_id - obj['channel_id'] = m.channel_id - obj['guild_id'] = m.guild_id - return obj -} - fn (m MessageReference) iszero() bool { - return m.to_json().str() == MessageReference{}.to_json().str() + return json.encode(m) == json.encode(MessageReference{}) } pub enum StickerType { @@ -662,7 +315,7 @@ pub enum StickerType { } pub struct Sticker { -pub mut: +pub: id string pack_id string name string @@ -673,22 +326,6 @@ pub mut: format_type StickerType } -pub fn (mut st Sticker) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { st.id = v.str() } - 'pack_id' { st.pack_id = v.str() } - 'name' { st.name = v.str() } - 'description' { st.description = v.str() } - 'tags' { st.tags = v.str() } - 'asset' { st.asset = v.str() } - 'preview_asset' { st.preview_asset = v.str() } - 'format_type' { st.format_type = StickerType(v.int()) } - else {} - } - } -} - pub type MessageFlag = byte pub const ( @@ -699,102 +336,31 @@ pub const ( urgent = MessageFlag(1 << 4) ) -pub fn (mut m Message) from_json(f map[string]json.Any) { +pub fn (mut m Message) from_json(data string) { + obj := json2.raw_decode(data) or { return } + f := obj.as_map() for k, v in f { match k { - 'id' { - m.id = v.str() - } - 'channel_id' { - m.channel_id = v.str() - } - 'guild_id' { - m.guild_id = v.str() - } - 'author' { - m.author = from_json(v.as_map()) - } - 'member' { - m.member = from_json(v.as_map()) - } - 'content' { - m.content = v.str() - } 'timestamp' { - m.timestamp = time.parse_iso8601(v.str()) or { time.unix(0) } + m.timestamp = time.parse_iso8601(v.str()) or { + time.unix(int(snowflake.discord_epoch / 1000)) + } } 'edited_timestamp' { - m.edited_timestamp = time.parse_iso8601(v.str()) or { time.unix(0) } - } - 'tts' { - m.tts = v.bool() - } - 'mention_everyone' { - m.mention_everyone = v.bool() - } - 'mentions' { - m.mentions = from_json_arr(v.arr()) - } - 'mention_roles' { - mut obja := v.arr() - for va in obja { - m.mention_roles << va.str() + m.edited_timestamp = time.parse_iso8601(v.str()) or { + time.unix(int(snowflake.discord_epoch / 1000)) } } - 'mention_channels' { - m.mention_channels = from_json_arr(v.arr()) - } - 'attachments' { - m.attachments = from_json_arr(v.arr()) - } - 'embeds' { - m.embeds = from_json_arr(v.arr()) - } - 'reaction' { - m.reactions = from_json_arr(v.arr()) - } - 'nonce' { - m.nonce = v.str() - } - 'pinned' { - m.pinned = v.bool() - } - 'webhook_id' { - m.webhook_id = v.str() - } - 'type' { - m.@type = MessageType(v.int()) - } - 'activity' { - m.activity = from_json(v.as_map()) - } - 'application' { - m.application = from_json(v.as_map()) - } - 'message_reference' { - m.message_reference = from_json(v.as_map()) - } - 'referenced_message' { - mut ref := from_json(v.as_map()) - m.referenced_message = &ref - } - 'stickers' { - m.stickers = from_json_arr(v.arr()) - } - 'flags' { - m.flags = MessageFlag(byte(v.int())) - } else {} } } } pub struct Embed { -pub mut: +pub: title string description string url string - timestamp time.Time color int footer EmbedFooter image EmbedImage @@ -803,387 +369,117 @@ pub mut: provider EmbedProvider author EmbedAuthor fields []EmbedField +pub mut: + timestamp time.Time } -pub fn (mut embed Embed) from_json(f map[string]json.Any) { +pub fn (embed Embed) iszero() bool { + return json.encode(embed) == json.encode(Embed{}) +} + +pub fn (mut embed Embed) from_json(data string) { + obj := json2.raw_decode(data) or { return } + f := obj.as_map() for k, v in f { match k { - 'title' { - embed.title = v.str() - } - 'description' { - embed.description = v.str() - } - 'url' { - embed.url = v.str() - } 'timestamp' { embed.timestamp = time.parse_iso8601(v.str()) or { time.unix(int(snowflake.discord_epoch / 1000)) } } - 'color' { - embed.color = v.int() - } - 'footer' { - embed.footer = from_json(v.as_map()) - } - 'image' { - embed.image = from_json(v.as_map()) - } - 'thumbnail' { - embed.thumbnail = from_json(v.as_map()) - } - 'video' { - embed.video = from_json(v.as_map()) - } - 'provider' { - embed.provider = from_json(v.as_map()) - } - 'author' { - embed.author = from_json(v.as_map()) - } - 'fields' { - embed.image = from_json(v.as_map()) - } else {} } } } -pub fn (mut embeds []Embed) from_json(f json.Any) { - mut obj := f.arr() - for embed in obj { - mut e := Embed{} - e.from_json(embed.as_map()) - embeds << e - } -} - -pub fn (embed Embed) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['title'] = embed.title - obj['description'] = embed.description - obj['color'] = embed.color - obj['footer'] = embed.footer.to_json() - obj['image'] = embed.image.to_json() - obj['thumbnail'] = embed.thumbnail.to_json() - obj['video'] = embed.video.to_json() - obj['provider'] = embed.provider.to_json() - obj['author'] = embed.author.to_json() - obj['fields'] = embed.fields.to_json() - return obj -} - -pub fn (embed []Embed) to_json() json.Any { - mut obj := []json.Any{} - for e in embed { - obj << e.to_json() - } - return obj -} - -pub fn (embed Embed) iszero() bool { - return embed.to_json().str() == Embed{}.to_json().str() -} - pub struct EmbedFooter { -pub mut: +pub: text string icon_url string proxy_icon_url string } -pub fn (mut ef EmbedFooter) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'text' { ef.text = v.str() } - 'icon_url' { ef.icon_url = v.str() } - 'proxy_icon_url' { ef.proxy_icon_url = v.str() } - else {} - } - } -} - -pub fn (ef EmbedFooter) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['text'] = ef.text - obj['icon_url'] = ef.icon_url - obj['proxy_icon_url'] = ef.proxy_icon_url - return obj -} - -pub fn (ef EmbedFooter) str() string { - return ef.to_json().str() -} - pub struct EmbedImage { -pub mut: +pub: url string proxy_url string height int width int } -pub fn (mut ei EmbedImage) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'url' { ei.url = v.str() } - 'proxy_url' { ei.proxy_url = v.str() } - 'height' { ei.height = v.int() } - 'width' { ei.width = v.int() } - else {} - } - } -} - -pub fn (ei EmbedImage) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['url'] = ei.url - obj['proxy_url'] = ei.proxy_url - obj['height'] = ei.height - obj['width'] = ei.width - return obj -} - -pub fn (ei EmbedImage) str() string { - return ei.to_json().str() -} - pub struct EmbedThumbnail { -pub mut: +pub: url string proxy_url string height int width int } -pub fn (mut et EmbedThumbnail) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'url' { et.url = v.str() } - 'proxy_url' { et.proxy_url = v.str() } - 'height' { et.height = v.int() } - 'width' { et.width = v.int() } - else {} - } - } -} - -pub fn (et EmbedThumbnail) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['url'] = et.url - obj['proxy_url'] = et.proxy_url - obj['height'] = et.height - obj['width'] = et.width - return obj -} - -pub fn (et EmbedThumbnail) str() string { - return et.to_json().str() -} - pub struct EmbedVideo { -pub mut: +pub: url string height int width int } -pub fn (mut ev EmbedVideo) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'url' { ev.url = v.str() } - 'height' { ev.height = v.int() } - 'width' { ev.width = v.int() } - else {} - } - } -} - -pub fn (ev EmbedVideo) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['url'] = ev.url - obj['height'] = ev.height - obj['width'] = ev.width - return obj -} - -pub fn (ev EmbedVideo) str() string { - return ev.to_json().str() -} - pub struct EmbedProvider { -pub mut: +pub: name string url string } -pub fn (mut ep EmbedProvider) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'name' { ep.name = v.str() } - 'url' { ep.url = v.str() } - else {} - } - } -} - -pub fn (ep EmbedProvider) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['name'] = ep.name - obj['url'] = ep.url - return obj -} - -pub fn (ep EmbedProvider) str() string { - return ep.to_json().str() -} - pub struct EmbedAuthor { -pub mut: +pub: name string url string icon_url string proxy_icon_url string } -pub fn (mut ea EmbedAuthor) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'name' { ea.name = v.str() } - 'url' { ea.url = v.str() } - 'icon_url' { ea.icon_url = v.str() } - 'proxy_icon_url' { ea.proxy_icon_url = v.str() } - else {} - } - } -} - -pub fn (ea EmbedAuthor) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['name'] = ea.name - obj['url'] = ea.url - obj['icon_url'] = ea.icon_url - obj['proxy_icon_url'] = ea.proxy_icon_url - return obj -} - -pub fn (ea EmbedAuthor) str() string { - return ea.to_json().str() -} - pub struct EmbedField { -pub mut: +pub: name string value string inline bool } -pub fn (mut ef EmbedField) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'name' { ef.name = v.str() } - 'value' { ef.value = v.str() } - 'inline' { ef.inline = v.bool() } - else {} - } - } -} - -pub fn (ef EmbedField) to_json() json.Any { - mut obj := map[string]json.Any{} - obj['name'] = ef.name - obj['value'] = ef.value - obj['inline'] = ef.inline - return obj -} - -pub fn (ef []EmbedField) to_json() json.Any { - mut obj := []json.Any{} - for field in ef { - obj << field.to_json() - } - return obj -} - -pub fn (ef EmbedField) str() string { - return ef.to_json().str() -} - pub struct Emoji { -pub mut: +pub: id string name string roles []Role } -pub fn (mut emoji Emoji) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { - emoji.id = v.str() - } - 'name' { - emoji.name = v.str() - } - 'roles' { - emoji.roles = from_json_arr(v.arr()) - } - else {} - } - } -} - pub struct File { -pub mut: +pub: filename string data []byte } pub struct UnavailableGuild { -pub mut: +pub: id string unavailable bool } -fn (mut g UnavailableGuild) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { g.id = v.str() } - 'unavailable' { g.unavailable = v.bool() } - else {} - } - } -} - pub struct Member { +pub: + user User + nick string + roles []string + deaf bool + mute bool + pending bool pub mut: - user User - nick string - roles []string joined_at time.Time premium_since time.Time - deaf bool - mute bool - pending bool } -pub fn (mut member Member) from_json(f map[string]json.Any) { +pub fn (mut member Member) from_json(data string) { + obj := json2.raw_decode(data) or { return } + f := obj.as_map() for k, v in f { - match k { - 'user' { - member.user = from_json(v.as_map()) - } - 'nick' { - member.nick = v.str() - } - 'roles' { - mut roles := v.arr() - for role in roles { - member.roles << role.str() - } - } + match k { 'joined_at' { member.joined_at = time.parse_iso8601(v.str()) or { time.unix(int(snowflake.discord_epoch / 1000)) @@ -1194,84 +490,30 @@ pub fn (mut member Member) from_json(f map[string]json.Any) { time.unix(int(snowflake.discord_epoch / 1000)) } } - 'deaf' { - member.deaf = v.bool() - } - 'mute' { - member.mute = v.bool() - } - 'pending' { - member.pending = v.bool() - } else {} } } } pub struct Reaction { -pub mut: +pub: count int me bool emoji Emoji } -pub fn (mut r Reaction) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'count' { - r.count = v.int() - } - 'me' { - r.me = v.bool() - } - 'emoji' { - r.emoji = from_json(v.as_map()) - } - else {} - } - } -} - pub struct Ready { -pub mut: +pub: v int user User private_channels []Channel guilds []UnavailableGuild session_id string - shard [2]int -} - -pub fn (mut r Ready) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'v' { - r.v = v.int() - } - 'user' { - r.user = from_json(v.as_map()) - } - 'private_channels' { - r.private_channels = from_json_arr(v.arr()) - } - 'guilds' { - r.guilds = from_json_arr(v.arr()) - } - 'session_id' { - r.session_id = v.str() - } - 'shard' { - mut shards := v.arr() - r.shard[0] = shards[0].int() - r.shard[1] = shards[1].int() - } - else {} - } - } + shard []int // length is 2 } pub struct PresenceUpdate { -pub mut: +pub: user User guild_id string status PresenceStatus @@ -1279,29 +521,6 @@ pub mut: client_status PresenceClientStatus } -pub fn (mut pu PresenceUpdate) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'user' { - pu.user = from_json(v.as_map()) - } - 'guild_id' { - pu.guild_id = v.str() - } - 'status' { - pu.status = PresenceStatus(v.str()) - } - 'activities' { - pu.activities = from_json_arr(v.arr()) - } - 'client_status' { - pu.client_status = from_json(v.as_map()) - } - else {} - } - } -} - pub type PresenceStatus = string pub const ( @@ -1312,31 +531,14 @@ pub const ( ) pub struct PresenceClientStatus { -pub mut: +pub: desktop PresenceStatus = discordv.offline mobile PresenceStatus = discordv.offline web PresenceStatus = discordv.offline } -pub fn (mut pcs PresenceClientStatus) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'desktop' { - pcs.desktop = PresenceStatus(v.str()) - } - 'mobile' { - pcs.mobile = PresenceStatus(v.str()) - } - 'web' { - pcs.web = PresenceStatus(v.str()) - } - else {} - } - } -} - pub struct Guild { -pub mut: +pub: id string name string icon string @@ -1362,7 +564,6 @@ pub mut: system_channel_id string system_channel_flags string rules_channel_id string - joined_at time.Time large bool unavailable bool member_count int @@ -1382,151 +583,20 @@ pub mut: max_video_channel_users int approximate_member_count int approximate_presence_count int +pub mut: + joined_at time.Time } -pub fn (mut guild Guild) from_json(f map[string]json.Any) { +pub fn (mut guild Guild) from_json(data string) { + obj := json2.raw_decode(data) or { return } + f := obj.as_map() for k, v in f { match k { - 'id' { - guild.id = v.str() - } - 'name' { - guild.name = v.str() - } - 'icon' { - guild.icon = v.str() - } - 'icon_hash' { - guild.icon_hash = v.str() - } - 'splash' { - guild.splash = v.str() - } - 'discovery_splash' { - guild.discovery_splash = v.str() - } - 'owner' { - guild.owner = v.bool() - } - 'owner_id' { - guild.owner_id = v.str() - } - 'permissions' { - guild.permissions = v.str() - } - 'region' { - guild.region = v.str() - } - 'afk_channel_id' { - guild.afk_channel_id = v.str() - } - 'afk_timeout' { - guild.afk_timeout = v.int() - } - 'widget_enabled' { - guild.widget_enabled = v.bool() - } - 'widget_channel_id' { - guild.widget_channel_id = v.str() - } - 'verification_level' { - guild.verification_level = GuildVerificationLevel(v.int()) - } - 'default_message_notifications' { - guild.default_message_notifications = GuildMessageNotificationsLevel(v.int()) - } - 'explicit_content_filter' { - guild.explicit_content_filter = GuildExplicitContentFilterLevel(v.int()) - } - 'roles' { - guild.roles = from_json_arr(v.arr()) - } - 'emojis' { - guild.emojis = from_json_arr(v.arr()) - } - 'features' { - mut roles := v.arr() - for role in roles { - guild.features << GuildFeature(role.str()) - } - } - 'mfa_level' { - guild.mfa_level = MFALevel(v.int()) - } - 'application_id' { - guild.application_id = v.str() - } - 'system_channel_id' { - guild.system_channel_id = v.str() - } - 'system_channel_flags' { - guild.system_channel_flags = v.str() - } - 'rules_channel_id' { - guild.rules_channel_id = v.str() - } 'joined_at' { guild.joined_at = time.parse_iso8601(v.str()) or { time.unix(int(snowflake.discord_epoch / 1000)) } } - 'large' { - guild.large = v.bool() - } - 'unavailable' { - guild.unavailable = v.bool() - } - 'member_count' { - guild.member_count = v.int() - } - 'voice_states' { - guild.voice_states = from_json_arr(v.arr()) - } - 'members' { - guild.members = from_json_arr(v.arr()) - } - 'channels' { - guild.channels = from_json_arr(v.arr()) - } - 'presences' { - guild.presences = from_json_arr(v.arr()) - } - 'max_presences' { - guild.max_presences = v.int() - } - 'max_members' { - guild.max_members = v.int() - } - 'vanity_url_code' { - guild.vanity_url_code = v.str() - } - 'description' { - guild.description = v.str() - } - 'banner' { - guild.banner = v.str() - } - 'premium_tier' { - guild.premium_tier = GuildPremiumTier(v.int()) - } - 'premium_subscription_count' { - guild.premium_subscription_count = v.int() - } - 'preferred_locale' { - guild.preferred_locale = v.str() - } - 'public_updates_channel_id' { - guild.public_updates_channel_id = v.str() - } - 'max_video_channel_users' { - guild.max_video_channel_users = v.int() - } - 'approximate_member_count' { - guild.approximate_member_count = v.int() - } - 'approximate_presence_count' { - guild.approximate_presence_count = v.int() - } else {} } } @@ -1582,7 +652,7 @@ pub const ( ) pub struct VoiceState { -pub mut: +pub: guild_id string channel_id string user_id string @@ -1597,50 +667,6 @@ pub mut: suppress bool } -pub fn (mut vs VoiceState) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'guild_id' { - vs.guild_id = v.str() - } - 'channel_id' { - vs.channel_id = v.str() - } - 'user_id' { - vs.user_id = v.str() - } - 'member' { - vs.member = from_json(v.as_map()) - } - 'session_id' { - vs.session_id = v.str() - } - 'deaf' { - vs.deaf = v.bool() - } - 'mute' { - vs.mute = v.bool() - } - 'self_deaf' { - vs.self_deaf = v.bool() - } - 'self_mute' { - vs.self_mute = v.bool() - } - 'self_stream' { - vs.self_stream = v.bool() - } - 'self_video' { - vs.self_video = v.bool() - } - 'suppress' { - vs.suppress = v.bool() - } - else {} - } - } -} - pub enum GuildPremiumTier { @none tier_1 @@ -1649,7 +675,7 @@ pub enum GuildPremiumTier { } pub struct VoiceRegion { -pub mut: +pub: id string name string vip bool @@ -1658,34 +684,8 @@ pub mut: custom bool } -pub fn (mut vr VoiceRegion) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { - vr.id = v.str() - } - 'name' { - vr.name = v.str() - } - 'vip' { - vr.vip = v.bool() - } - 'optimal' { - vr.optimal = v.bool() - } - 'deprecated' { - vr.deprecated = v.bool() - } - 'custom' { - vr.custom = v.bool() - } - else {} - } - } -} - pub struct Role { -pub mut: +pub: id string name string color int @@ -1696,28 +696,12 @@ pub mut: mentionable bool } -pub fn (mut role Role) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { role.id = v.str() } - 'name' { role.name = v.str() } - 'color' { role.color = v.int() } - 'hoist' { role.hoist = v.bool() } - 'position' { role.position = v.int() } - 'permission' { role.permission = v.str() } - 'managed' { role.managed = v.bool() } - 'mentionable' { role.mentionable = v.bool() } - else {} - } - } -} - pub struct User { -pub mut: +pub: id string username string discriminator string - avatar Avatar + avatar string bot bool system bool mfa_enabled bool @@ -1729,18 +713,8 @@ pub mut: public_flags UserFlag } -pub struct Avatar { - user_id string -pub: - hash string -} - -pub fn (avatar Avatar) url() string { - return 'https://cdn.discordapp.com/avatars/$avatar.user_id/{$avatar.hash}.png' -} - -pub fn (avatar Avatar) str() string { - return avatar.hash +pub fn (user User) avatar_url() string { + return 'https://cdn.discordapp.com/avatars/$user.id/{$user.avatar}.png' } pub type UserFlag = int @@ -1768,33 +742,6 @@ pub enum PremiumType { nitro } -pub fn (mut user User) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { user.id = v.str() } - 'username' { user.username = v.str() } - 'discriminator' { user.discriminator = v.str() } - 'bot' { user.bot = v.bool() } - 'system' { user.system = v.bool() } - 'mfa_enabled' { user.mfa_enabled = v.bool() } - 'locale' { user.locale = v.str() } - 'verified' { user.verified = v.bool() } - 'email' { user.email = v.str() } - 'flags' { user.flags = UserFlag(v.int()) } - 'premium_type' { user.premium_type = PremiumType(v.int()) } - 'public_flags' { user.public_flags = UserFlag(v.int()) } - else {} - } - } - if 'avatar' in f { - hash := f['avatar'].str() - user.avatar = Avatar{ - user_id: user.id - hash: hash - } - } -} - pub enum IntegrationExpireBehavior { remove_role kick @@ -1809,23 +756,13 @@ pub const ( ) pub struct IntegrationAccount { -pub mut: +pub: id string name string } -pub fn (mut iacc IntegrationAccount) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { iacc.id = v.str() } - 'name' { iacc.name = v.str() } - else {} - } - } -} - pub struct IntegrationApplication { -pub mut: +pub: id string name string icon string @@ -1834,37 +771,11 @@ pub mut: bot User } -pub fn (mut iapp IntegrationApplication) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { - iapp.id = v.str() - } - 'name' { - iapp.name = v.str() - } - 'icon' { - iapp.icon = v.str() - } - 'description' { - iapp.description = v.str() - } - 'summary' { - iapp.summary = v.str() - } - 'bot' { - iapp.bot = from_json(v.as_map()) - } - else {} - } - } -} - pub struct Integration { -pub mut: +pub: id string name string - @type IntegrationType + @type IntegrationType [json: 'type'] enabled bool syncing bool role_id string @@ -1873,71 +784,32 @@ pub mut: expire_grace_period int user User account IntegrationAccount - synced_at time.Time subscriber_count int revoked bool application IntegrationApplication +pub mut: + synced_at time.Time } -pub fn (mut integration Integration) from_json(f map[string]json.Any) { +pub fn (mut integration Integration) from_json(data string) { + obj := json2.raw_decode(data) or { return } + f := obj.as_map() for k, v in f { match k { - 'id' { - integration.id = v.str() - } - 'name' { - integration.name = v.str() - } - 'type' { - integration.@type = IntegrationType(v.str()) - } - 'enabled' { - integration.enabled = v.bool() - } - 'syncing' { - integration.syncing = v.bool() - } - 'role_id' { - integration.role_id = v.str() - } - 'enable_emoticons' { - integration.enable_emoticons = v.bool() - } - 'expire_behavior' { - integration.expire_behavior = IntegrationExpireBehavior(v.int()) - } - 'expire_grace_period' { - integration.expire_grace_period = v.int() - } - 'user' { - integration.user = from_json(v.as_map()) - } - 'account' { - integration.account = from_json(v.as_map()) - } 'synced_at' { integration.synced_at = time.parse_iso8601(v.str()) or { time.unix(int(snowflake.discord_epoch / 1000)) } } - 'subscriber_count' { - integration.subscriber_count = v.int() - } - 'revoked' { - integration.revoked = v.bool() - } - 'application' { - integration.application = from_json(v.as_map()) - } else {} } } } pub struct Interaction { -pub mut: +pub: id string - @type InteractionType [json: "type"] + @type InteractionType [json: 'type'] data ApplicationCommandInteractionData guild_id string channel_id string @@ -1946,86 +818,29 @@ pub mut: version int } -pub fn (mut inter Interaction) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { inter.id = v.str() } - 'type' { inter.@type = InteractionType(v.int()) } - 'data' { inter.data = from_json(v.as_map()) } - 'guild_id' { inter.guild_id = v.str() } - 'channel_id' { inter.channel_id = v.str() } - 'member' { inter.member = from_json(v.as_map()) } - 'token' { inter.token = v.str() } - 'version' { inter.version = v.int() } - else {} - } - } -} - pub enum InteractionType { ping = 1 application_command = 2 } pub struct ApplicationCommandInteractionData { -pub mut: +pub: id string name string - options []&ApplicationCommandInteractionDataOption -} - -pub fn (mut acid ApplicationCommandInteractionData) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { - acid.id = v.str() - } - 'name' { - acid.name = v.str() - } - 'options' { - mut arr := from_json_arr(v.arr()) - for mut item in arr { - acid.options << item - } - } - else {} - } - } + options []ApplicationCommandInteractionDataOption } -[heap] pub struct ApplicationCommandInteractionDataOption { -pub mut: - name string - value string - options []&ApplicationCommandInteractionDataOption -} - -pub fn (mut acido ApplicationCommandInteractionDataOption) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'name' { - acido.name = v.str() - } - 'value' { - acido.value = v.str() - } - 'options' { - mut arr := from_json_arr(v.arr()) - for item in arr { - acido.options << &item - } - } - else {} - } - } +pub: + name string + value string + // options []&ApplicationCommandInteractionDataOption } pub struct Webhook { pub mut: id string - @type WebhookType [json: "type"] + @type WebhookType [json: 'type'] guild_id string channel_id string user User @@ -2035,40 +850,7 @@ pub mut: application_id string } -pub fn (mut webhook Webhook) from_json(f map[string]json.Any) { - for k, v in f { - match k { - 'id' { webhook.id = v.str() } - 'type' { webhook.@type = WebhookType(v.int()) } - 'guild_id' { webhook.guild_id = v.str() } - 'channel_id' { webhook.channel_id = v.str() } - 'user' { webhook.user = from_json(v.as_map()) } - 'name' { webhook.name = v.str() } - 'avatar' { webhook.avatar = v.str() } - 'token' { webhook.token = v.str() } - 'application_id' { webhook.application_id = v.str() } - else {} - } - } -} - pub enum WebhookType { incoming = 1 channel_follower } - -fn from_json(f map[string]json.Any) T { - mut obj := T{} - obj.from_json(f) - return obj -} - -fn from_json_arr(f []json.Any) []T { - mut arr := []T{} - for fs in f { - mut item := T{} - item.from_json(fs.as_map()) - arr << item - } - return arr -}