native aot in container

This commit is contained in:
Vinzenz Schroeter 2024-04-10 22:03:36 +02:00
parent 0ca6a91a7e
commit 85ae3e302c
11 changed files with 128 additions and 61 deletions

View file

@ -23,3 +23,4 @@
**/values.dev.yaml **/values.dev.yaml
LICENSE LICENSE
README.md README.md
**/node_modules

38
Dockerfile Normal file
View file

@ -0,0 +1,38 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build-server
RUN apk add clang binutils musl-dev build-base zlib-static cmake openssl-dev openssl-libs-static openssl
WORKDIR /src/TanksServer
# dependencies
COPY TanksServer/TanksServer.csproj .
RUN dotnet restore --runtime linux-musl-x64 TanksServer.csproj
#build
COPY TanksServer .
RUN dotnet build TanksServer.csproj -c Release -o /app/build
RUN dotnet publish TanksServer.csproj -r linux-musl-x64 -c Release -o /app/publish
FROM node:21-alpine AS build-client
WORKDIR /app
# dependencies
COPY tank-frontend/package.json .
COPY tank-frontend/package-lock.json .
RUN npm i
# build
env CONTAINERMODE 1
COPY tank-frontend .
RUN npm run build
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-alpine AS final
WORKDIR /app
COPY --from=build-server /app/publish .
COPY --from=build-client /app/dist ./client
EXPOSE 80
ENTRYPOINT ./TanksServer

View file

@ -1,20 +0,0 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["TanksServer/TanksServer.csproj", "TanksServer/"]
RUN dotnet restore "TanksServer/TanksServer.csproj"
COPY . .
WORKDIR "/src/TanksServer"
RUN dotnet build "TanksServer.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "TanksServer.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TanksServer.dll"]

View file

@ -1,3 +1,5 @@
using System.Text.Json.Serialization;
namespace TanksServer.Models; namespace TanksServer.Models;
internal sealed class Player(string name) internal sealed class Player(string name)
@ -6,18 +8,10 @@ internal sealed class Player(string name)
public Guid Id { get; } = Guid.NewGuid(); public Guid Id { get; } = Guid.NewGuid();
[JsonIgnore]
public PlayerControls Controls { get; } = new(); public PlayerControls Controls { get; } = new();
public int Kills { get; set; } public int Kills { get; set; }
public int Deaths { get; set; } public int Deaths { get; set; }
} }
internal sealed class PlayerControls
{
public bool Forward { get; set; }
public bool Backward { get; set; }
public bool TurnLeft { get; set; }
public bool TurnRight { get; set; }
public bool Shoot { get; set; }
}

View file

@ -0,0 +1,10 @@
namespace TanksServer.Models;
internal sealed class PlayerControls
{
public bool Forward { get; set; }
public bool Backward { get; set; }
public bool TurnLeft { get; set; }
public bool TurnRight { get; set; }
public bool Shoot { get; set; }
}

View file

@ -11,15 +11,12 @@ using TanksServer.ServicePointDisplay;
namespace TanksServer; namespace TanksServer;
internal static class Program public static class Program
{ {
public static async Task Main(string[] args) public static void Main(string[] args)
{ {
var app = Configure(args); var app = Configure(args);
app.UseCors();
app.UseWebSockets();
var clientScreenServer = app.Services.GetRequiredService<ClientScreenServer>(); var clientScreenServer = app.Services.GetRequiredService<ClientScreenServer>();
var playerService = app.Services.GetRequiredService<PlayerServer>(); var playerService = app.Services.GetRequiredService<PlayerServer>();
var controlsServer = app.Services.GetRequiredService<ControlsServer>(); var controlsServer = app.Services.GetRequiredService<ControlsServer>();
@ -52,10 +49,10 @@ internal static class Program
using var ws = await context.WebSockets.AcceptWebSocketAsync(); using var ws = await context.WebSockets.AcceptWebSocketAsync();
await controlsServer.HandleClient(ws, player); await controlsServer.HandleClient(ws, player);
return Results.Empty; return Results.Ok();
}); });
await app.RunAsync(); app.Run();
} }
private static WebApplication Configure(string[] args) private static WebApplication Configure(string[] args)
@ -74,7 +71,7 @@ internal static class Program
options.SerializerOptions.TypeInfoResolverChain.Insert(0, new AppSerializerContext()); options.SerializerOptions.TypeInfoResolverChain.Insert(0, new AppSerializerContext());
}); });
builder.Services.AddOptions(); builder.Services.AddHttpLogging(_ => { });
builder.Services.AddSingleton<MapService>(); builder.Services.AddSingleton<MapService>();
builder.Services.AddSingleton<BulletManager>(); builder.Services.AddSingleton<BulletManager>();
@ -107,6 +104,12 @@ internal static class Program
builder.Services.Configure<ServicePointDisplayConfiguration>( builder.Services.Configure<ServicePointDisplayConfiguration>(
builder.Configuration.GetSection("ServicePointDisplay")); builder.Configuration.GetSection("ServicePointDisplay"));
return builder.Build(); var app = builder.Build();
app.UseCors();
app.UseWebSockets();
app.UseHttpLogging();
return app;
} }
} }

