using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using AutoMapper;
using BililiveRecorder.Core;
using BililiveRecorder.Web.Models;
using BililiveRecorder.Web.Models.Rest;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace BililiveRecorder.Web.Api
{
[ApiController, Route("api/[controller]", Name = "[controller] [action]")]
public sealed class RoomController : ControllerBase
{
private readonly IMapper mapper;
private readonly IRecorder recorder;
public RoomController(IMapper mapper, IRecorder recorder)
{
this.mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
this.recorder = recorder ?? throw new ArgumentNullException(nameof(recorder));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private IRoom? FetchRoom(int roomId) => this.recorder.Rooms.FirstOrDefault(x => x.ShortId == roomId || x.RoomConfig.RoomId == roomId);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private IRoom? FetchRoom(Guid objectId) => this.recorder.Rooms.FirstOrDefault(x => x.ObjectId == objectId);
///
/// 列出所有直播间
///
///
[HttpGet]
public RoomDto[] GetRooms() => this.mapper.Map(this.recorder.Rooms);
#region Create & Delete
///
/// 添加直播间
///
///
///
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status400BadRequest)]
public ActionResult CreateRoom([FromBody] CreateRoomDto createRoom)
{
if (createRoom.RoomId <= 0)
return this.BadRequest(new RestApiError { Code = RestApiErrorCode.RoomidOutOfRange, Message = "Roomid must be greater than 0." });
var room = this.FetchRoom(createRoom.RoomId);
if (room is not null)
{
if (room.RoomConfig.AutoRecord != createRoom.AutoRecord)
room.RoomConfig.AutoRecord = createRoom.AutoRecord;
}
else
{
room = this.recorder.AddRoom(createRoom.RoomId, createRoom.AutoRecord);
}
return this.mapper.Map(room);
}
///
/// 删除直播间
///
///
///
[HttpDelete("{roomId:int}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult DeleteRoom(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
this.recorder.RemoveRoom(room);
return this.mapper.Map(room);
}
///
/// 删除直播间
///
///
///
[HttpDelete("{objectId:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult DeleteRoom(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
this.recorder.RemoveRoom(room);
return this.mapper.Map(room);
}
#endregion
#region Get Room
///
/// 读取一个直播间
///
///
///
[HttpGet("{roomId:int}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult GetRoom(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
return this.mapper.Map(room);
}
///
/// 读取一个直播间
///
///
///
[HttpGet("{objectId:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult GetRoom(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
return this.mapper.Map(room);
}
#endregion
#region Get Room Stats
///
/// 读取直播间录制统计信息
///
///
///
[HttpGet("{roomId:int}/stats")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult GetRoomRecordingStats(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
return this.mapper.Map(room.Stats);
}
///
/// 读取直播间录制统计信息
///
///
///
[HttpGet("{objectId:guid}/stats")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult GetRoomRecordingStats(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
return this.mapper.Map(room.Stats);
}
///
/// 读取直播间 IO 统计信息
///
///
///
[HttpGet("{roomId:int}/ioStats")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult GetRoomIOStats(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
return this.mapper.Map(room.Stats);
}
///
/// 读取直播间 IO 统计信息
///
///
///
[HttpGet("{objectId:guid}/ioStats")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult GetRoomIOStats(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
return this.mapper.Map(room.Stats);
}
#endregion
#region Room Config
///
/// 读取直播间设置
///
///
///
[HttpGet("{roomId:int}/config")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult GetRoomConfig(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
return this.mapper.Map(room.RoomConfig);
}
///
/// 读取直播间设置
///
///
///
[HttpGet("{objectId:guid}/config")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult GetRoomConfig(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
return this.mapper.Map(room.RoomConfig);
}
///
/// 修改直播间设置
///
///
///
///
[HttpPost("{roomId:int}/config")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult SetRoomConfig(int roomId, [FromBody] SetRoomConfig config)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
config.ApplyTo(room.RoomConfig);
this.recorder.SaveConfig();
return this.mapper.Map(room.RoomConfig);
}
///
/// 修改直播间设置
///
///
///
///
[HttpPost("{objectId:guid}/config")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult SetRoomConfig(Guid objectId, [FromBody] SetRoomConfig config)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
config.ApplyTo(room.RoomConfig);
this.recorder.SaveConfig();
return this.mapper.Map(room.RoomConfig);
}
#endregion
#region Room Action
///
/// 开始录制
///
///
///
[HttpPost("{roomId:int}/start")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult StartRecording(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
room.StartRecord();
return this.mapper.Map(room);
}
///
/// 开始录制
///
///
///
[HttpPost("{objectId:guid}/start")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult StartRecording(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
room.StartRecord();
return this.mapper.Map(room);
}
///
/// 停止录制
///
///
///
[HttpPost("{roomId:int}/stop")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult StopRecording(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
room.StopRecord();
return this.mapper.Map(room);
}
///
/// 停止录制
///
///
///
[HttpPost("{objectId:guid}/stop")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult StopRecording(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
room.StopRecord();
return this.mapper.Map(room);
}
///
/// 手动分段
///
///
///
[HttpPost("{roomId:int}/split")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult SplitRecording(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
room.SplitOutput();
return this.mapper.Map(room);
}
///
/// 手动分段
///
///
///
[HttpPost("{objectId:guid}/split")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public ActionResult SplitRecording(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
room.SplitOutput();
return this.mapper.Map(room);
}
///
/// 刷新直播间信息
///
///
///
[HttpPost("{roomId:int}/refresh")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public async Task> RefreshRecordingAsync(int roomId)
{
var room = this.FetchRoom(roomId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
await room.RefreshRoomInfoAsync().ConfigureAwait(false);
return this.mapper.Map(room);
}
///
/// 刷新直播间信息
///
///
///
[HttpPost("{objectId:guid}/refresh")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(RestApiError), StatusCodes.Status404NotFound)]
public async Task> RefreshRecordingAsync(Guid objectId)
{
var room = this.FetchRoom(objectId);
if (room is null)
return this.NotFound(new RestApiError { Code = RestApiErrorCode.RoomNotFound, Message = "Room not found" });
await room.RefreshRoomInfoAsync().ConfigureAwait(false);
return this.mapper.Map(room);
}
#endregion
}
}