[WIP] Live flow

This commit is contained in:
Paul Schneider 2019-02-08 10:22:52 +00:00
commit ae55d9b8d8
16 changed files with 3605 additions and 100 deletions

View file

@ -39,11 +39,13 @@ namespace Yavsc.Controllers
_dbContext = context;
_logger = loggerFactory.CreateLogger<LiveApiController>();
}
[HttpGet("filenamehint/{id}")]
public async Task<string[]> GetFileNameHint(string id)
{
return await _dbContext.Tags.Where( t=> t.Name.StartsWith(id)).Select(t=>t.Name).Take(25).ToArrayAsync();
}
[HttpGet("live/{id}")]
public async Task<IActionResult> GetLive(string id)
{
if (!HttpContext.WebSockets.IsWebSocketRequest) return new BadRequestResult();
@ -59,91 +61,10 @@ namespace Yavsc.Controllers
return HttpBadRequest("Listeners.TryAdd returned false");
}
public async Task<IActionResult> Cast(long id)
{
// ensure this request is for a websocket
if (!HttpContext.WebSockets.IsWebSocketRequest) return new BadRequestResult();
var uname = User.GetUserName();
// ensure uniqueness of casting stream from this user
var existent = Casters[uname];
if (existent != null)
{
ModelState.AddModelError("error","not supported, you already casting, there's support for one live streaming only");
return new BadRequestObjectResult(ModelState);
}
var uid = User.GetUserId();
// get some setup from user
var flow = _dbContext.LiveFlow.Include(f=>f.Owner).SingleOrDefault(f=> (f.OwnerId==uid && f.Id == id));
if (flow == null)
{
ModelState.AddModelError("error",$"You don't own any flow with the id {id}");
return new BadRequestObjectResult (ModelState);
}
// Accept the socket
var meta = new LiveCastMeta { Socket = await HttpContext.WebSockets.AcceptWebSocketAsync() };
// Dispatch the flow
using (meta.Socket)
{
if (meta.Socket != null && meta.Socket.State == WebSocketState.Open)
{
Casters[uname] = meta;
// TODO: Handle the socket here.
// Find receivers: others in the chat room
// send them the flow
byte[] buffer = new byte[1024];
WebSocketReceiveResult received = await meta.Socket.ReceiveAsync
(new ArraySegment<byte>(buffer), CancellationToken.None);
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
hubContext.Clients.All.addPublicStream(new { id = flow.Id, sender = flow.Owner.UserName, title = flow.Title, url = flow.GetFileUrl(),
mediaType = flow.MediaType }, $"{flow.Owner.UserName} is starting a stream!");
// FIXME do we really need to close those one in invalid state ?
Stack<string> ToClose = new Stack<string>();
while (received.MessageType != WebSocketMessageType.Close)
{
_logger.LogInformation($"Echoing {received.Count} bytes received in a {received.MessageType} message; Fin={received.EndOfMessage}");
// Echo anything we receive
// and send to all listner found
foreach (var cliItem in meta.Listeners)
{
var listenningSocket = cliItem.Value;
if (listenningSocket.State == WebSocketState.Open)
await listenningSocket.SendAsync(new ArraySegment<byte>
(buffer, 0, received.Count), received.MessageType, received.EndOfMessage, CancellationToken.None);
else ToClose.Push(cliItem.Key);
}
received = await meta.Socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
string no;
do
{
no = ToClose.Pop();
WebSocket listenningSocket;
if (meta.Listeners.TryRemove(no, out listenningSocket))
await listenningSocket.CloseAsync(WebSocketCloseStatus.EndpointUnavailable, "State != WebSocketState.Open", CancellationToken.None);
} while (no != null);
}
await meta.Socket.CloseAsync(received.CloseStatus.Value, received.CloseStatusDescription, CancellationToken.None);
Casters[uname] = null;
}
else _logger.LogInformation($"failed (meta.Socket != null && meta.Socket.State == WebSocketState.Open)");
}
return Ok();
}
/// <summary>
/// Lists user's live castings
/// </summary>
/// <param name="id">user id</param>
/// <param name="meta/id">user id</param>
/// <returns></returns>
public IActionResult Index(long? id)
{
@ -158,7 +79,7 @@ namespace Yavsc.Controllers
}
[HttpGet("{id}", Name = "GetLiveFlow")]
[HttpGet("meta/{id}")]
public async Task<IActionResult> GetLiveFlow([FromRoute] long id)
{
if (!ModelState.IsValid)
@ -176,7 +97,7 @@ namespace Yavsc.Controllers
return Ok(liveFlow);
}
[HttpPut("{id}")]
[HttpPut("meta/{id}")]
public async Task<IActionResult> PutLiveFlow([FromRoute] long id, [FromBody] LiveFlow liveFlow)
{
if (!ModelState.IsValid)
@ -216,7 +137,7 @@ namespace Yavsc.Controllers
return new HttpStatusCodeResult(StatusCodes.Status204NoContent);
}
[HttpPost]
[HttpPost("meta")]
public async Task<IActionResult> PostLiveFlow([FromBody] LiveFlow liveFlow)
{
if (!ModelState.IsValid)
@ -248,7 +169,7 @@ namespace Yavsc.Controllers
}
// DELETE: api/LiveApi/5
[HttpDelete("{id}")]
[HttpDelete("meta/{id}")]
public async Task<IActionResult> DeleteLiveFlow([FromRoute] long id)
{
if (!ModelState.IsValid)
@ -289,4 +210,4 @@ namespace Yavsc.Controllers
return _dbContext.LiveFlow.Count(e => e.Id == id) > 0;
}
}
}
}