Skip to content

Commit

Permalink
Add cli tools
Browse files Browse the repository at this point in the history
  • Loading branch information
RicoSuter committed May 20, 2022
1 parent 12f99dd commit 1e8ba66
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 40 deletions.
3 changes: 1 addition & 2 deletions src/HelloSignalR/HelloSignalR.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SigSpec.AspNetCore\SigSpec.AspNetCore.csproj" />
<ProjectReference Include="..\SigSpec.CodeGeneration.TypeScript\SigSpec.CodeGeneration.TypeScript.csproj" />
</ItemGroup>
</Project>
32 changes: 28 additions & 4 deletions src/HelloSignalR/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using NJsonSchema.CodeGeneration.TypeScript;
using SigSpec.CodeGeneration.TypeScript;
using System.IO;

namespace HelloSignalR
{
Expand All @@ -11,16 +14,34 @@ public void ConfigureServices(IServiceCollection services)
services.AddSignalR();

// TODO: Automatically look hubs up
services.AddSigSpecDocument(o => o.Hubs["/chat"] = typeof(ChatHub));
services.AddSigSpecDocument(options =>
{
options.Hubs["/chat"] = typeof(ChatHub);

options.OutputPath = "sigspec.json";
options.CommandLineAction = document => // run cli with "donet run -- --sigspec""
{
var generator = new SigSpecToTypeScriptGenerator(
new SigSpecToTypeScriptGeneratorSettings
{
TypeScriptGeneratorSettings =
{
TypeStyle = TypeScriptTypeStyle.Interface
}
});

var code = generator.GenerateFile(document);
File.WriteAllText("signalr-api.ts", code);
};
});

services.AddCors(c =>
{
c.AddDefaultPolicy(policy =>
{
policy.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin()
.AllowCredentials();
.AllowAnyOrigin();
});
});
}
Expand All @@ -33,10 +54,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseSigSpec();
app.UseSigSpecUi();

app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chat");
endpoints.AddHubsFromSigSpec(app);
});

app.HandleSigSpecCommandLine();
}
}
}
42 changes: 42 additions & 0 deletions src/HelloSignalR/signalr-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { HubConnection, IStreamResult } from "@microsoft/signalr"

export class ChatHub {
constructor(private connection: HubConnection) {
}

send(message: string): Promise<void> {
return this.connection.invoke('Send', message);
}

addPerson(person: Person): Promise<void> {
return this.connection.invoke('AddPerson', person);
}

getEvents(): IStreamResult<Event> {
return this.connection.stream('GetEvents');
}

registerCallbacks(implementation: IChatHubCallbacks) {
this.connection.on('Welcome', () => implementation.welcome());
this.connection.on('Send', (message) => implementation.send(message));
}

unregisterCallbacks(implementation: IChatHubCallbacks) {
this.connection.off('Welcome', () => implementation.welcome());
this.connection.off('Send', (message) => implementation.send(message));
}
}

export interface IChatHubCallbacks {
welcome(): void;
send(message: string): void;
}

export interface Person {
firstName: string | undefined;
lastName: string | undefined;
}

export interface Event {
type: string | undefined;
}
97 changes: 97 additions & 0 deletions src/HelloSignalR/sigspec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"sigspec": "1.0.0",
"info": {
"title": "SigSpec specification",
"version": "1.0.0"
},
"hubs": {
"/chat": {
"name": "Chat",
"description": "",
"operations": {
"Send": {
"description": "",
"parameters": {
"message": {
"type": "string",
"description": ""
}
}
},
"AddPerson": {
"description": "",
"parameters": {
"person": {
"description": "",
"oneOf": [
{
"$ref": "#/definitions/Person"
}
]
}
}
},
"GetEvents": {
"description": "",
"parameters": {},
"returntype": {
"description": "",
"oneOf": [
{
"$ref": "#/definitions/Event"
}
]
},
"type": "Observable"
}
},
"callbacks": {
"Welcome": {
"description": "",
"parameters": {}
},
"Send": {
"description": "",
"parameters": {
"message": {
"type": "string",
"description": ""
}
}
}
}
}
},
"definitions": {
"Person": {
"type": "object",
"additionalProperties": false,
"properties": {
"firstName": {
"type": [
"null",
"string"
]
},
"lastName": {
"type": [
"null",
"string"
]
}
}
},
"Event": {
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"type": [
"null",
"string"
]
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/HelloSignalR/wwwroot/Index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
});

connection.on('Welcome', data => {
alert('Welcome message.');
alert('Welcome message from server.');
});

