Example #1
0
 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>()
     }));
 }
Example #2
0
        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);
        }
Example #3
0
        public void TestOptionalSerialization2()
        {
            var p = new RestGuildModifyPayload();

            Assert.AreEqual("{}", DiscordJson.SerializeObject(p));
            Assert.AreEqual("{}", DiscordJson.SerializeObject(new RestGuildModifyPayload()
            {
                SystemChannelId = default,
Example #4
0
        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) { }
        }
Example #5
0
        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) { }
        }
Example #6
0
        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) { }
        }
Example #7
0
        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);
        }
Example #12
0
        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;
            }
        }
Example #13
0
        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"));
        }
Example #14
0
        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));
        }