1 #include "serialization.h"
2 #include "connection.h"
3 #include "discord_rpc.h"
4 
5 template <typename T>
NumberToString(char * dest,T number)6 void NumberToString(char* dest, T number)
7 {
8     if (!number) {
9         *dest++ = '0';
10         *dest++ = 0;
11         return;
12     }
13     if (number < 0) {
14         *dest++ = '-';
15         number = -number;
16     }
17     char temp[32];
18     int place = 0;
19     while (number) {
20         auto digit = number % 10;
21         number = number / 10;
22         temp[place++] = '0' + (char)digit;
23     }
24     for (--place; place >= 0; --place) {
25         *dest++ = temp[place];
26     }
27     *dest = 0;
28 }
29 
30 // it's ever so slightly faster to not have to strlen the key
31 template <typename T>
WriteKey(JsonWriter & w,T & k)32 void WriteKey(JsonWriter& w, T& k)
33 {
34     w.Key(k, sizeof(T) - 1);
35 }
36 
37 struct WriteObject {
38     JsonWriter& writer;
WriteObjectWriteObject39     WriteObject(JsonWriter& w)
40       : writer(w)
41     {
42         writer.StartObject();
43     }
44     template <typename T>
WriteObjectWriteObject45     WriteObject(JsonWriter& w, T& name)
46       : writer(w)
47     {
48         WriteKey(writer, name);
49         writer.StartObject();
50     }
~WriteObjectWriteObject51     ~WriteObject() { writer.EndObject(); }
52 };
53 
54 struct WriteArray {
55     JsonWriter& writer;
56     template <typename T>
WriteArrayWriteArray57     WriteArray(JsonWriter& w, T& name)
58       : writer(w)
59     {
60         WriteKey(writer, name);
61         writer.StartArray();
62     }
~WriteArrayWriteArray63     ~WriteArray() { writer.EndArray(); }
64 };
65 
66 template <typename T>
WriteOptionalString(JsonWriter & w,T & k,const char * value)67 void WriteOptionalString(JsonWriter& w, T& k, const char* value)
68 {
69     if (value && value[0]) {
70         w.Key(k, sizeof(T) - 1);
71         w.String(value);
72     }
73 }
74 
JsonWriteNonce(JsonWriter & writer,int nonce)75 static void JsonWriteNonce(JsonWriter& writer, int nonce)
76 {
77     WriteKey(writer, "nonce");
78     char nonceBuffer[32];
79     NumberToString(nonceBuffer, nonce);
80     writer.String(nonceBuffer);
81 }
82 
JsonWriteRichPresenceObj(char * dest,size_t maxLen,int nonce,int pid,const DiscordRichPresence * presence)83 size_t JsonWriteRichPresenceObj(char* dest,
84                                 size_t maxLen,
85                                 int nonce,
86                                 int pid,
87                                 const DiscordRichPresence* presence)
88 {
89     JsonWriter writer(dest, maxLen);
90 
91     {
92         WriteObject top(writer);
93 
94         JsonWriteNonce(writer, nonce);
95 
96         WriteKey(writer, "cmd");
97         writer.String("SET_ACTIVITY");
98 
99         {
100             WriteObject args(writer, "args");
101 
102             WriteKey(writer, "pid");
103             writer.Int(pid);
104 
105             if (presence != nullptr) {
106                 WriteObject activity(writer, "activity");
107 
108                 WriteOptionalString(writer, "state", presence->state);
109                 WriteOptionalString(writer, "details", presence->details);
110 
111                 if (presence->startTimestamp || presence->endTimestamp) {
112                     WriteObject timestamps(writer, "timestamps");
113 
114                     if (presence->startTimestamp) {
115                         WriteKey(writer, "start");
116                         writer.Int64(presence->startTimestamp);
117                     }
118 
119                     if (presence->endTimestamp) {
120                         WriteKey(writer, "end");
121                         writer.Int64(presence->endTimestamp);
122                     }
123                 }
124 
125                 if ((presence->largeImageKey && presence->largeImageKey[0]) ||
126                     (presence->largeImageText && presence->largeImageText[0]) ||
127                     (presence->smallImageKey && presence->smallImageKey[0]) ||
128                     (presence->smallImageText && presence->smallImageText[0])) {
129                     WriteObject assets(writer, "assets");
130                     WriteOptionalString(writer, "large_image", presence->largeImageKey);
131                     WriteOptionalString(writer, "large_text", presence->largeImageText);
132                     WriteOptionalString(writer, "small_image", presence->smallImageKey);
133                     WriteOptionalString(writer, "small_text", presence->smallImageText);
134                 }
135 
136                 if ((presence->partyId && presence->partyId[0]) || presence->partySize ||
137                     presence->partyMax) {
138                     WriteObject party(writer, "party");
139                     WriteOptionalString(writer, "id", presence->partyId);
140                     if (presence->partySize && presence->partyMax) {
141                         WriteArray size(writer, "size");
142                         writer.Int(presence->partySize);
143                         writer.Int(presence->partyMax);
144                     }
145                 }
146 
147                 if ((presence->matchSecret && presence->matchSecret[0]) ||
148                     (presence->joinSecret && presence->joinSecret[0]) ||
149                     (presence->spectateSecret && presence->spectateSecret[0])) {
150                     WriteObject secrets(writer, "secrets");
151                     WriteOptionalString(writer, "match", presence->matchSecret);
152                     WriteOptionalString(writer, "join", presence->joinSecret);
153                     WriteOptionalString(writer, "spectate", presence->spectateSecret);
154                 }
155 
156                 writer.Key("instance");
157                 writer.Bool(presence->instance != 0);
158             }
159         }
160     }
161 
162     return writer.Size();
163 }
164 
JsonWriteHandshakeObj(char * dest,size_t maxLen,int version,const char * applicationId)165 size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId)
166 {
167     JsonWriter writer(dest, maxLen);
168 
169     {
170         WriteObject obj(writer);
171         WriteKey(writer, "v");
172         writer.Int(version);
173         WriteKey(writer, "client_id");
174         writer.String(applicationId);
175     }
176 
177     return writer.Size();
178 }
179 
JsonWriteSubscribeCommand(char * dest,size_t maxLen,int nonce,const char * evtName)180 size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName)
181 {
182     JsonWriter writer(dest, maxLen);
183 
184     {
185         WriteObject obj(writer);
186 
187         JsonWriteNonce(writer, nonce);
188 
189         WriteKey(writer, "cmd");
190         writer.String("SUBSCRIBE");
191 
192         WriteKey(writer, "evt");
193         writer.String(evtName);
194     }
195 
196     return writer.Size();
197 }
198 
JsonWriteUnsubscribeCommand(char * dest,size_t maxLen,int nonce,const char * evtName)199 size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName)
200 {
201     JsonWriter writer(dest, maxLen);
202 
203     {
204         WriteObject obj(writer);
205 
206         JsonWriteNonce(writer, nonce);
207 
208         WriteKey(writer, "cmd");
209         writer.String("UNSUBSCRIBE");
210 
211         WriteKey(writer, "evt");
212         writer.String(evtName);
213     }
214 
215     return writer.Size();
216 }
217 
JsonWriteJoinReply(char * dest,size_t maxLen,const char * userId,int reply,int nonce)218 size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce)
219 {
220     JsonWriter writer(dest, maxLen);
221 
222     {
223         WriteObject obj(writer);
224 
225         WriteKey(writer, "cmd");
226         if (reply == DISCORD_REPLY_YES) {
227             writer.String("SEND_ACTIVITY_JOIN_INVITE");
228         }
229         else {
230             writer.String("CLOSE_ACTIVITY_JOIN_REQUEST");
231         }
232 
233         WriteKey(writer, "args");
234         {
235             WriteObject args(writer);
236 
237             WriteKey(writer, "user_id");
238             writer.String(userId);
239         }
240 
241         JsonWriteNonce(writer, nonce);
242     }
243 
244     return writer.Size();
245 }
246