View file

@ -14,6 +14,7 @@ internal sealed class SendToServicePointDisplay : ITickStep, IDisposable
private readonly TextDisplayBuffer _scoresBuffer; private readonly TextDisplayBuffer _scoresBuffer;
private readonly PlayerServer _players; private readonly PlayerServer _players;
private readonly ILogger<SendToServicePointDisplay> _logger; private readonly ILogger<SendToServicePointDisplay> _logger;
private DateTime _nextFailLog = DateTime.Now;
private const int ScoresWidth = 12; private const int ScoresWidth = 12;
private const int ScoresHeight = 20; private const int ScoresHeight = 20;
@ -70,7 +71,11 @@ internal sealed class SendToServicePointDisplay : ITickStep, IDisposable
} }
catch (SocketException ex) catch (SocketException ex)
{ {
_logger.LogWarning(ex, "could not send data to service point display"); if (DateTime.Now > _nextFailLog)
{
_logger.LogWarning("could not send data to service point display: {}", ex.Message);
_nextFailLog = DateTime.Now + TimeSpan.FromSeconds(5);
}
} }
} }
} }

View file

@ -5,25 +5,41 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization> <InvariantGlobalization>true</InvariantGlobalization>
<PublishAot>true</PublishAot>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Content Include="..\.dockerignore">
<Link>.dockerignore</Link>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
</ItemGroup>
<PropertyGroup> <PropertyGroup>
<AnalysisMode>Recommended</AnalysisMode> <AnalysisMode>Recommended</AnalysisMode>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>CA1805,CA1848</NoWarn> <NoWarn>CA1805,CA1848</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<IsAotCompatible>true</IsAotCompatible>
<PublishAot>true</PublishAot>
<IlcDisableReflection>false</IlcDisableReflection>
<InvariantGlobalization>true</InvariantGlobalization>
<StaticExecutable>true</StaticExecutable>
<StripSymbols>true</StripSymbols>
<StaticallyLinked>true</StaticallyLinked>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0"/>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3"/>
</ItemGroup>
<ItemGroup>
<None Include="./assets/tank.png" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" />
<Content Include="../Dockerfile">
<Link>..\Dockerfile</Link>
</Content>
<Content Include="../.dockerignore">
<Link>../Dockerfile</Link>
</Content>
<Content Include="../Makefile" />
</ItemGroup>
</Project> </Project>

View file

@ -13,6 +13,7 @@
"react-use-websocket": "^4.8.1" "react-use-websocket": "^4.8.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.12.7",
"@types/react": "^18.2.66", "@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22", "@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/eslint-plugin": "^7.2.0",
@ -1240,6 +1241,15 @@
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true "dev": true
}, },
"node_modules/@types/node": {
"version": "20.12.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@types/prop-types": { "node_modules/@types/prop-types": {
"version": "15.7.12", "version": "15.7.12",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
@ -3143,6 +3153,12 @@
"node": ">=14.17" "node": ">=14.17"
} }
}, },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.0.13", "version": "1.0.13",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",

View file

@ -15,6 +15,7 @@
"react-use-websocket": "^4.8.1" "react-use-websocket": "^4.8.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.12.7",
"@types/react": "^18.2.66", "@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22", "@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/eslint-plugin": "^7.2.0",

View file

@ -1,12 +1,15 @@
import {defineConfig} from 'vite'; import {ConfigEnv, defineConfig} from 'vite';
import react from '@vitejs/plugin-react'; import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig(() => {
const isContainer = process.env.CONTAINERMODE;
return {
plugins: [react()], plugins: [react()],
build: { build: {
outDir: '../TanksServer/client', outDir: isContainer ? undefined : '../TanksServer/client',
emptyOutDir: true emptyOutDir: true
} }
};
}); });