refactoring
parent
73055d11a0
commit
57c4ca5f7b
@ -1,165 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Microsoft.AspNet.Mvc;
|
|
||||||
using Microsoft.Data.Entity;
|
|
||||||
using Yavsc.Models;
|
|
||||||
using Yavsc.Models.Streaming;
|
|
||||||
|
|
||||||
namespace Yavsc.Controllers
|
|
||||||
{
|
|
||||||
[Produces("application/json")]
|
|
||||||
[Route("api/LiveApi")]
|
|
||||||
public class LiveApiController : Controller
|
|
||||||
{
|
|
||||||
private ApplicationDbContext _context;
|
|
||||||
|
|
||||||
public LiveApiController(ApplicationDbContext context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET: api/LiveApi
|
|
||||||
[HttpGet]
|
|
||||||
public IEnumerable<LiveFlow> GetLiveFlow()
|
|
||||||
{
|
|
||||||
return _context.LiveFlow;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET: api/LiveApi/5
|
|
||||||
[HttpGet("{id}", Name = "GetLiveFlow")]
|
|
||||||
public async Task<IActionResult> GetLiveFlow([FromRoute] long id)
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return HttpBadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
LiveFlow liveFlow = await _context.LiveFlow.SingleAsync(m => m.Id == id);
|
|
||||||
|
|
||||||
if (liveFlow == null)
|
|
||||||
{
|
|
||||||
return HttpNotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(liveFlow);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT: api/LiveApi/5
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
public async Task<IActionResult> PutLiveFlow([FromRoute] long id, [FromBody] LiveFlow liveFlow)
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return HttpBadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id != liveFlow.Id)
|
|
||||||
{
|
|
||||||
return HttpBadRequest();
|
|
||||||
}
|
|
||||||
var uid = User.GetUserId();
|
|
||||||
if (liveFlow.OwnerId!=uid)
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("id","This flow isn't yours.");
|
|
||||||
return HttpBadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
_context.Entry(liveFlow).State = EntityState.Modified;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _context.SaveChangesAsync(uid);
|
|
||||||
}
|
|
||||||
catch (DbUpdateConcurrencyException)
|
|
||||||
{
|
|
||||||
if (!LiveFlowExists(id))
|
|
||||||
{
|
|
||||||
return HttpNotFound();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new HttpStatusCodeResult(StatusCodes.Status204NoContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST: api/LiveApi
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IActionResult> PostLiveFlow([FromBody] LiveFlow liveFlow)
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return HttpBadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
var uid = User.GetUserId();
|
|
||||||
liveFlow.OwnerId=uid;
|
|
||||||
|
|
||||||
_context.LiveFlow.Add(liveFlow);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _context.SaveChangesAsync(uid);
|
|
||||||
}
|
|
||||||
catch (DbUpdateException)
|
|
||||||
{
|
|
||||||
if (LiveFlowExists(liveFlow.Id))
|
|
||||||
{
|
|
||||||
return new HttpStatusCodeResult(StatusCodes.Status409Conflict);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreatedAtRoute("GetLiveFlow", new { id = liveFlow.Id }, liveFlow);
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE: api/LiveApi/5
|
|
||||||
[HttpDelete("{id}")]
|
|
||||||
public async Task<IActionResult> DeleteLiveFlow([FromRoute] long id)
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
return HttpBadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
LiveFlow liveFlow = await _context.LiveFlow.SingleAsync(m => m.Id == id);
|
|
||||||
if (liveFlow == null)
|
|
||||||
{
|
|
||||||
return HttpNotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
var uid = User.GetUserId();
|
|
||||||
if (liveFlow.OwnerId!=uid)
|
|
||||||
{
|
|
||||||
ModelState.AddModelError("id","This flow isn't yours.");
|
|
||||||
return HttpBadRequest(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
_context.LiveFlow.Remove(liveFlow);
|
|
||||||
await _context.SaveChangesAsync(uid);
|
|
||||||
|
|
||||||
return Ok(liveFlow);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
_context.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool LiveFlowExists(long id)
|
|
||||||
{
|
|
||||||
return _context.LiveFlow.Count(e => e.Id == id) > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,281 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.Data.Entity;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Yavsc.Models;
|
||||||
|
using Yavsc.Models.Streaming;
|
||||||
|
using Yavsc.ViewModels.Streaming;
|
||||||
|
|
||||||
|
namespace Yavsc.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/LiveApi")]
|
||||||
|
public class LiveApiController : Controller
|
||||||
|
{
|
||||||
|
public static ConcurrentDictionary<string, LiveCastMeta> Casters = new ConcurrentDictionary<string, LiveCastMeta>();
|
||||||
|
|
||||||
|
private ApplicationDbContext _dbContext;
|
||||||
|
ILogger _logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Live Api Controller
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="loggerFactory"></param>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
|
||||||
|
public LiveApiController(
|
||||||
|
ILoggerFactory loggerFactory,
|
||||||
|
ApplicationDbContext context)
|
||||||
|
{
|
||||||
|
_dbContext = context;
|
||||||
|
_logger = loggerFactory.CreateLogger<LiveApiController>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<IActionResult> GetLive(string id)
|
||||||
|
{
|
||||||
|
if (!HttpContext.WebSockets.IsWebSocketRequest) return new BadRequestResult();
|
||||||
|
var uid = User.GetUserId();
|
||||||
|
var existent = Casters[id];
|
||||||
|
var socket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||||
|
if (existent.Listeners.TryAdd(uid,socket)) {
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await socket.CloseAsync(WebSocketCloseStatus.EndpointUnavailable,"Listeners.TryAdd failed",CancellationToken.None);
|
||||||
|
}
|
||||||
|
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.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);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public IActionResult Index(long? id)
|
||||||
|
{
|
||||||
|
if (id==0)
|
||||||
|
return View("Index", Casters.Select(c=> new { UserName = c.Key, Listenning = c.Value.Listeners.Count }));
|
||||||
|
|
||||||
|
var flow = _dbContext.LiveFlow.SingleOrDefault(f=>f.Id == id);
|
||||||
|
if (flow == null) return HttpNotFound();
|
||||||
|
|
||||||
|
return View("Flow", flow);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GET: api/LiveApi/5
|
||||||
|
[HttpGet("{id}", Name = "GetLiveFlow")]
|
||||||
|
public async Task<IActionResult> GetLiveFlow([FromRoute] long id)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return HttpBadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveFlow liveFlow = await _dbContext.LiveFlow.SingleAsync(m => m.Id == id);
|
||||||
|
|
||||||
|
if (liveFlow == null)
|
||||||
|
{
|
||||||
|
return HttpNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(liveFlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT: api/LiveApi/5
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public async Task<IActionResult> PutLiveFlow([FromRoute] long id, [FromBody] LiveFlow liveFlow)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return HttpBadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id != liveFlow.Id)
|
||||||
|
{
|
||||||
|
return HttpBadRequest();
|
||||||
|
}
|
||||||
|
var uid = User.GetUserId();
|
||||||
|
if (liveFlow.OwnerId!=uid)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("id","This flow isn't yours.");
|
||||||
|
return HttpBadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbContext.Entry(liveFlow).State = EntityState.Modified;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _dbContext.SaveChangesAsync(uid);
|
||||||
|
}
|
||||||
|
catch (DbUpdateConcurrencyException)
|
||||||
|
{
|
||||||
|
if (!LiveFlowExists(id))
|
||||||
|
{
|
||||||
|
return HttpNotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HttpStatusCodeResult(StatusCodes.Status204NoContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST: api/LiveApi
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> PostLiveFlow([FromBody] LiveFlow liveFlow)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return HttpBadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var uid = User.GetUserId();
|
||||||
|
liveFlow.OwnerId=uid;
|
||||||
|
|
||||||
|
_dbContext.LiveFlow.Add(liveFlow);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _dbContext.SaveChangesAsync(uid);
|
||||||
|
}
|
||||||
|
catch (DbUpdateException)
|
||||||
|
{
|
||||||
|
if (LiveFlowExists(liveFlow.Id))
|
||||||
|
{
|
||||||
|
return new HttpStatusCodeResult(StatusCodes.Status409Conflict);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreatedAtRoute("GetLiveFlow", new { id = liveFlow.Id }, liveFlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE: api/LiveApi/5
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public async Task<IActionResult> DeleteLiveFlow([FromRoute] long id)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return HttpBadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveFlow liveFlow = await _dbContext.LiveFlow.SingleAsync(m => m.Id == id);
|
||||||
|
if (liveFlow == null)
|
||||||
|
{
|
||||||
|
return HttpNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var uid = User.GetUserId();
|
||||||
|
if (liveFlow.OwnerId!=uid)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError("id","This flow isn't yours.");
|
||||||
|
return HttpBadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbContext.LiveFlow.Remove(liveFlow);
|
||||||
|
await _dbContext.SaveChangesAsync(uid);
|
||||||
|
|
||||||
|
return Ok(liveFlow);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_dbContext.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LiveFlowExists(long id)
|
||||||
|
{
|
||||||
|
return _dbContext.LiveFlow.Count(e => e.Id == id) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,34 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNet.Mvc;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace Yavsc {
|
|
||||||
|
|
||||||
public class StreamingApiController {
|
|
||||||
|
|
||||||
ILogger _logger;
|
|
||||||
|
|
||||||
public StreamingApiController (LoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
_logger = loggerFactory.CreateLogger<StreamingApiController>();
|
|
||||||
_logger.LogInformation
|
|
||||||
("created logger");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IActionResult> GetStreamingToken()
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Token asked");
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
public async Task<IActionResult> GetLiveStreamingIndex()
|
|
||||||
{
|
|
||||||
_logger.LogInformation("GetLiveStreamingIndex");
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue