private async Task HLSHandler(IOwinContext ctx) { var ct = ctx.Request.CallCancelled; var req = ParsedRequest.Parse(ctx); if (!req.IsValid) { ctx.Response.StatusCode = (int)req.Status; return; } Channel channel; try { channel = await GetChannelAsync(ctx, req, ct).ConfigureAwait(false); } catch (TaskCanceledException) { ctx.Response.StatusCode = (int)HttpStatusCode.GatewayTimeout; return; } if (channel == null) { ctx.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } if (req.FragmentNumber.HasValue) { await FragmentHandler(ctx, req, channel).ConfigureAwait(false); } else { await PlayListHandler(ctx, req, channel).ConfigureAwait(false); } }
public void TestEmpty() { ParsedRequest parsedRequest; string error; var isOk = ParsedRequest.Parse("", 1, out parsedRequest, out error); Assert.False(isOk); }
public void TestAge40() { ParsedRequest parsedRequest; string error; var isOk = ParsedRequest.Parse("40", 1, out parsedRequest, out error); Assert.True(isOk); Assert.Null(parsedRequest.phone); Assert.Equal(parsedRequest.age, 40); }
public void TestMix() { ParsedRequest parsedRequest; string error; var isOk = ParsedRequest.Parse("A1B2C3", 1, out parsedRequest, out error); Assert.True(isOk); Assert.Equal(parsedRequest.name, "A1B2C3"); Assert.Null(parsedRequest.phone); Assert.Null(parsedRequest.age); }
public void TestPhone160() { ParsedRequest parsedRequest; string error; var isOk = ParsedRequest.Parse("160", 1, out parsedRequest, out error); Assert.True(isOk); Assert.Null(parsedRequest.name); Assert.Equal(parsedRequest.phone, "160"); Assert.Null(parsedRequest.age); }
public void TestNameWithSpaceAndAge() { ParsedRequest parsedRequest; string error; var isOk = ParsedRequest.Parse("ders Karl 24", 1, out parsedRequest, out error); Assert.True(isOk); Assert.Equal(parsedRequest.name, "ders Karl"); Assert.Null(parsedRequest.phone); Assert.Equal(parsedRequest.age, 24); }
public void TestAllComponents() { ParsedRequest parsedRequest; string error; var isOk = ParsedRequest.Parse("20 Johan 1234-567890", 1, out parsedRequest, out error); Assert.True(isOk); Assert.Equal(parsedRequest.name, "Johan"); Assert.Equal(parsedRequest.phone, "1234-567890"); Assert.Equal(parsedRequest.age, 20); }
private static async Task StreamHandler(IOwinContext ctx) { var logger = new Logger(typeof(HTTPDirectOwinApp), $"{ctx.Request.RemoteIpAddress}:{ctx.Request.RemotePort}"); var ct = ctx.Request.CallCancelled; var req = ParsedRequest.Parse(ctx); if (!req.IsValid) { ctx.Response.StatusCode = (int)req.Status; return; } Channel channel; try { channel = await GetChannelAsync(ctx, req, ct).ConfigureAwait(false); } catch (TaskCanceledException) { ctx.Response.StatusCode = (int)HttpStatusCode.GatewayTimeout; return; } if (channel == null) { ctx.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } var sink = new ChannelSink(ctx); using (channel.AddOutputStream(sink)) using (channel.AddContentSink(sink)) { ctx.Response.StatusCode = (int)HttpStatusCode.OK; bool asf = channel.ChannelInfo.ContentType == "WMV" || channel.ChannelInfo.ContentType == "WMA" || channel.ChannelInfo.ContentType == "ASX"; if (asf && (!ctx.Request.Headers.TryGetValue("Pragma", out var values) || !values.Contains("xplaystrm=1", StringComparer.InvariantCultureIgnoreCase))) { ctx.Response.Headers.Add("Cache-Control", new string [] { "no-cache" }); ctx.Response.Headers.Add("Server", new string [] { "Rex/9.0.2980" }); ctx.Response.Headers.Add("Pragma", new string [] { "no-cache", @"features=""broadcast,playlist""" }); ctx.Response.Headers.Add("Access-Control-Allow-Origin", new string[] { "*" }); ctx.Response.ContentType = "application/vnd.ms.wms-hdr.asfv1"; try { while (!ct.IsCancellationRequested) { var packet = await sink.DequeueAsync(ct).ConfigureAwait(false); ctx.Response.ContentLength = packet.Content.Data.Length; if (packet.Type == ChannelSink.ChannelMessage.MessageType.ContentHeader) { await ctx.Response.WriteAsync(packet.Content.Data, ct).ConfigureAwait(false); logger.Debug("Sent ContentHeader pos {0}", packet.Content.Position); break; } else if (packet.Type == ChannelSink.ChannelMessage.MessageType.ChannelStopped) { break; } } } catch (OperationCanceledException) { } } else { if (asf) { ctx.Response.Headers.Add("Cache-Control", new string [] { "no-cache" }); ctx.Response.Headers.Add("Server", new string [] { "Rex/9.0.2980" }); ctx.Response.Headers.Add("Pragma", new string [] { "no-cache", @"features=""broadcast,playlist""" }); ctx.Response.Headers.Add("Access-Control-Allow-Origin", new string[] { "*" }); ctx.Response.ContentType = "application/x-mms-framed"; ctx.Response.Headers.Add("Connection", new string[] { "close" }); } else { ctx.Response.ContentType = channel.ChannelInfo.MIMEType; ctx.Response.Headers.Add("Access-Control-Allow-Origin", new string[] { "*" }); ctx.Response.Headers.Add("Transfer-Encoding", new string [] { "chunked" }); } Content sent_header = null; Content sent_packet = null; try { while (!ct.IsCancellationRequested) { var packet = await sink.DequeueAsync(ct).ConfigureAwait(false); if (packet.Type == ChannelSink.ChannelMessage.MessageType.ContentHeader) { if (sent_header != packet.Content && packet.Content != null) { await ctx.Response.WriteAsync(packet.Content.Data, ct).ConfigureAwait(false); logger.Debug("Sent ContentHeader pos {0}", packet.Content.Position); sent_header = packet.Content; sent_packet = packet.Content; } } else if (packet.Type == ChannelSink.ChannelMessage.MessageType.ContentBody) { if (sent_header == null) { continue; } var c = packet.Content; if (c.Timestamp > sent_packet.Timestamp || (c.Timestamp == sent_packet.Timestamp && c.Position > sent_packet.Position)) { await ctx.Response.WriteAsync(c.Data, ct).ConfigureAwait(false); sent_packet = c; } } else if (packet.Type == ChannelSink.ChannelMessage.MessageType.ChannelStopped) { break; } } } catch (OperationCanceledException) { } } } }
private static async Task PlayListHandler(IOwinContext ctx) { var ct = ctx.Request.CallCancelled; var req = ParsedRequest.Parse(ctx); if (!req.IsValid) { ctx.Response.StatusCode = (int)req.Status; return; } Channel channel; try { channel = await GetChannelAsync(ctx, req, ct).ConfigureAwait(false); } catch (TaskCanceledException) { ctx.Response.StatusCode = (int)HttpStatusCode.GatewayTimeout; return; } if (channel == null) { ctx.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } var fmt = ctx.Request.Query.Get("pls") ?? req.Extension; //m3u8のプレイリストを要求された時はHLS用のパスに転送する if (fmt?.ToLowerInvariant() == "m3u8") { ctx.Response.StatusCode = (int)HttpStatusCode.MovedPermanently; var location = new UriBuilder(ctx.Request.Uri); location.Path = $"/hls/{req.ChannelId.ToString("N")}"; if (location.Query.Contains("pls=m3u8")) { var queries = location.Query.Substring(1).Split('&').Where(seg => seg != "pls=m3u8").ToArray(); if (queries.Length > 0) { location.Query = String.Join("&", queries); } else { location.Query = null; } } ctx.Response.Headers.Add("Location", new string [] { location.Uri.ToString() }); return; } var scheme = ctx.Request.Query.Get("scheme"); var pls = CreatePlaylist(channel, fmt, scheme); ctx.Response.StatusCode = (int)HttpStatusCode.OK; ctx.Response.Headers.Add("Cache-Control", new string [] { "private" }); ctx.Response.Headers.Add("Cache-Disposition", new string [] { "inline" }); ctx.Response.Headers.Add("Access-Control-Allow-Origin", new string[] { "*" }); ctx.Response.ContentType = pls.MIMEType; byte[] body; try { var baseuri = new Uri( new Uri(ctx.Request.Uri.GetComponents(UriComponents.SchemeAndServer | UriComponents.UserInfo, UriFormat.UriEscaped)), "stream/"); var acinfo = ctx.GetAccessControlInfo(); using (var cts = CancellationTokenSource.CreateLinkedTokenSource(ct)) { cts.CancelAfter(10000); if (acinfo.AuthorizationRequired) { var parameters = new Dictionary <string, string>() { { "auth", acinfo.AuthenticationKey.GetToken() }, }; body = await pls.CreatePlayListAsync(baseuri, parameters, cts.Token).ConfigureAwait(false); } else { body = await pls.CreatePlayListAsync(baseuri, Enumerable.Empty <KeyValuePair <string, string> >(), cts.Token).ConfigureAwait(false); } } } catch (OperationCanceledException) { ctx.Response.StatusCode = (int)HttpStatusCode.GatewayTimeout; return; } ctx.Response.StatusCode = (int)HttpStatusCode.OK; await ctx.Response.WriteAsync(body, ct).ConfigureAwait(false); }
public async Task <Tuple <int, SearchResult> > GetResult(Tuple <string, int> key) { Tuple <int, SearchResult> result; if (_cache.TryGetValue(key, out result)) { return(result); } var log = new StringBuilder(); Stopwatch sw = new Stopwatch(); sw.Start(); ParsedRequest parsedRequest; string error; if (ParsedRequest.Parse(key.Item1, key.Item2, out parsedRequest, out error)) { var jsonParsedRequest = JsonConvert.SerializeObject(parsedRequest); log.AppendFormat("Parsed request: {0}\n", jsonParsedRequest); var peopleSearchUri = GetPeopleSearchUri(parsedRequest); CancellationTokenSource cts1 = new CancellationTokenSource(); var peopleSearchResult = await CreateClientRequest() .PostAsync(peopleSearchUri, new StringContent(jsonParsedRequest), cts1.Token); string requestId; try { dynamic data = JsonConvert.DeserializeObject(await peopleSearchResult.Content.ReadAsStringAsync()); requestId = data.id; } catch (RuntimeBinderException) { requestId = null; } log.AppendFormat("Request id: {0}\n", requestId); if (requestId != null) { var peopleSearchResultUri = GetPeopleSearchResultUri(requestId); CancellationTokenSource cts2 = new CancellationTokenSource(); HttpResponseMessage result2 = null; var retries = 0; while (result2 == null) { try { result2 = await CreateClientRequest().GetAsync(peopleSearchResultUri, cts2.Token); } catch (HttpRequestException ex) { if (retries++ > 20) { throw; } log.AppendFormat("Search result not ready yet ({0}), retrying...\n", ex.Message); Thread.Sleep(500); } } var strData = await result2.Content.ReadAsStringAsync(); var data = JsonConvert.DeserializeObject <Person[]>(strData); sw.Stop(); var resultContent = new SearchResult { data = data, page = key.Item2, log = log.ToString(), requestId = requestId, timestamp = DateTime.UtcNow, duration = sw.ElapsedMilliseconds }; result = Tuple.Create(200, resultContent); } else { log.AppendFormat("Cannot get requestId\n"); sw.Stop(); result = Tuple.Create(500, new SearchResult { data = null, log = log.ToString(), requestId = null, timestamp = DateTime.UtcNow, duration = sw.ElapsedMilliseconds }); } } else { log.AppendFormat("Cannot parse query. Error: {0}\n", error); sw.Stop(); result = Tuple.Create(400, new SearchResult { data = null, log = log.ToString(), requestId = null, timestamp = DateTime.UtcNow, duration = sw.ElapsedMilliseconds }); } var options = new MemoryCacheEntryOptions() // Keep in cache for this time, reset time if accessed. .SetSlidingExpiration(TimeSpan.FromHours(1)); _cache.Set(key, result, options); return(result); }