connection.start().then(() => connection.invoke('send', ''));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using SigSpec.AspNetCore;
using SigSpec.AspNetCore.Middlewares;
Expand Down Expand Up @@ -41,5 +46,54 @@ public static IApplicationBuilder UseSigSpecUi(this IApplicationBuilder app, Act

return app;
}

public static void AddHubsFromSigSpec(this IEndpointRouteBuilder endpoints, IApplicationBuilder app)
{
var method = typeof(HubEndpointRouteBuilderExtensions)
.GetMethod("MapHub", new[] { typeof(IEndpointRouteBuilder), typeof(string) });

var registrations = app.ApplicationServices.GetServices<SigSpecDocumentRegistration>();
foreach (var registration in registrations
.SelectMany(r => r.Hubs)
.GroupBy(p => p.Key)
.Select(p => p.First())
.ToDictionary(p => p.Key, p => p.Value))
{
var specificMethod = method.MakeGenericMethod(new[] { registration.Value });
specificMethod.Invoke(null, new object[] { endpoints, registration.Key });
}
}

/// <summary>
/// Experimental: Handles the --sigspec command line argument and allows extension points to run SigSpec actions.
/// </summary>
/// <param name="app"></param>
/// <param name="processDocument"></param>
/// <returns></returns>
public static IApplicationBuilder HandleSigSpecCommandLine(this IApplicationBuilder app)
{
var args = Environment.GetCommandLineArgs();
if (args.Contains("--sigspec"))
{
var logger = app.ApplicationServices.GetRequiredService<ILogger<SigSpecDocumentRegistration>>();
var registrations = app.ApplicationServices.GetServices<SigSpecDocumentRegistration>();
foreach (var registration in registrations.Where(r => !string.IsNullOrEmpty(r.OutputPath) || r.CommandLineAction != null))
{
var document = registration.GenerateDocumentAsync().GetAwaiter().GetResult();
registration.CommandLineAction?.Invoke(document);

if (!string.IsNullOrEmpty(registration.OutputPath))
{
File.WriteAllText(registration.OutputPath, document.ToJson());
logger.LogInformation("SigSpec document {DocumentName} successfully generated and written to file system {OutputPath}.", registration.DocumentName, registration.OutputPath);
}
}

var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
lifetime.StopApplication();
}

return app;
}
}
}
4 changes: 2 additions & 2 deletions src/SigSpec.AspNetCore/Middlewares/SigSpecMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ private async Task RespondWithSigSpecJsonAsync(HttpResponse response, SigSpecDoc
response.StatusCode = 200;
response.ContentType = "application/json;charset=utf-8";

var json = await registration.GenerateJsonAsync();
await response.WriteAsync(json, new UTF8Encoding(false));
var document = await registration.GenerateDocumentAsync();
await response.WriteAsync(document.ToJson(), new UTF8Encoding(false));
}
}
}
58 changes: 30 additions & 28 deletions src/SigSpec.AspNetCore/SigSpec.AspNetCore.csproj
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<Owners>Rico Suter</Owners>
<Authors>Rico Suter</Authors>
<Description>Specification and code generator for SignalR Core.</Description>
<Version>0.3.0</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageProjectUrl>https://github.com/RicoSuter/SigSpec</PackageProjectUrl>
<RepositoryUrl>https://github.com/RicoSuter/SigSpec.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>SignalR Specification CodeGeneration</PackageTags>
</PropertyGroup>
<ItemGroup>
<None Remove="SigSpecUi\index.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="SigSpecUi\index.html" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SigSpec.Core\SigSpec.Core.csproj" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<Owners>Rico Suter</Owners>
<Authors>Rico Suter</Authors>
<Description>Specification and code generator for SignalR Core.</Description>
<Version>0.3.0</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageProjectUrl>https://github.com/RicoSuter/SigSpec</PackageProjectUrl>
<RepositoryUrl>https://github.com/RicoSuter/SigSpec.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>SignalR Specification CodeGeneration</PackageTags>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<None Remove="SigSpecUi\index.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="SigSpecUi\index.html" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.4" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SigSpec.Core\SigSpec.Core.csproj" />
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions src/SigSpec.AspNetCore/SigSpecDocumentGeneratorSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ public class SigSpecDocumentGeneratorSettings : SigSpecGeneratorSettings
{
public string DocumentName { get; set; } = "v1";

public string OutputPath { get; set; }

public Action<SigSpecDocument> CommandLineAction { get; set; }

public Dictionary<string, Type> Hubs { get; set; } = new Dictionary<string, Type>();

public SigSpecDocument Template { get; set; } = new SigSpecDocument();
Expand Down
Loading

0 comments on commit 1e8ba66

Please sign in to comment.