public async Task PlayAsync(PlayPacket playPacket) { _cache.TryGetFromCache(playPacket.Id, out var track); if (track is null) { var(isEnabled, response) = await _sources .HandleRequestAsync(track.Provider, track.Url ?? track.Title) .ConfigureAwait(false); if (isEnabled) { LogHandler <AudioEngine> .Log .Error($"{track.Provider} is disabled in configuration."); return; } track = response.Tracks .FirstOrDefault(x => x.Url == track.Url || x.Title.Contains(track.Title)); } if (track is null) { LogHandler <AudioEngine> .Log.Error($"Unable to play the requested track: {track.Title}"); return; } if (playPacket.StartTime > track.Duration || playPacket.StartTime < 0 || playPacket.EndTime > track.Duration) { LogHandler <AudioEngine> .Log.Error($"Client sent out-of-bounds start or end time."); return; } _currentTrack = track; var stream = await _sources.GetStreamAsync(track).ConfigureAwait(false); await stream.CopyToAsync(_stream) .ConfigureAwait(false); await _stream.FlushAsync() .ConfigureAwait(false); SpinWait.SpinUntil(() => IsPlaybackCompleted); await _socket.SendAsync(new BaseResponse { Op = OperationType.TrackFinished, Data = new PlayerResponse { GuildId = _voiceClient.GuildId, Track = _currentTrack } }) .ConfigureAwait(false); _currentTrack = default; }
private async Task ProcessRequestAsync(HttpListenerContext context) { var localPath = context.Request.Url.LocalPath; var remoteEndPoint = context.Request.RemoteEndPoint; var response = new BaseResponse(); try { switch (localPath) { case "/tracks": LogHandler <WsServer> .Log.Debug($"Incoming http request from {remoteEndPoint}."); if (context.Request.Headers.Get("Password") != _config.Password) { response.Error = "Password header doesn't match value specified in configuration"; return; } var(prov, query) = context.Request.QueryString.BuildQuery(); if (query is null || prov is null) { response.Error = "Please use the `?prov={provider}&q={YOUR_QUERY} argument after /tracks"; return; } var(isEnabled, searchResponse) = await _sources.HandleRequestAsync(prov, query) .ConfigureAwait(false); if (!isEnabled) { response.Error = $"Requested {prov} isn't enabled in configuration"; } else { response.Data = searchResponse; } response.Op = OperationType.Rest; await context.SendResponseAsync(response) .ConfigureAwait(false); LogHandler <WsServer> .Log.Debug($"Replied to {remoteEndPoint} with {response.Error ?? "success"}."); break; case "/": if (!context.Request.IsWebSocketRequest) { response.Error = "Only websocket connections are allowed at this endpoint. For rest use /tracks endpoint."; await context.SendResponseAsync(response) .ConfigureAwait(false); return; } LogHandler <WsServer> .Log.Debug($"Incoming websocket request coming from {remoteEndPoint}."); var wsContext = await context.AcceptWebSocketAsync(default) .ConfigureAwait(false); var wsClient = new WsClient(wsContext); _clients.TryAdd(remoteEndPoint, wsClient); if (_clients.Count > 0 && _statsSenderTask == null) { _statsCancellation = new CancellationTokenSource(); _statsSenderTask = CollectStatsAsync(); } LogHandler <WsServer> .Log.Information($"Websocket connection opened from {remoteEndPoint}."); break; default: LogHandler <WsServer> .Log.Warning( $"{remoteEndPoint} requested an unknown path: {context.Request.Url}."); response.Error = "You are trying to access an unknown endpoint."; await context.SendResponseAsync(response) .ConfigureAwait(false); break; } } catch (Exception ex) { response.Error = $"Frostbyte threw an inner exception: {ex?.InnerException?.Message ?? ex?.Message}"; await context.SendResponseAsync(response) .ConfigureAwait(false); LogHandler <WsServer> .Log.Error(exception : ex); } finally { context.Response.Close(); } }