mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-15 19:22:19 +08:00
Add Web API
This commit is contained in:
parent
30a659f4d2
commit
db7f2872f8
|
@ -4,6 +4,7 @@
|
|||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<StartupObject>BililiveRecorder.Cli.Program</StartupObject>
|
||||
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
|
||||
<RuntimeIdentifiers>win-x64;osx-x64;osx.10.11-x64;linux-arm64;linux-arm;linux-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifier Condition=" '$(RuntimeIdentifier)' == 'any' "></RuntimeIdentifier>
|
||||
<PublishDir Condition=" '$(RuntimeIdentifier)' == '' ">publish\any</PublishDir>
|
||||
|
@ -22,6 +23,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Process" Version="2.0.2" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Exceptions" Version="8.0.0" />
|
||||
|
@ -35,6 +37,7 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\BililiveRecorder.Core\BililiveRecorder.Core.csproj" />
|
||||
<ProjectReference Include="..\BililiveRecorder.ToolBox\BililiveRecorder.ToolBox.csproj" />
|
||||
<ProjectReference Include="..\BililiveRecorder.Web\BililiveRecorder.Web.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -6,12 +6,16 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using BililiveRecorder.Cli.Configure;
|
||||
using System.Threading.Tasks;
|
||||
using BililiveRecorder.Core;
|
||||
using BililiveRecorder.Core.Config;
|
||||
using BililiveRecorder.Core.Config.V2;
|
||||
using BililiveRecorder.DependencyInjection;
|
||||
using BililiveRecorder.ToolBox;
|
||||
using BililiveRecorder.Web;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
|
@ -26,12 +30,13 @@ namespace BililiveRecorder.Cli
|
|||
{
|
||||
var cmd_run = new Command("run", "Run BililiveRecorder in standard mode")
|
||||
{
|
||||
new Option<string?>(new []{ "--web-bind", "--bind", "-b" }, () => null, "Bind address for web api"),
|
||||
new Option<LogEventLevel>(new []{ "--loglevel", "--log", "-l" }, () => LogEventLevel.Information, "Minimal log level output to console"),
|
||||
new Option<LogEventLevel>(new []{ "--logfilelevel", "--flog" }, () => LogEventLevel.Debug, "Minimal log level output to file"),
|
||||
new Argument<string>("path"),
|
||||
};
|
||||
cmd_run.AddAlias("r");
|
||||
cmd_run.Handler = CommandHandler.Create<string, LogEventLevel, LogEventLevel>(RunConfigMode);
|
||||
cmd_run.Handler = CommandHandler.Create<RunModeArguments>(RunConfigModeAsync);
|
||||
|
||||
var cmd_portable = new Command("portable", "Run BililiveRecorder in config-less mode")
|
||||
{
|
||||
|
@ -60,9 +65,11 @@ namespace BililiveRecorder.Cli
|
|||
return root.Invoke(args);
|
||||
}
|
||||
|
||||
private static int RunConfigMode(string path, LogEventLevel logLevel, LogEventLevel logFileLevel)
|
||||
private static async Task<int> RunConfigModeAsync(RunModeArguments args)
|
||||
{
|
||||
using var logger = BuildLogger(logLevel, logFileLevel);
|
||||
var path = args.Path;
|
||||
|
||||
using var logger = BuildLogger(args.LogLevel, args.LogFileLevel);
|
||||
Log.Logger = logger;
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
|
@ -76,22 +83,64 @@ namespace BililiveRecorder.Cli
|
|||
config.Global.WorkDirectory = path;
|
||||
|
||||
var serviceProvider = BuildServiceProvider(config, logger);
|
||||
IRecorder recorderAccessProxy(IServiceProvider x) => serviceProvider.GetRequiredService<IRecorder>();
|
||||
|
||||
// recorder setup done
|
||||
// check if web service required
|
||||
IHost? host = null;
|
||||
if (string.IsNullOrWhiteSpace(args.WebBind))
|
||||
{
|
||||
logger.Information("Web API not enabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Information("Creating web server on {BindAddress}", args.WebBind);
|
||||
|
||||
host = new HostBuilder()
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddSingleton(recorderAccessProxy);
|
||||
})
|
||||
.ConfigureWebHost(webBuilder =>
|
||||
{
|
||||
webBuilder
|
||||
.UseUrls(urls: args.WebBind)
|
||||
.UseKestrel()
|
||||
.UseSerilog(logger: logger)
|
||||
.UseStartup<Startup>();
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
|
||||
// make sure recorder is created, also used in cleanup ( .Dispose() )
|
||||
var recorder = serviceProvider.GetRequiredService<IRecorder>();
|
||||
|
||||
ConsoleCancelEventHandler p = null!;
|
||||
var semaphore = new SemaphoreSlim(0, 1);
|
||||
var cts = new CancellationTokenSource();
|
||||
p = (sender, e) =>
|
||||
{
|
||||
logger.Information("Ctrl+C pressed. Exiting");
|
||||
Console.CancelKeyPress -= p;
|
||||
e.Cancel = true;
|
||||
recorder.Dispose();
|
||||
semaphore.Release();
|
||||
cts.Cancel();
|
||||
};
|
||||
Console.CancelKeyPress += p;
|
||||
|
||||
semaphore.Wait();
|
||||
Thread.Sleep(1000 * 2);
|
||||
Console.ReadLine();
|
||||
var token = cts.Token;
|
||||
if (host is not null)
|
||||
{
|
||||
var hostStartTask = host.RunAsync(token);
|
||||
await Task.WhenAny(Task.Delay(-1, token), hostStartTask).ConfigureAwait(false);
|
||||
await host.StopAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(-1, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
recorder.Dispose();
|
||||
|
||||
await Task.Delay(1000 * 3).ConfigureAwait(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -140,6 +189,7 @@ namespace BililiveRecorder.Cli
|
|||
var semaphore = new SemaphoreSlim(0, 1);
|
||||
p = (sender, e) =>
|
||||
{
|
||||
logger.Information("Ctrl+C pressed. Exiting");
|
||||
Console.CancelKeyPress -= p;
|
||||
e.Cancel = true;
|
||||
recorder.Dispose();
|
||||
|
@ -179,6 +229,17 @@ namespace BililiveRecorder.Cli
|
|||
.WriteTo.File(new CompactJsonFormatter(), "./logs/bilirec.txt", restrictedToMinimumLevel: logFileLevel, shared: true, rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true)
|
||||
.CreateLogger();
|
||||
|
||||
public class RunModeArguments
|
||||
{
|
||||
public LogEventLevel LogLevel { get; set; } = LogEventLevel.Information;
|
||||
|
||||
public LogEventLevel LogFileLevel { get; set; } = LogEventLevel.Information;
|
||||
|
||||
public string? WebBind { get; set; } = null;
|
||||
|
||||
public string Path { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class PortableModeArguments
|
||||
{
|
||||
public LogEventLevel LogLevel { get; set; } = LogEventLevel.Information;
|
||||
|
|
|
@ -18,8 +18,8 @@ namespace BililiveRecorder.Core
|
|||
event EventHandler<AggregatedRoomEventArgs<NetworkingStatsEventArgs>>? NetworkingStats;
|
||||
event EventHandler<AggregatedRoomEventArgs<RecordingStatsEventArgs>>? RecordingStats;
|
||||
|
||||
void AddRoom(int roomid);
|
||||
void AddRoom(int roomid, bool enabled);
|
||||
IRoom AddRoom(int roomid);
|
||||
IRoom AddRoom(int roomid, bool enabled);
|
||||
void RemoveRoom(IRoom room);
|
||||
|
||||
void SaveConfig();
|
||||
|
|
|
@ -58,20 +58,21 @@ namespace BililiveRecorder.Core
|
|||
|
||||
public ReadOnlyObservableCollection<IRoom> Rooms { get; }
|
||||
|
||||
public void AddRoom(int roomid) => this.AddRoom(roomid, true);
|
||||
public IRoom AddRoom(int roomid) => this.AddRoom(roomid, true);
|
||||
|
||||
public void AddRoom(int roomid, bool enabled)
|
||||
public IRoom AddRoom(int roomid, bool enabled)
|
||||
{
|
||||
lock (this.lockObject)
|
||||
{
|
||||
this.logger.Debug("AddRoom {RoomId}, AutoRecord: {AutoRecord}", roomid, enabled);
|
||||
var roomConfig = new RoomConfig { RoomId = roomid, AutoRecord = enabled };
|
||||
this.AddRoom(roomConfig, 0);
|
||||
var room = this.AddRoom(roomConfig, 0);
|
||||
this.SaveConfig();
|
||||
return room;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddRoom(RoomConfig roomConfig, int initDelayFactor)
|
||||
private IRoom AddRoom(RoomConfig roomConfig, int initDelayFactor)
|
||||
{
|
||||
roomConfig.SetParent(this.Config.Global);
|
||||
var room = this.roomFactory.CreateRoom(roomConfig, initDelayFactor);
|
||||
|
@ -85,6 +86,7 @@ namespace BililiveRecorder.Core
|
|||
room.PropertyChanged += this.Room_PropertyChanged;
|
||||
|
||||
this.roomCollection.Add(room);
|
||||
return room;
|
||||
}
|
||||
|
||||
public void RemoveRoom(IRoom room)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GraphQL.Server.Core" Version="5.0.2" />
|
||||
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="5.0.2" />
|
||||
<PackageReference Include="GraphQL.Server.Transports.Subscriptions.WebSockets" Version="5.0.2" />
|
||||
<PackageReference Include="GraphQL.Server.Ui.Altair" Version="5.0.2" />
|
||||
<PackageReference Include="GraphQL.Server.Ui.GraphiQL" Version="5.0.2" />
|
||||
<PackageReference Include="GraphQL.Server.Ui.Playground" Version="5.0.2" />
|
||||
<PackageReference Include="GraphQL.Server.Ui.Voyager" Version="5.0.2" />
|
||||
<PackageReference Include="GraphQL.SystemReactive" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BililiveRecorder.Core\BililiveRecorder.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
229
BililiveRecorder.Web.Schemas/RecorderMutation.cs
Normal file
229
BililiveRecorder.Web.Schemas/RecorderMutation.cs
Normal file
|
@ -0,0 +1,229 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using BililiveRecorder.Core;
|
||||
using BililiveRecorder.Web.Schemas.Types;
|
||||
using GraphQL;
|
||||
using GraphQL.Types;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas
|
||||
{
|
||||
internal class RecorderMutation : ObjectGraphType
|
||||
{
|
||||
private readonly IRecorder recorder;
|
||||
|
||||
public RecorderMutation(IRecorder recorder)
|
||||
{
|
||||
this.recorder = recorder ?? throw new ArgumentNullException(nameof(recorder));
|
||||
|
||||
this.SetupFields();
|
||||
}
|
||||
|
||||
private void SetupFields()
|
||||
{
|
||||
this.Field<RoomType>("addRoom",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<IntGraphType> { Name = "roomId" },
|
||||
new QueryArgument<BooleanGraphType> { Name = "autoRecord" }
|
||||
),
|
||||
resolve: context =>
|
||||
{
|
||||
var roomid = context.GetArgument<int>("roomId");
|
||||
var enabled = context.GetArgument<bool>("autoRecord");
|
||||
|
||||
var room = this.recorder.Rooms.FirstOrDefault(x => x.RoomConfig.RoomId == roomid || x.ShortId == roomid);
|
||||
|
||||
if (room is not null)
|
||||
{
|
||||
context.Errors.Add(new ExecutionError("Room already exist.")
|
||||
{
|
||||
Code = "BREC_ROOM_DUPLICATE"
|
||||
});
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.recorder.AddRoom(roomid, enabled);
|
||||
}
|
||||
});
|
||||
|
||||
this.Field<RoomType>("removeRoom",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<GuidGraphType> { Name = "objectId" },
|
||||
new QueryArgument<IntGraphType> { Name = "roomId" }
|
||||
),
|
||||
resolve: context =>
|
||||
{
|
||||
var objectId = context.GetArgument<Guid>("objectId");
|
||||
var roomid = context.GetArgument<int>("roomId");
|
||||
|
||||
var room = objectId != default
|
||||
? this.recorder.Rooms.FirstOrDefault(x => x.ObjectId == objectId)
|
||||
: this.recorder.Rooms.FirstOrDefault(x => x.RoomConfig.RoomId == roomid || x.ShortId == roomid);
|
||||
|
||||
if (room is not null)
|
||||
this.recorder.RemoveRoom(room);
|
||||
else
|
||||
context.Errors.Add(new ExecutionError("Room not found")
|
||||
{
|
||||
Code = "BREC_ROOM_NOT_FOUND"
|
||||
});
|
||||
|
||||
return room;
|
||||
});
|
||||
|
||||
this.FieldAsync<RoomType>("refreshRoomInfo",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<GuidGraphType> { Name = "objectId" },
|
||||
new QueryArgument<IntGraphType> { Name = "roomId" }
|
||||
),
|
||||
resolve: async context =>
|
||||
{
|
||||
var objectId = context.GetArgument<Guid>("objectId");
|
||||
var roomid = context.GetArgument<int>("roomId");
|
||||
|
||||
var room = objectId != default
|
||||
? this.recorder.Rooms.FirstOrDefault(x => x.ObjectId == objectId)
|
||||
: this.recorder.Rooms.FirstOrDefault(x => x.RoomConfig.RoomId == roomid || x.ShortId == roomid);
|
||||
|
||||
if (room is not null)
|
||||
await room.RefreshRoomInfoAsync().ConfigureAwait(false);
|
||||
else
|
||||
context.Errors.Add(new ExecutionError("Room not found")
|
||||
{
|
||||
Code = "BREC_ROOM_NOT_FOUND"
|
||||
});
|
||||
|
||||
return room;
|
||||
});
|
||||
|
||||
this.Field<RoomType>("startRecording",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<GuidGraphType> { Name = "objectId" },
|
||||
new QueryArgument<IntGraphType> { Name = "roomId" }
|
||||
),
|
||||
resolve: context =>
|
||||
{
|
||||
var objectId = context.GetArgument<Guid>("objectId");
|
||||
var roomid = context.GetArgument<int>("roomId");
|
||||
|
||||
var room = objectId != default
|
||||
? this.recorder.Rooms.FirstOrDefault(x => x.ObjectId == objectId)
|
||||
: this.recorder.Rooms.FirstOrDefault(x => x.RoomConfig.RoomId == roomid || x.ShortId == roomid);
|
||||
|
||||
if (room is not null)
|
||||
room.StartRecord();
|
||||
else
|
||||
context.Errors.Add(new ExecutionError("Room not found")
|
||||
{
|
||||
Code = "BREC_ROOM_NOT_FOUND"
|
||||
});
|
||||
|
||||
return room;
|
||||
});
|
||||
|
||||
this.Field<RoomType>("stopRecording",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<GuidGraphType> { Name = "objectId" },
|
||||
new QueryArgument<IntGraphType> { Name = "roomId" }
|
||||
),
|
||||
resolve: context =>
|
||||
{
|
||||
var objectId = context.GetArgument<Guid>("objectId");
|
||||
var roomid = context.GetArgument<int>("roomId");
|
||||
|
||||
var room = objectId != default
|
||||
? this.recorder.Rooms.FirstOrDefault(x => x.ObjectId == objectId)
|
||||
: this.recorder.Rooms.FirstOrDefault(x => x.RoomConfig.RoomId == roomid || x.ShortId == roomid);
|
||||
|
||||
if (room is not null)
|
||||
room.StopRecord();
|
||||
else
|
||||
context.Errors.Add(new ExecutionError("Room not found")
|
||||
{
|
||||
Code = "BREC_ROOM_NOT_FOUND"
|
||||
});
|
||||
|
||||
return room;
|
||||
});
|
||||
|
||||
this.Field<RoomType>("splitRecordingOutput",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<GuidGraphType> { Name = "objectId" },
|
||||
new QueryArgument<IntGraphType> { Name = "roomId" }
|
||||
),
|
||||
resolve: context =>
|
||||
{
|
||||
var objectId = context.GetArgument<Guid>("objectId");
|
||||
var roomid = context.GetArgument<int>("roomId");
|
||||
|
||||
var room = objectId != default
|
||||
? this.recorder.Rooms.FirstOrDefault(x => x.ObjectId == objectId)
|
||||
: this.recorder.Rooms.FirstOrDefault(x => x.RoomConfig.RoomId == roomid || x.ShortId == roomid);
|
||||
|
||||
if (room is not null)
|
||||
room.SplitOutput();
|
||||
else
|
||||
context.Errors.Add(new ExecutionError("Room not found")
|
||||
{
|
||||
Code = "BREC_ROOM_NOT_FOUND"
|
||||
});
|
||||
|
||||
return room;
|
||||
});
|
||||
|
||||
this.Field<RoomType>("setRoomConfig",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<GuidGraphType> { Name = "objectId" },
|
||||
new QueryArgument<IntGraphType> { Name = "roomId" },
|
||||
new QueryArgument<SetRoomConfigType> { Name = "config" }
|
||||
),
|
||||
resolve: context =>
|
||||
{
|
||||
var objectId = context.GetArgument<Guid>("objectId");
|
||||
var roomid = context.GetArgument<int>("roomId");
|
||||
var config = context.GetArgument<SetRoomConfig>("config");
|
||||
|
||||
if (config is null)
|
||||
{
|
||||
context.Errors.Add(new ExecutionError("config can't be null"));
|
||||
return null;
|
||||
}
|
||||
|
||||
var room = objectId != default
|
||||
? this.recorder.Rooms.FirstOrDefault(x => x.ObjectId == objectId)
|
||||
: this.recorder.Rooms.FirstOrDefault(x => x.RoomConfig.RoomId == roomid || x.ShortId == roomid);
|
||||
|
||||
if (room is null)
|
||||
context.Errors.Add(new ExecutionError("Room not found")
|
||||
{
|
||||
Code = "BREC_ROOM_NOT_FOUND"
|
||||
});
|
||||
else
|
||||
config.ApplyTo(room.RoomConfig);
|
||||
|
||||
return room;
|
||||
});
|
||||
|
||||
this.Field<GlobalConfigType>("setConfig",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<SetGlobalConfigType> { Name = "config" }
|
||||
),
|
||||
resolve: context =>
|
||||
{
|
||||
var config = context.GetArgument<SetGlobalConfig>("config");
|
||||
|
||||
if (config is null)
|
||||
{
|
||||
context.Errors.Add(new ExecutionError("config can't be null"));
|
||||
return null;
|
||||
}
|
||||
|
||||
var recconfig = this.recorder.Config.Global;
|
||||
|
||||
config.ApplyTo(recconfig);
|
||||
|
||||
return recconfig;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
49
BililiveRecorder.Web.Schemas/RecorderQuery.cs
Normal file
49
BililiveRecorder.Web.Schemas/RecorderQuery.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using BililiveRecorder.Core;
|
||||
using BililiveRecorder.Core.Config.V2;
|
||||
using BililiveRecorder.Web.Schemas.Types;
|
||||
using GraphQL;
|
||||
using GraphQL.Types;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas
|
||||
{
|
||||
internal class RecorderQuery : ObjectGraphType
|
||||
{
|
||||
private readonly IRecorder recorder;
|
||||
|
||||
public RecorderQuery(IRecorder recorder)
|
||||
{
|
||||
this.recorder = recorder ?? throw new ArgumentNullException(nameof(recorder));
|
||||
|
||||
this.SetupFields();
|
||||
}
|
||||
|
||||
private void SetupFields()
|
||||
{
|
||||
this.Field<GlobalConfigType>("config", resolve: context => this.recorder.Config.Global);
|
||||
|
||||
this.Field<DefaultConfigType>("defaultConfig", resolve: context => DefaultConfig.Instance);
|
||||
|
||||
this.Field<ListGraphType<RoomType>>("rooms", resolve: context => this.recorder.Rooms);
|
||||
|
||||
this.Field<RoomType>("room",
|
||||
arguments: new QueryArguments(
|
||||
new QueryArgument<IdGraphType> { Name = "objectId" },
|
||||
new QueryArgument<IntGraphType> { Name = "roomId" }
|
||||
),
|
||||
resolve: context =>
|
||||
{
|
||||
var objectId = context.GetArgument<Guid>("objectId");
|
||||
var roomid = context.GetArgument<int>("roomId");
|
||||
|
||||
var room = objectId != default
|
||||
? this.recorder.Rooms.FirstOrDefault(x => x.ObjectId == objectId)
|
||||
: this.recorder.Rooms.FirstOrDefault(x => x.RoomConfig.RoomId == roomid || x.ShortId == roomid);
|
||||
|
||||
return room;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
16
BililiveRecorder.Web.Schemas/RecorderSchema.cs
Normal file
16
BililiveRecorder.Web.Schemas/RecorderSchema.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using BililiveRecorder.Core;
|
||||
using GraphQL.Types;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas
|
||||
{
|
||||
public class RecorderSchema : Schema
|
||||
{
|
||||
public RecorderSchema(IServiceProvider services, IRecorder recorder) : base(services)
|
||||
{
|
||||
this.Query = new RecorderQuery(recorder);
|
||||
this.Mutation = new RecorderMutation(recorder);
|
||||
//this.Subscription = new RecorderSubscription();
|
||||
}
|
||||
}
|
||||
}
|
8
BililiveRecorder.Web.Schemas/RecorderSubscription.cs
Normal file
8
BililiveRecorder.Web.Schemas/RecorderSubscription.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using GraphQL.Types;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas
|
||||
{
|
||||
internal class RecorderSubscription : ObjectGraphType
|
||||
{
|
||||
}
|
||||
}
|
214
BililiveRecorder.Web.Schemas/Types/Config.gen.cs
Normal file
214
BililiveRecorder.Web.Schemas/Types/Config.gen.cs
Normal file
|
@ -0,0 +1,214 @@
|
|||
// ******************************
|
||||
// GENERATED CODE, DO NOT EDIT MANUALLY.
|
||||
// SEE /config_gen/README.md
|
||||
// ******************************
|
||||
|
||||
using BililiveRecorder.Core.Config.V2;
|
||||
using GraphQL.Types;
|
||||
using HierarchicalPropertyDefault;
|
||||
#nullable enable
|
||||
namespace BililiveRecorder.Web.Schemas.Types
|
||||
{
|
||||
internal class RoomConfigType : ObjectGraphType<RoomConfig>
|
||||
{
|
||||
public RoomConfigType()
|
||||
{
|
||||
this.Field(x => x.RoomId);
|
||||
this.Field(x => x.AutoRecord);
|
||||
this.Field(x => x.OptionalRecordMode, type: typeof(HierarchicalOptionalType<RecordMode>));
|
||||
this.Field(x => x.OptionalCuttingMode, type: typeof(HierarchicalOptionalType<CuttingMode>));
|
||||
this.Field(x => x.OptionalCuttingNumber, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalRecordDanmaku, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuRaw, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuSuperChat, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGift, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGuard, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordingQuality, type: typeof(HierarchicalOptionalType<string>));
|
||||
}
|
||||
}
|
||||
|
||||
internal class GlobalConfigType : ObjectGraphType<GlobalConfig>
|
||||
{
|
||||
public GlobalConfigType()
|
||||
{
|
||||
this.Field(x => x.OptionalRecordMode, type: typeof(HierarchicalOptionalType<RecordMode>));
|
||||
this.Field(x => x.OptionalCuttingMode, type: typeof(HierarchicalOptionalType<CuttingMode>));
|
||||
this.Field(x => x.OptionalCuttingNumber, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalRecordDanmaku, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuRaw, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuSuperChat, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGift, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGuard, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalRecordingQuality, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalRecordFilenameFormat, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalWebHookUrls, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalWebHookUrlsV2, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalWpfShowTitleAndArea, type: typeof(HierarchicalOptionalType<bool>));
|
||||
this.Field(x => x.OptionalCookie, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalLiveApiHost, type: typeof(HierarchicalOptionalType<string>));
|
||||
this.Field(x => x.OptionalTimingCheckInterval, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalTimingStreamRetry, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalTimingStreamRetryNoQn, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalTimingStreamConnect, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalTimingDanmakuRetry, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalTimingWatchdogTimeout, type: typeof(HierarchicalOptionalType<uint>));
|
||||
this.Field(x => x.OptionalRecordDanmakuFlushInterval, type: typeof(HierarchicalOptionalType<uint>));
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultConfigType : ObjectGraphType<DefaultConfig>
|
||||
{
|
||||
public DefaultConfigType()
|
||||
{
|
||||
this.Field(x => x.RecordMode);
|
||||
this.Field(x => x.CuttingMode);
|
||||
this.Field(x => x.CuttingNumber);
|
||||
this.Field(x => x.RecordDanmaku);
|
||||
this.Field(x => x.RecordDanmakuRaw);
|
||||
this.Field(x => x.RecordDanmakuSuperChat);
|
||||
this.Field(x => x.RecordDanmakuGift);
|
||||
this.Field(x => x.RecordDanmakuGuard);
|
||||
this.Field(x => x.RecordingQuality);
|
||||
this.Field(x => x.RecordFilenameFormat);
|
||||
this.Field(x => x.WebHookUrls);
|
||||
this.Field(x => x.WebHookUrlsV2);
|
||||
this.Field(x => x.WpfShowTitleAndArea);
|
||||
this.Field(x => x.Cookie);
|
||||
this.Field(x => x.LiveApiHost);
|
||||
this.Field(x => x.TimingCheckInterval);
|
||||
this.Field(x => x.TimingStreamRetry);
|
||||
this.Field(x => x.TimingStreamRetryNoQn);
|
||||
this.Field(x => x.TimingStreamConnect);
|
||||
this.Field(x => x.TimingDanmakuRetry);
|
||||
this.Field(x => x.TimingWatchdogTimeout);
|
||||
this.Field(x => x.RecordDanmakuFlushInterval);
|
||||
}
|
||||
}
|
||||
|
||||
internal class SetRoomConfig
|
||||
{
|
||||
public bool? AutoRecord { get; set; }
|
||||
public Optional<RecordMode>? OptionalRecordMode { get; set; }
|
||||
public Optional<CuttingMode>? OptionalCuttingMode { get; set; }
|
||||
public Optional<uint>? OptionalCuttingNumber { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmaku { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuRaw { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuSuperChat { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuGift { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuGuard { get; set; }
|
||||
public Optional<string?>? OptionalRecordingQuality { get; set; }
|
||||
|
||||
public void ApplyTo(RoomConfig config)
|
||||
{
|
||||
if (this.AutoRecord.HasValue) config.AutoRecord = this.AutoRecord.Value;
|
||||
if (this.OptionalRecordMode.HasValue) config.OptionalRecordMode = this.OptionalRecordMode.Value;
|
||||
if (this.OptionalCuttingMode.HasValue) config.OptionalCuttingMode = this.OptionalCuttingMode.Value;
|
||||
if (this.OptionalCuttingNumber.HasValue) config.OptionalCuttingNumber = this.OptionalCuttingNumber.Value;
|
||||
if (this.OptionalRecordDanmaku.HasValue) config.OptionalRecordDanmaku = this.OptionalRecordDanmaku.Value;
|
||||
if (this.OptionalRecordDanmakuRaw.HasValue) config.OptionalRecordDanmakuRaw = this.OptionalRecordDanmakuRaw.Value;
|
||||
if (this.OptionalRecordDanmakuSuperChat.HasValue) config.OptionalRecordDanmakuSuperChat = this.OptionalRecordDanmakuSuperChat.Value;
|
||||
if (this.OptionalRecordDanmakuGift.HasValue) config.OptionalRecordDanmakuGift = this.OptionalRecordDanmakuGift.Value;
|
||||
if (this.OptionalRecordDanmakuGuard.HasValue) config.OptionalRecordDanmakuGuard = this.OptionalRecordDanmakuGuard.Value;
|
||||
if (this.OptionalRecordingQuality.HasValue) config.OptionalRecordingQuality = this.OptionalRecordingQuality.Value;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SetRoomConfigType : InputObjectGraphType<SetRoomConfig>
|
||||
{
|
||||
public SetRoomConfigType()
|
||||
{
|
||||
this.Field(x => x.AutoRecord, nullable: true);
|
||||
this.Field(x => x.OptionalRecordMode, nullable: true, type: typeof(HierarchicalOptionalInputType<RecordMode>));
|
||||
this.Field(x => x.OptionalCuttingMode, nullable: true, type: typeof(HierarchicalOptionalInputType<CuttingMode>));
|
||||
this.Field(x => x.OptionalCuttingNumber, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalRecordDanmaku, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuRaw, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuSuperChat, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGift, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGuard, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordingQuality, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
}
|
||||
}
|
||||
|
||||
internal class SetGlobalConfig
|
||||
{
|
||||
public Optional<RecordMode>? OptionalRecordMode { get; set; }
|
||||
public Optional<CuttingMode>? OptionalCuttingMode { get; set; }
|
||||
public Optional<uint>? OptionalCuttingNumber { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmaku { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuRaw { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuSuperChat { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuGift { get; set; }
|
||||
public Optional<bool>? OptionalRecordDanmakuGuard { get; set; }
|
||||
public Optional<string?>? OptionalRecordingQuality { get; set; }
|
||||
public Optional<string?>? OptionalRecordFilenameFormat { get; set; }
|
||||
public Optional<string?>? OptionalWebHookUrls { get; set; }
|
||||
public Optional<string?>? OptionalWebHookUrlsV2 { get; set; }
|
||||
public Optional<bool>? OptionalWpfShowTitleAndArea { get; set; }
|
||||
public Optional<string?>? OptionalCookie { get; set; }
|
||||
public Optional<string?>? OptionalLiveApiHost { get; set; }
|
||||
public Optional<uint>? OptionalTimingCheckInterval { get; set; }
|
||||
public Optional<uint>? OptionalTimingStreamRetry { get; set; }
|
||||
public Optional<uint>? OptionalTimingStreamRetryNoQn { get; set; }
|
||||
public Optional<uint>? OptionalTimingStreamConnect { get; set; }
|
||||
public Optional<uint>? OptionalTimingDanmakuRetry { get; set; }
|
||||
public Optional<uint>? OptionalTimingWatchdogTimeout { get; set; }
|
||||
public Optional<uint>? OptionalRecordDanmakuFlushInterval { get; set; }
|
||||
|
||||
public void ApplyTo(GlobalConfig config)
|
||||
{
|
||||
if (this.OptionalRecordMode.HasValue) config.OptionalRecordMode = this.OptionalRecordMode.Value;
|
||||
if (this.OptionalCuttingMode.HasValue) config.OptionalCuttingMode = this.OptionalCuttingMode.Value;
|
||||
if (this.OptionalCuttingNumber.HasValue) config.OptionalCuttingNumber = this.OptionalCuttingNumber.Value;
|
||||
if (this.OptionalRecordDanmaku.HasValue) config.OptionalRecordDanmaku = this.OptionalRecordDanmaku.Value;
|
||||
if (this.OptionalRecordDanmakuRaw.HasValue) config.OptionalRecordDanmakuRaw = this.OptionalRecordDanmakuRaw.Value;
|
||||
if (this.OptionalRecordDanmakuSuperChat.HasValue) config.OptionalRecordDanmakuSuperChat = this.OptionalRecordDanmakuSuperChat.Value;
|
||||
if (this.OptionalRecordDanmakuGift.HasValue) config.OptionalRecordDanmakuGift = this.OptionalRecordDanmakuGift.Value;
|
||||
if (this.OptionalRecordDanmakuGuard.HasValue) config.OptionalRecordDanmakuGuard = this.OptionalRecordDanmakuGuard.Value;
|
||||
if (this.OptionalRecordingQuality.HasValue) config.OptionalRecordingQuality = this.OptionalRecordingQuality.Value;
|
||||
if (this.OptionalRecordFilenameFormat.HasValue) config.OptionalRecordFilenameFormat = this.OptionalRecordFilenameFormat.Value;
|
||||
if (this.OptionalWebHookUrls.HasValue) config.OptionalWebHookUrls = this.OptionalWebHookUrls.Value;
|
||||
if (this.OptionalWebHookUrlsV2.HasValue) config.OptionalWebHookUrlsV2 = this.OptionalWebHookUrlsV2.Value;
|
||||
if (this.OptionalWpfShowTitleAndArea.HasValue) config.OptionalWpfShowTitleAndArea = this.OptionalWpfShowTitleAndArea.Value;
|
||||
if (this.OptionalCookie.HasValue) config.OptionalCookie = this.OptionalCookie.Value;
|
||||
if (this.OptionalLiveApiHost.HasValue) config.OptionalLiveApiHost = this.OptionalLiveApiHost.Value;
|
||||
if (this.OptionalTimingCheckInterval.HasValue) config.OptionalTimingCheckInterval = this.OptionalTimingCheckInterval.Value;
|
||||
if (this.OptionalTimingStreamRetry.HasValue) config.OptionalTimingStreamRetry = this.OptionalTimingStreamRetry.Value;
|
||||
if (this.OptionalTimingStreamRetryNoQn.HasValue) config.OptionalTimingStreamRetryNoQn = this.OptionalTimingStreamRetryNoQn.Value;
|
||||
if (this.OptionalTimingStreamConnect.HasValue) config.OptionalTimingStreamConnect = this.OptionalTimingStreamConnect.Value;
|
||||
if (this.OptionalTimingDanmakuRetry.HasValue) config.OptionalTimingDanmakuRetry = this.OptionalTimingDanmakuRetry.Value;
|
||||
if (this.OptionalTimingWatchdogTimeout.HasValue) config.OptionalTimingWatchdogTimeout = this.OptionalTimingWatchdogTimeout.Value;
|
||||
if (this.OptionalRecordDanmakuFlushInterval.HasValue) config.OptionalRecordDanmakuFlushInterval = this.OptionalRecordDanmakuFlushInterval.Value;
|
||||
}
|
||||
}
|
||||
|
||||
internal class SetGlobalConfigType : InputObjectGraphType<SetGlobalConfig>
|
||||
{
|
||||
public SetGlobalConfigType()
|
||||
{
|
||||
this.Field(x => x.OptionalRecordMode, nullable: true, type: typeof(HierarchicalOptionalInputType<RecordMode>));
|
||||
this.Field(x => x.OptionalCuttingMode, nullable: true, type: typeof(HierarchicalOptionalInputType<CuttingMode>));
|
||||
this.Field(x => x.OptionalCuttingNumber, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalRecordDanmaku, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuRaw, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuSuperChat, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGift, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordDanmakuGuard, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalRecordingQuality, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalRecordFilenameFormat, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalWebHookUrls, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalWebHookUrlsV2, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalWpfShowTitleAndArea, nullable: true, type: typeof(HierarchicalOptionalInputType<bool>));
|
||||
this.Field(x => x.OptionalCookie, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalLiveApiHost, nullable: true, type: typeof(HierarchicalOptionalInputType<string>));
|
||||
this.Field(x => x.OptionalTimingCheckInterval, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalTimingStreamRetry, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalTimingStreamRetryNoQn, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalTimingStreamConnect, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalTimingDanmakuRetry, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalTimingWatchdogTimeout, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
this.Field(x => x.OptionalRecordDanmakuFlushInterval, nullable: true, type: typeof(HierarchicalOptionalInputType<uint>));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
9
BililiveRecorder.Web.Schemas/Types/CuttingModeEnum.cs
Normal file
9
BililiveRecorder.Web.Schemas/Types/CuttingModeEnum.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using BililiveRecorder.Core.Config.V2;
|
||||
using GraphQL.Types;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas.Types
|
||||
{
|
||||
public class CuttingModeEnum : EnumerationGraphType<CuttingMode>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using GraphQL.Types;
|
||||
using HierarchicalPropertyDefault;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas.Types
|
||||
{
|
||||
public class HierarchicalOptionalInputType<TValue> : InputObjectGraphType<Optional<TValue>>
|
||||
{
|
||||
public HierarchicalOptionalInputType()
|
||||
{
|
||||
this.Name = "HierarchicalOptionalInput_" + typeof(TValue).Name + "_Type";
|
||||
|
||||
this.Field(x => x.HasValue)
|
||||
.Description("Use 'value' when 'hasValue' is true, or use the value from parent object when 'hasValue' is false.");
|
||||
|
||||
this.Field(x => x.Value, nullable: typeof(TValue) == typeof(string))
|
||||
.Description("NOTE: The value of this field is ignored when 'hasValue' is false.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using GraphQL.Types;
|
||||
using HierarchicalPropertyDefault;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas.Types
|
||||
{
|
||||
public class HierarchicalOptionalType<TValue> : ObjectGraphType<Optional<TValue>>
|
||||
{
|
||||
public HierarchicalOptionalType()
|
||||
{
|
||||
this.Name = "HierarchicalOptional_" + typeof(TValue).Name + "_Type";
|
||||
|
||||
this.Field(x => x.HasValue)
|
||||
.Description("Use 'value' when 'hasValue' is true, or use the value from parent object when 'hasValue' is false.");
|
||||
|
||||
this.Field(x => x.Value, nullable: typeof(TValue) == typeof(string))
|
||||
.Description("NOTE: The value of this field is ignored when 'hasValue' is false.");
|
||||
}
|
||||
}
|
||||
}
|
9
BililiveRecorder.Web.Schemas/Types/RecordModeEnum.cs
Normal file
9
BililiveRecorder.Web.Schemas/Types/RecordModeEnum.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using BililiveRecorder.Core.Config.V2;
|
||||
using GraphQL.Types;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas.Types
|
||||
{
|
||||
public class RecordModeEnum : EnumerationGraphType<RecordMode>
|
||||
{
|
||||
}
|
||||
}
|
19
BililiveRecorder.Web.Schemas/Types/RecordingStatsType.cs
Normal file
19
BililiveRecorder.Web.Schemas/Types/RecordingStatsType.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using BililiveRecorder.Core;
|
||||
using GraphQL.Types;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas.Types
|
||||
{
|
||||
public class RecordingStatsType : ObjectGraphType<RecordingStats>
|
||||
{
|
||||
public RecordingStatsType()
|
||||
{
|
||||
this.Field(x => x.NetworkMbps);
|
||||
this.Field(x => x.SessionDuration);
|
||||
this.Field(x => x.FileMaxTimestamp);
|
||||
this.Field(x => x.SessionMaxTimestamp);
|
||||
this.Field(x => x.DurationRatio);
|
||||
this.Field(x => x.TotalInputBytes);
|
||||
this.Field(x => x.TotalOutputBytes);
|
||||
}
|
||||
}
|
||||
}
|
24
BililiveRecorder.Web.Schemas/Types/RoomType.cs
Normal file
24
BililiveRecorder.Web.Schemas/Types/RoomType.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using BililiveRecorder.Core;
|
||||
using GraphQL.Types;
|
||||
|
||||
namespace BililiveRecorder.Web.Schemas.Types
|
||||
{
|
||||
internal class RoomType : ObjectGraphType<IRoom>
|
||||
{
|
||||
public RoomType()
|
||||
{
|
||||
this.Field(x => x.ObjectId);
|
||||
this.Field(x => x.RoomConfig, type: typeof(RoomConfigType));
|
||||
this.Field(x => x.ShortId);
|
||||
this.Field(x => x.Name);
|
||||
this.Field(x => x.Title);
|
||||
this.Field(x => x.AreaNameParent);
|
||||
this.Field(x => x.AreaNameChild);
|
||||
this.Field(x => x.Recording);
|
||||
this.Field(x => x.Streaming);
|
||||
this.Field(x => x.AutoRecordForThisSession);
|
||||
this.Field(x => x.DanmakuConnected);
|
||||
this.Field(x => x.Stats, type: typeof(RecordingStatsType));
|
||||
}
|
||||
}
|
||||
}
|
15
BililiveRecorder.Web/BililiveRecorder.Web.csproj
Normal file
15
BililiveRecorder.Web/BililiveRecorder.Web.csproj
Normal file
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.NewtonsoftJson" Version="5.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BililiveRecorder.Web.Schemas\BililiveRecorder.Web.Schemas.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
65
BililiveRecorder.Web/FakeRecorderForWeb.cs
Normal file
65
BililiveRecorder.Web/FakeRecorderForWeb.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using BililiveRecorder.Core;
|
||||
using BililiveRecorder.Core.Config.V2;
|
||||
using BililiveRecorder.Core.Event;
|
||||
|
||||
namespace BililiveRecorder.Web
|
||||
{
|
||||
internal class FakeRecorderForWeb : IRecorder
|
||||
{
|
||||
private bool disposedValue;
|
||||
|
||||
public ConfigV2 Config { get; } = new ConfigV2();
|
||||
|
||||
public ReadOnlyObservableCollection<IRoom> Rooms { get; } = new ReadOnlyObservableCollection<IRoom>(new ObservableCollection<IRoom>());
|
||||
|
||||
public event EventHandler<AggregatedRoomEventArgs<RecordSessionStartedEventArgs>>? RecordSessionStarted;
|
||||
public event EventHandler<AggregatedRoomEventArgs<RecordSessionEndedEventArgs>>? RecordSessionEnded;
|
||||
public event EventHandler<AggregatedRoomEventArgs<RecordFileOpeningEventArgs>>? RecordFileOpening;
|
||||
public event EventHandler<AggregatedRoomEventArgs<RecordFileClosedEventArgs>>? RecordFileClosed;
|
||||
public event EventHandler<AggregatedRoomEventArgs<NetworkingStatsEventArgs>>? NetworkingStats;
|
||||
public event EventHandler<AggregatedRoomEventArgs<RecordingStatsEventArgs>>? RecordingStats;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public IRoom AddRoom(int roomid) => null!;
|
||||
|
||||
public IRoom AddRoom(int roomid, bool enabled) => null!;
|
||||
|
||||
public void RemoveRoom(IRoom room)
|
||||
{ }
|
||||
|
||||
public void SaveConfig()
|
||||
{ }
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!this.disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// TODO: dispose managed state (managed objects)
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
this.disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~FakeRecorderForWeb()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
this.Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
23
BililiveRecorder.Web/Program.cs
Normal file
23
BililiveRecorder.Web/Program.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BililiveRecorder.Web
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args) => CreateHostBuilder(args).Build().Run();
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
28
BililiveRecorder.Web/Properties/launchSettings.json
Normal file
28
BililiveRecorder.Web/Properties/launchSettings.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:9644",
|
||||
"sslPort": 44313
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"BililiveRecorder.Web": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
82
BililiveRecorder.Web/Startup.cs
Normal file
82
BililiveRecorder.Web/Startup.cs
Normal file
|
@ -0,0 +1,82 @@
|
|||
using System.Diagnostics;
|
||||
using BililiveRecorder.Core;
|
||||
using BililiveRecorder.Web.Schemas;
|
||||
using GraphQL;
|
||||
using GraphQL.Server;
|
||||
using GraphQL.Types;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace BililiveRecorder.Web
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
// TODO 减少引用的依赖数量
|
||||
|
||||
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
|
||||
{
|
||||
this.Configuration = configuration;
|
||||
this.Environment = environment;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public IWebHostEnvironment Environment { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.Configure<KestrelServerOptions>(o => o.AllowSynchronousIO = true);
|
||||
|
||||
services.TryAddSingleton<IRecorder>(new FakeRecorderForWeb());
|
||||
|
||||
services
|
||||
.AddCors(o => o.AddDefaultPolicy(p => p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()))
|
||||
.AddSingleton<RecorderSchema>()
|
||||
.AddSingleton(typeof(EnumerationGraphType<>))
|
||||
.AddSingleton<IDocumentExecuter, SubscriptionDocumentExecuter>()
|
||||
.AddGraphQL((options, provider) =>
|
||||
{
|
||||
options.EnableMetrics = this.Environment.IsDevelopment() || Debugger.IsAttached;
|
||||
var logger = provider.GetRequiredService<ILogger<Startup>>();
|
||||
options.UnhandledExceptionDelegate = ctx => logger.LogWarning(ctx.OriginalException, "Unhandled GraphQL Exception");
|
||||
})
|
||||
//.AddSystemTextJson()
|
||||
.AddNewtonsoftJson()
|
||||
.AddWebSockets()
|
||||
.AddGraphTypes(typeof(RecorderSchema))
|
||||
;
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) => app
|
||||
.UseCors()
|
||||
.UseWebSockets()
|
||||
.UseGraphQLWebSockets<RecorderSchema>()
|
||||
.UseGraphQL<RecorderSchema>()
|
||||
.UseGraphQLPlayground()
|
||||
.UseGraphQLGraphiQL()
|
||||
.UseGraphQLAltair()
|
||||
.UseGraphQLVoyager()
|
||||
.Use(next => async context =>
|
||||
{
|
||||
if (context.Request.Path == "/")
|
||||
{
|
||||
await context.Response.WriteAsync(@"<h1>to be done</h1><style>a{margin:5px}</style><a href=""/ui/playground"">Playground</a><a href=""/ui/graphiql"">GraphiQL</a><a href=""/ui/altair"">Altair</a><a href=""/ui/voyager"">Voyager</a>").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Redirect("/");
|
||||
}
|
||||
})
|
||||
;
|
||||
}
|
||||
}
|
9
BililiveRecorder.Web/appsettings.Development.json
Normal file
9
BililiveRecorder.Web/appsettings.Development.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
10
BililiveRecorder.Web/appsettings.json
Normal file
10
BililiveRecorder.Web/appsettings.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
|
@ -29,6 +29,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BililiveRecorder.ToolBox",
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BililiveRecorder.Flv.Tests", "test\BililiveRecorder.Flv.Tests\BililiveRecorder.Flv.Tests.csproj", "{32E554B1-0ECC-4145-85B8-3FC128FEBEA1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BililiveRecorder.Web", "BililiveRecorder.Web\BililiveRecorder.Web.csproj", "{263EC584-AFD5-45C9-8347-127016B3B8F5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BililiveRecorder.Web.Schemas", "BililiveRecorder.Web.Schemas\BililiveRecorder.Web.Schemas.csproj", "{4E72646D-8E25-49E5-B72C-E9749141DBF4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -63,6 +67,14 @@ Global
|
|||
{32E554B1-0ECC-4145-85B8-3FC128FEBEA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{32E554B1-0ECC-4145-85B8-3FC128FEBEA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{32E554B1-0ECC-4145-85B8-3FC128FEBEA1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{263EC584-AFD5-45C9-8347-127016B3B8F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{263EC584-AFD5-45C9-8347-127016B3B8F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{263EC584-AFD5-45C9-8347-127016B3B8F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{263EC584-AFD5-45C9-8347-127016B3B8F5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4E72646D-8E25-49E5-B72C-E9749141DBF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4E72646D-8E25-49E5-B72C-E9749141DBF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4E72646D-8E25-49E5-B72C-E9749141DBF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4E72646D-8E25-49E5-B72C-E9749141DBF4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -75,12 +87,14 @@ Global
|
|||
{521EC763-5694-45A8-B87F-6E6B7F2A3BD4} = {623A2ACC-DAC6-4E6F-9242-B4B54381AAE1}
|
||||
{4FAAE8E7-AC4E-4E99-A7D1-53D20AD8A200} = {2D44A59D-E437-4FEE-8A2E-3FF00D53A64D}
|
||||
{32E554B1-0ECC-4145-85B8-3FC128FEBEA1} = {623A2ACC-DAC6-4E6F-9242-B4B54381AAE1}
|
||||
{263EC584-AFD5-45C9-8347-127016B3B8F5} = {2D44A59D-E437-4FEE-8A2E-3FF00D53A64D}
|
||||
{4E72646D-8E25-49E5-B72C-E9749141DBF4} = {2D44A59D-E437-4FEE-8A2E-3FF00D53A64D}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
RESX_SortFileContentOnSave = True
|
||||
SolutionGuid = {F3CB8B14-077A-458F-BD8E-1747ED0F5170}
|
||||
RESX_NeutralResourcesLanguage = zh-Hans
|
||||
RESX_SaveFilesImmediatelyUponChange = True
|
||||
RESX_ShowErrorsInErrorList = False
|
||||
RESX_SaveFilesImmediatelyUponChange = True
|
||||
RESX_NeutralResourcesLanguage = zh-Hans
|
||||
SolutionGuid = {F3CB8B14-077A-458F-BD8E-1747ED0F5170}
|
||||
RESX_SortFileContentOnSave = True
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -7,7 +7,7 @@ export const data: Array<ConfigEntry> = [
|
|||
type: "int",
|
||||
configType: "roomOnly",
|
||||
defaultValue: "default",
|
||||
// web_readonly: true,
|
||||
webReadonly: true,
|
||||
markdown: ""
|
||||
},
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@ const map: SectionInfoMap = {
|
|||
header: true,
|
||||
build: builderCli
|
||||
},
|
||||
web_is_disabled_for_now: {
|
||||
web: {
|
||||
path: './BililiveRecorder.Web.Schemas/Types/Config.gen.cs',
|
||||
format: true,
|
||||
header: true,
|
||||
|
|
|
@ -1,5 +1,125 @@
|
|||
import { ConfigEntry, ConfigEntryType } from "../types"
|
||||
import { trimEnd } from "../utils";
|
||||
|
||||
export default function (data: ConfigEntry[]): string {
|
||||
return ""
|
||||
let result = `using BililiveRecorder.Core.Config.V2;
|
||||
using GraphQL.Types;
|
||||
using HierarchicalPropertyDefault;
|
||||
#nullable enable
|
||||
namespace BililiveRecorder.Web.Schemas.Types
|
||||
{
|
||||
`;
|
||||
function write_query_graphType_property(r: ConfigEntry) {
|
||||
if (r.configType == "roomOnly") {
|
||||
result += `this.Field(x => x.${r.name});\n`;
|
||||
} else {
|
||||
result += `this.Field(x => x.Optional${r.name}, type: typeof(HierarchicalOptionalType<${trimEnd(r.type, '?')}>));\n`;
|
||||
}
|
||||
}
|
||||
|
||||
function write_mutation_graphType_property(r: ConfigEntry) {
|
||||
if (r.configType == "roomOnly") {
|
||||
result += `this.Field(x => x.${r.name}, nullable: true);\n`;
|
||||
} else {
|
||||
result += `this.Field(x => x.Optional${r.name}, nullable: true, type: typeof(HierarchicalOptionalInputType<${trimEnd(r.type, '?')}>));\n`;
|
||||
}
|
||||
}
|
||||
|
||||
function write_mutation_dataType_property(r: ConfigEntry) {
|
||||
if (r.configType == "roomOnly") {
|
||||
result += `public ${r.type}? ${r.name} { get; set; }\n`;
|
||||
} else {
|
||||
result += `public Optional<${r.type}>? Optional${r.name} { get; set; }\n`;
|
||||
}
|
||||
}
|
||||
|
||||
function write_mutation_apply_method(r: ConfigEntry) {
|
||||
if (r.configType == "roomOnly") {
|
||||
result += `if (this.${r.name}.HasValue) config.${r.name} = this.${r.name}.Value;\n`;
|
||||
} else {
|
||||
result += `if (this.Optional${r.name}.HasValue) config.Optional${r.name} = this.Optional${r.name}.Value;\n`;
|
||||
}
|
||||
}
|
||||
|
||||
{ // ====== RoomConfigType ======
|
||||
result += "internal class RoomConfigType : ObjectGraphType<RoomConfig>\n{\n";
|
||||
result += "public RoomConfigType()\n{\n"
|
||||
|
||||
data.filter(r => r.configType != "globalOnly").forEach(r => write_query_graphType_property(r));
|
||||
|
||||
result += "}\n}\n\n";
|
||||
}
|
||||
|
||||
{ // ====== GlobalConfigType ======
|
||||
result += "internal class GlobalConfigType : ObjectGraphType<GlobalConfig>\n{\n"
|
||||
result += "public GlobalConfigType()\n{\n";
|
||||
|
||||
data.filter(r => r.configType != "roomOnly")
|
||||
.forEach(r => write_query_graphType_property(r));
|
||||
|
||||
result += "}\n}\n\n";
|
||||
}
|
||||
|
||||
{ // ====== DefaultConfigType ======
|
||||
result += "internal class DefaultConfigType : ObjectGraphType<DefaultConfig>\n{\n"
|
||||
result += "public DefaultConfigType()\n{\n";
|
||||
|
||||
data.filter(r => r.configType != "roomOnly")
|
||||
.forEach(r => {
|
||||
result += `this.Field(x => x.${r.name});\n`;
|
||||
});
|
||||
|
||||
result += "}\n}\n\n";
|
||||
}
|
||||
|
||||
{ // ====== SetRoomConfig ======
|
||||
result += "internal class SetRoomConfig\n{\n"
|
||||
|
||||
data.filter(x => x.configType != "globalOnly" && !x.webReadonly)
|
||||
.forEach(r => write_mutation_dataType_property(r));
|
||||
|
||||
result += "\npublic void ApplyTo(RoomConfig config)\n{\n";
|
||||
|
||||
data.filter(x => x.configType != "globalOnly" && !x.webReadonly)
|
||||
.forEach(r => write_mutation_apply_method(r));
|
||||
|
||||
result += "}\n}\n\n";
|
||||
}
|
||||
|
||||
{ // ====== SetRoomConfigType ======
|
||||
result += "internal class SetRoomConfigType : InputObjectGraphType<SetRoomConfig>\n{\n"
|
||||
result += "public SetRoomConfigType()\n{\n";
|
||||
|
||||
data.filter(x => x.configType != "globalOnly" && !x.webReadonly)
|
||||
.forEach(r => write_mutation_graphType_property(r));
|
||||
|
||||
result += "}\n}\n\n";
|
||||
}
|
||||
|
||||
{ // ====== SetGlobalConfig ======
|
||||
result += "internal class SetGlobalConfig\n{\n"
|
||||
|
||||
data.filter(r => r.configType != "roomOnly" && !r.webReadonly)
|
||||
.forEach(r => write_mutation_dataType_property(r));
|
||||
|
||||
result += "\npublic void ApplyTo(GlobalConfig config)\n{\n";
|
||||
|
||||
data.filter(r => r.configType != "roomOnly" && !r.webReadonly)
|
||||
.forEach(r => write_mutation_apply_method(r));
|
||||
|
||||
result += "}\n}\n\n";
|
||||
}
|
||||
|
||||
{ // ====== SetGlobalConfigType ======
|
||||
result += "internal class SetGlobalConfigType : InputObjectGraphType<SetGlobalConfig>\n{\n"
|
||||
result += "public SetGlobalConfigType()\n{\n";
|
||||
|
||||
data.filter(r => r.configType != "roomOnly" && !r.webReadonly)
|
||||
.forEach(r => write_mutation_graphType_property(r));
|
||||
|
||||
result += "}\n}\n\n";
|
||||
}
|
||||
|
||||
result += `}\n`;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,2 @@
|
|||
import { ConfigEntry } from "../types"
|
||||
export { default as code } from "./code"
|
||||
export { default as doc } from "./doc"
|
||||
|
||||
export const core = function (data: Array<ConfigEntry>) {
|
||||
}
|
||||
export const cli = function (data: Array<ConfigEntry>) {
|
||||
}
|
||||
export const web = function (data: Array<ConfigEntry>) {
|
||||
}
|
||||
export const schema = function (data: Array<ConfigEntry>) {
|
||||
}
|
|
@ -1,14 +1,5 @@
|
|||
import { spawn } from "child_process";
|
||||
import { stdout, stderr } from "process";
|
||||
import { writeFileSync } from "fs";
|
||||
import { resolve, dirname } from "path";
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
import { data } from "./data"
|
||||
import * as generators from "./generators"
|
||||
|
||||
const baseDirectory = __dirname
|
||||
|
||||
const argv = process.argv.slice(2)
|
||||
|
||||
switch (argv[0]) {
|
||||
|
|
14
config_gen/package-lock.json
generated
14
config_gen/package-lock.json
generated
|
@ -5,7 +5,7 @@
|
|||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.6.1",
|
||||
"@types/node": "^16.11.26",
|
||||
"ts-node": "^10.2.0",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.3.5"
|
||||
|
@ -57,9 +57,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.6.1",
|
||||
"resolved": "https://registry.nlark.com/@types/node/download/@types/node-16.6.1.tgz?cache=0&sync_timestamp=1628800447602&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-16.6.1.tgz",
|
||||
"integrity": "sha1-ruYse5ZvVfxmx7bfodWNsqYW2mE=",
|
||||
"version": "16.11.26",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-16.11.26.tgz",
|
||||
"integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
|
@ -224,9 +224,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.6.1",
|
||||
"resolved": "https://registry.nlark.com/@types/node/download/@types/node-16.6.1.tgz?cache=0&sync_timestamp=1628800447602&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-16.6.1.tgz",
|
||||
"integrity": "sha1-ruYse5ZvVfxmx7bfodWNsqYW2mE=",
|
||||
"version": "16.11.26",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-16.11.26.tgz",
|
||||
"integrity": "sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn": {
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
"build": "ts-node index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.6.1",
|
||||
"@types/node": "^16.11.26",
|
||||
"ts-node": "^10.2.0",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ export interface ConfigEntry {
|
|||
readonly type: string,
|
||||
/** 设置类型 */
|
||||
readonly configType: ConfigEntryType
|
||||
/** Web API 只读属性 */
|
||||
readonly webReadonly?: boolean,
|
||||
/** 是否为高级设置(隐藏设置),默认为 false */
|
||||
readonly advancedConfig?: boolean,
|
||||
/** 默认值 */
|
||||
|
|
Loading…
Reference in New Issue
Block a user