public void TestOptionalSerialization() { // ulong Assert.AreEqual(@"{""Entry"":0}", DiscordJson.SerializeObject(new TestFixture1 { Entry = new Optional <ulong?>(0UL) })); Assert.AreEqual(@"{}", DiscordJson.SerializeObject(new TestFixture1 { Entry = new Optional <ulong?>() })); // bool? Assert.AreEqual(@"{""Entry"":true}", DiscordJson.SerializeObject(new TestFixture2 { Entry = new Optional <bool?>(true) })); Assert.AreEqual(@"{""Entry"":false}", DiscordJson.SerializeObject(new TestFixture2 { Entry = new Optional <bool?>(false) })); Assert.AreEqual(@"{}", DiscordJson.SerializeObject(new TestFixture2 { Entry = new Optional <bool?>() })); // bool Assert.AreEqual(@"{""Entry"":true}", DiscordJson.SerializeObject(new TestFixture3 { Entry = new Optional <bool>(true) })); Assert.AreEqual(@"{""Entry"":false}", DiscordJson.SerializeObject(new TestFixture3 { Entry = new Optional <bool>(false) })); Assert.AreEqual(@"{}", DiscordJson.SerializeObject(new TestFixture3 { Entry = new Optional <bool>() })); }
private async Task VoiceWS_SocketMessage(IWebSocketClient client, SocketMessageEventArgs e) { if (!(e is SocketTextMessageEventArgs et)) { this.Discord.Logger.LogCritical(VoiceNextEvents.VoiceGatewayError, "Discord Voice Gateway sent binary data - unable to process"); return; } if (this.Discord.Configuration.MinimumLogLevel == LogLevel.Trace) { var cs = new MemoryStream(); await et.Message.CopyToAsync(cs).ConfigureAwait(false); cs.Seek(0, SeekOrigin.Begin); et.Message.Seek(0, SeekOrigin.Begin); using var sr = new StreamReader(cs, Utilities.UTF8); this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceWsRx, await sr.ReadToEndAsync().ConfigureAwait(false)); } var j = await DiscordJson.LoadJObjectAsync(et.Message).ConfigureAwait(false); await this.HandleDispatch(j).ConfigureAwait(false); }
public void TestOptionalSerialization2() { var p = new RestGuildModifyPayload(); Assert.AreEqual("{}", DiscordJson.SerializeObject(p)); Assert.AreEqual("{}", DiscordJson.SerializeObject(new RestGuildModifyPayload() { SystemChannelId = default,
internal RateLimitException(BaseRestRequest request, RestResponse response) : base("Rate limited: " + response.ResponseCode) { this.WebRequest = request; this.WebResponse = response; try { JObject j = DiscordJson.LoadJObject(response.Response); if (j["message"] != null) { JsonMessage = j["message"].ToString(); } } catch (Exception) { } }
internal RequestSizeException(BaseRestRequest request, RestResponse response) : base($"Request entity too large: {response.ResponseCode}. Make sure the data sent is within Discord's upload limit.") { this.WebRequest = request; this.WebResponse = response; try { var j = DiscordJson.LoadJObject(response.Response); if (j["message"] != null) { JsonMessage = j["message"].ToString(); } } catch (Exception) { } }
internal NotFoundException(BaseRestRequest request, RestResponse response) : base("Not found: " + response.ResponseCode) { this.WebRequest = request; this.WebResponse = response; try { var j = DiscordJson.LoadJObject(response.Response); if (j["message"] != null) { JsonMessage = j["message"].ToString(); } } catch (Exception) { } }
internal async Task HandleSocketMessageAsync(Stream data) { var payload = DiscordJson.Deserialize <GatewayPayload>(data); switch (payload.OpCode) { case GatewayOpCode.Dispatch: await this.HandleDispatchAsync(payload).ConfigureAwait(false); break; case GatewayOpCode.Heartbeat: await this.OnHeartbeatAsync((long)payload.Data).ConfigureAwait(false); break; case GatewayOpCode.Reconnect: await this.OnReconnectAsync().ConfigureAwait(false); break; case GatewayOpCode.InvalidSession: await this.OnInvalidateSessionAsync((bool)payload.Data).ConfigureAwait(false); break; case GatewayOpCode.Hello: await this.OnHelloAsync((payload.Data as JObject).ToObject <GatewayHello>()).ConfigureAwait(false); break; case GatewayOpCode.HeartbeatAck: await this.OnHeartbeatAckAsync().ConfigureAwait(false); break; default: this.Logger.LogWarning(LoggerEvents.WebSocketReceive, "Unknown Discord opcode: {0}\nPayload: {1}", payload.OpCode, payload.Data); break; } }
private async Task <GatewayInfo> GetGatewayInfoAsync() { var url = $"{Utilities.GetApiBaseUri()}{Endpoints.GATEWAY}{Endpoints.BOT}"; var http = new HttpClient(); http.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", Utilities.GetUserAgent()); http.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", Utilities.GetFormattedToken(this.Configuration)); this.Logger.LogDebug(LoggerEvents.ShardRest, $"Obtaining gateway information from GET {Endpoints.GATEWAY}{Endpoints.BOT}..."); var resp = await http.GetAsync(url).ConfigureAwait(false); http.Dispose(); if (!resp.IsSuccessStatusCode) { var ratelimited = await HandleHttpError(url, resp).ConfigureAwait(false); if (ratelimited) { return(await this.GetGatewayInfoAsync().ConfigureAwait(false)); } } var timer = new Stopwatch(); timer.Start(); var jo = await DiscordJson.LoadJObjectAsync(await resp.Content.ReadAsStreamAsync().ConfigureAwait(false)).ConfigureAwait(false); var info = jo.ToObject <GatewayInfo>(); //There is a delay from parsing here. timer.Stop(); info.SessionBucket.resetAfter -= (int)timer.ElapsedMilliseconds; info.SessionBucket.ResetAfter = DateTimeOffset.UtcNow + TimeSpan.FromMilliseconds(info.SessionBucket.resetAfter); return(info); async Task <bool> HandleHttpError(string reqUrl, HttpResponseMessage msg) { var code = (int)msg.StatusCode; if (code == 401 || code == 403) { throw new Exception($"Authentication failed, check your token and try again: {code} {msg.ReasonPhrase}"); } else if (code == 429) { this.Logger.LogError(LoggerEvents.ShardClientError, $"Ratelimit hit, requeuing request to {reqUrl}"); var hs = msg.Headers.ToDictionary(xh => xh.Key, xh => string.Join("\n", xh.Value), StringComparer.OrdinalIgnoreCase); var waitInterval = 0; if (hs.TryGetValue("Retry-After", out var retry_after_raw)) { waitInterval = int.Parse(retry_after_raw, CultureInfo.InvariantCulture); } await Task.Delay(waitInterval).ConfigureAwait(false); return(true); } else if (code >= 500) { throw new Exception($"Internal Server Error: {code} {msg.ReasonPhrase}"); } else { throw new Exception($"An unsuccessful HTTP status code was encountered: {code} {msg.ReasonPhrase}"); } } }
/// <summary> /// Edits the interaction response /// </summary> /// <param name="token">The token of the interaction</param> /// <param name="builder">The data, if any, to edit the response with</param> /// <returns></returns> public async Task EditInteractionResponseAsync(string token, DiscordInteractionBuilder builder) { var route = $"/webhooks/{Client.CurrentApplication.Id}/{token}/messages/@original"; var bucket = Client.ApiClient.Rest.GetBucket(RestRequestMethod.PATCH, route, new { }, out var path); var url = Utilities.GetApiUriFor(path); await Client.ApiClient.DoRequestAsync(Client, bucket, url, RestRequestMethod.PATCH, route, payload : DiscordJson.SerializeObject(builder)); }
//Respond methods /// <summary> /// Creates a response to an interaction /// </summary> /// <param name="interactionId">The id of the interaction</param> /// <param name="token">The token of the interaction</param> /// <param name="type">The type to respond with</param> /// <param name="builder">The data, if any, to send</param> /// <returns></returns> public async Task CreateInteractionResponseAsync(ulong interactionId, string token, DiscordInteractionResponseType type, DiscordInteractionBuilder builder = null) { var pld = new InteractionCreatePayload { Type = type, Data = builder }; var route = $"/interactions/{interactionId}/{token}/callback"; var bucket = Client.ApiClient.Rest.GetBucket(RestRequestMethod.POST, route, new { }, out var path); var url = Utilities.GetApiUriFor(path); await Client.ApiClient.DoRequestAsync(Client, bucket, url, RestRequestMethod.POST, route, payload : DiscordJson.SerializeObject(pld)); }
internal async Task <IReadOnlyList <DiscordApplicationCommand> > BulkCreateCommandsAsync(List <CommandCreatePayload> pld, ulong?guildid = null) { string route; if (guildid == null) { route = $"/applications/{Client.CurrentApplication.Id}/commands"; } else { route = $"/applications/{Client.CurrentApplication.Id}/guilds/{guildid}/commands"; } var bucket = Client.ApiClient.Rest.GetBucket(RestRequestMethod.PUT, route, new { }, out var path); var url = Utilities.GetApiUriFor(path); var res = await Client.ApiClient.DoRequestAsync(Client, bucket, url, RestRequestMethod.PUT, route, payload : DiscordJson.SerializeObject(pld)); var ret = JsonConvert.DeserializeObject <List <DiscordApplicationCommand> >(res.Response); foreach (var app in ret) { app.Discord = Client; } return(ret); }
private async Task WebSocket_OnMessage(IWebSocketClient client, SocketMessageEventArgs e) { if (!(e is SocketTextMessageEventArgs et)) { this.Discord.Logger.LogCritical(LavalinkEvents.LavalinkConnectionError, "Lavalink sent binary data - unable to process"); return; } if (this.Discord.Configuration.MinimumLogLevel == LogLevel.Trace) { var cs = new MemoryStream(); await et.Message.CopyToAsync(cs).ConfigureAwait(false); cs.Seek(0, SeekOrigin.Begin); et.Message.Seek(0, SeekOrigin.Begin); using var sr = new StreamReader(cs, Utilities.UTF8); this.Discord.Logger.LogTrace(LavalinkEvents.LavalinkWsRx, await sr.ReadToEndAsync().ConfigureAwait(false)); } var json = et.Message; var jsonData = await DiscordJson.LoadJObjectAsync(json).ConfigureAwait(false); switch (jsonData["op"].ToString()) { case "playerUpdate": var gid = (ulong)jsonData["guildId"]; var state = jsonData["state"].ToObject <LavalinkState>(); if (this._connectedGuilds.TryGetValue(gid, out var lvl)) { await lvl.InternalUpdatePlayerStateAsync(state).ConfigureAwait(false); } break; case "stats": var statsRaw = jsonData.ToObject <LavalinkStats>(); this.Statistics.Update(statsRaw); await this._statsReceived.InvokeAsync(this, new StatisticsReceivedEventArgs(this.Statistics)).ConfigureAwait(false); break; case "event": var evtype = jsonData["type"].ToObject <EventType>(); var guildId = (ulong)jsonData["guildId"]; switch (evtype) { case EventType.TrackStartEvent: if (this._connectedGuilds.TryGetValue(guildId, out var lvl_evtst)) { await lvl_evtst.InternalPlaybackStartedAsync(jsonData["track"].ToString()).ConfigureAwait(false); } break; case EventType.TrackEndEvent: TrackEndReason reason = TrackEndReason.Cleanup; switch (jsonData["reason"].ToString()) { case "FINISHED": reason = TrackEndReason.Finished; break; case "LOAD_FAILED": reason = TrackEndReason.LoadFailed; break; case "STOPPED": reason = TrackEndReason.Stopped; break; case "REPLACED": reason = TrackEndReason.Replaced; break; case "CLEANUP": reason = TrackEndReason.Cleanup; break; } if (this._connectedGuilds.TryGetValue(guildId, out var lvl_evtf)) { await lvl_evtf.InternalPlaybackFinishedAsync(new TrackFinishData { Track = jsonData["track"].ToString(), Reason = reason }).ConfigureAwait(false); } break; case EventType.TrackStuckEvent: if (this._connectedGuilds.TryGetValue(guildId, out var lvl_evts)) { await lvl_evts.InternalTrackStuckAsync(new TrackStuckData { Track = jsonData["track"].ToString(), Threshold = (long)jsonData["thresholdMs"] }).ConfigureAwait(false); } break; case EventType.TrackExceptionEvent: if (this._connectedGuilds.TryGetValue(guildId, out var lvl_evte)) { await lvl_evte.InternalTrackExceptionAsync(new TrackExceptionData { Track = jsonData["track"].ToString(), Error = jsonData["error"].ToString() }).ConfigureAwait(false); } break; case EventType.WebSocketClosedEvent: if (this._connectedGuilds.TryGetValue(guildId, out var lvl_ewsce)) { lvl_ewsce.VoiceWsDisconnectTcs.SetResult(true); await lvl_ewsce.InternalWebSocketClosedAsync(new WebSocketCloseEventArgs(jsonData["code"].ToObject <int>(), jsonData["reason"].ToString(), jsonData["byRemote"].ToObject <bool>())).ConfigureAwait(false); } break; } break; } }
public HttpResponseMessage GetHour(int?hour = null) { // this needs to get called hourly at about 15 minutes past the hour; set pull time in config settings (admin login) and if it's a pull time, it'll post to discord // the local time conversion is in case your server has a different time zone than your local time - forecast times are all local time DateTime thisTime = DateTime.Now; TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(Resources.TimeZoneId); var now = DateTime.Now.ToUniversalTime(); var localTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, tst.Id); var date = localTime.Date; var localHour = localTime.Hour; int fch = int.Parse(db.ConfigSettings.Find(1).Value); WeatherEntry we = new WeatherEntry(); if (hour != null) { we = db.WeatherEntries.Where(w => w.Date == date && w.Hour == hour).FirstOrDefault(); } else { if (localHour == fch || localHour == (fch + 8) || localHour == (fch + 16)) { we = db.WeatherEntries.OrderByDescending(w => w.Id).FirstOrDefault(); } else { return(Request.CreateResponse(HttpStatusCode.OK, "not time yet")); } } // get WeatherEntry (and all values) for today's date and the specified hour if (we != null && we.WeatherValues != null) { var wv = we.WeatherValues.ToArray(); // then, create forecast StringBuilder forecast = new StringBuilder(); forecast.AppendLine("Forecast at " + TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, tst.Id).ToString("h:mm tt")); for (var i = 0; i < 8; i++) { var w = wv[i]; var types = new List <string>(); var tps = w.PgoWeather.PokemonTypes.ToArray(); for (var j = 0; j < tps.Length; j++) { types.Add(tps[j].Name); } var ts = types.ToArray(); int forecastHour = w.DateTime.Hour; string fcTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(w.DateTime, tst.Id).ToString("h:mm tt"); string fc1 = fcTime + ": " + w.PgoWeather.Description; string fc2 = "Boosted types: " + string.Join(", ", ts); string fc3 = "---"; forecast.AppendLine(fc1); forecast.AppendLine(fc2); forecast.AppendLine(fc3); } forecast.AppendLine("=^..^= =^..^= =^..^="); // then, post to Discord DiscordJson js = new DiscordJson() { content = forecast.ToString() }; string url = Resources.DiscordWebhook; int firstHour = wv[0].DateTime.Hour; string json = JsonConvert.SerializeObject(js); using (WebClient client = new WebClient()) { client.Headers.Add(HttpRequestHeader.ContentType, "application/json"); var resp = client.UploadString(url, json); } // now clean up weather values table (remove old values) Task.Factory.StartNew(() => WeatherHelper.RemoveStale()); //WeatherHelper.RemoveStale(); // finally, return success return(Request.CreateResponse(HttpStatusCode.OK, firstHour)); } return(Request.CreateResponse(HttpStatusCode.OK, "no valid forecast for this date/time")); }
public HttpResponseMessage GetWeather() { DateTime thisTime = DateTime.Now; TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(Resources.TimeZoneId); var now = DateTime.Now.ToUniversalTime(); var hourAgo = now.AddHours(-1); var wv = db.WeatherValues.Where(w => w.DateAdded > hourAgo).ToArray(); // then, create forecast StringBuilder forecast = new StringBuilder(); forecast.AppendLine("Forecast at " + TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, tst.Id).ToString("h:mm tt")); for (var i = 0; i < 8; i++) { var w = wv[i]; var types = new List <string>(); var tps = w.PgoWeather.PokemonTypes.ToArray(); for (var j = 0; j < tps.Length; j++) { types.Add(tps[j].Name); } var ts = types.ToArray(); int forecastHour = w.DateTime.Hour; List <string> raidBosses = new List <string>(); //string[] bs = bosses.Select(b => b.Name + (b."")).ToArray(); string fcTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(w.DateTime, tst.Id).ToString("h:mm tt"); string fc1 = fcTime + ": " + w.PgoWeather.Description; //TimeZoneInfo.ConvertTimeBySystemTimeZoneId(w.DateTime, tst.Id) string fc2 = "Boosted types: " + string.Join(", ", ts); string fc3 = "---"; forecast.AppendLine(fc1); forecast.AppendLine(fc2); forecast.AppendLine(fc3); } forecast.AppendLine("=^..^= =^..^= =^..^="); // then, post to Discord DiscordJson js = new DiscordJson() { content = forecast.ToString() }; string url = Resources.DiscordWebhook; int firstHour = wv[0].DateTime.Hour; string json = JsonConvert.SerializeObject(js); using (WebClient client = new WebClient()) { client.Headers.Add(HttpRequestHeader.ContentType, "application/json"); var resp = client.UploadString(url, json); } // now clean up weather values table (remove old values) Task.Factory.StartNew(() => WeatherHelper.RemoveStale()); //WeatherHelper.RemoveStale(); // finally, return success return(Request.CreateResponse(HttpStatusCode.OK, firstHour)); }