1 module dscord.state;
2 
3 import std.functional,
4        std.stdio,
5        std.experimental.logger;
6 
7 import dscord.client,
8        dscord.api.client,
9        dscord.gateway.client,
10        dscord.gateway.events,
11        dscord.gateway.packets,
12        dscord.types.all,
13        dscord.util.emitter;
14 
15 /**
16   The State class is used to track and maintain client state.
17 */
18 class State : Emitter {
19   // Client
20   Client         client;
21   APIClient      api;
22   GatewayClient  gw;
23 
24   // Storage
25   User        me;
26   GuildMap    guilds;
27   ChannelMap  channels;
28   UserMap     users;
29 
30   private {
31     Logger  log;
32     ulong  onReadyGuildCount;
33   }
34 
35   this(Client client) {
36     this.log = client.log;
37 
38     this.client = client;
39     this.api = client.api;
40     this.gw = client.gw;
41 
42     this.guilds = new GuildMap;
43     this.channels = new ChannelMap;
44     this.users = new UserMap;
45 
46     this.bindEvents();
47   }
48 
49   void bindEvents() {
50     this.client.events.listen!Ready(&this.onReady);
51 
52     // Guilds
53     this.client.events.listen!GuildCreate(&this.onGuildCreate);
54     this.client.events.listen!GuildUpdate(&this.onGuildUpdate);
55     this.client.events.listen!GuildDelete(&this.onGuildDelete);
56 
57     // Channels
58     this.client.events.listen!ChannelCreate(&this.onChannelCreate);
59     this.client.events.listen!ChannelUpdate(&this.onChannelUpdate);
60     this.client.events.listen!ChannelDelete(&this.onChannelDelete);
61 
62     // Voice State
63     this.client.events.listen!VoiceStateUpdate(&this.onVoiceStateUpdate);
64   }
65 
66   void onReady(Ready r) {
67     this.me = r.me;
68     this.onReadyGuildCount = r.guilds.length;
69   }
70 
71   void onGuildCreate(GuildCreate c) {
72     this.guilds[c.guild.id] = c.guild;
73 
74     // Add channels
75     c.guild.channels.each((c) {
76       this.channels[c.id] = c;
77     });
78   }
79 
80   void onGuildUpdate(GuildUpdate c) {
81     this.log.warning("Hit onGuildUpdate leaving state stale");
82     // TODO: handle state changes in here
83     // this.guilds[c.guild.id].load(c.payload);
84   }
85 
86   void onGuildDelete(GuildDelete c) {
87     if (!this.guilds.has(c.guildID)) return;
88 
89     destroy(this.guilds[c.guildID]);
90     this.guilds.remove(c.guildID);
91   }
92 
93   void onChannelCreate(ChannelCreate c) {
94     this.channels[c.channel.id] = c.channel;
95   }
96 
97   void onChannelUpdate(ChannelUpdate c) {
98     this.channels[c.channel.id] = c.channel;
99   }
100 
101   void onChannelDelete(ChannelDelete c) {
102     if (this.channels.has(c.channel.id)) {
103       destroy(this.channels[c.channel.id]);
104       this.channels.remove(c.channel.id);
105     }
106   }
107 
108   void onVoiceStateUpdate(VoiceStateUpdate u) {
109     auto guild = this.guilds.get(u.state.guildID);
110 
111     if (!u.state.channelID) {
112       guild.voiceStates.remove(u.state.sessionID);
113     } else {
114       guild.voiceStates[u.state.sessionID] = u.state;
115     }
116   }
117 }