chore: ci jobs expanded & .net 8 support
All checks were successful
Build, Package and Push Images / preprocess (push) Successful in 1s
Build, Package and Push Images / build (push) Successful in 26s
Build, Package and Push Images / sbom-scan (push) Successful in 39s
Build, Package and Push Images / sonarqube (push) Successful in 1m21s
Build, Package and Push Images / container-build (push) Successful in 1m30s
Build, Package and Push Images / container-sbom-scan (push) Successful in 37s

ci: branch name sanitization for docker

ci: another attempt

ci: forgot actor

chore: remove nuke remnants

chore(deps): update dependency dotnet-sdk to v7.0.403

Signed-off-by: noreply@rainote.dev

refactor: shared data into library

refactor: rewrite for packethandler/id map

chore: logging

chore: Sonar Warnings

chore: upgrade to .net8 image

chore: fetch all required information for characters

chore: upgrade to .net 8

ci: install .net 7.0 alongside 8.0 for sbom

fix: incorrect job

ci: let's try arm64 again

ci: adjust project for .net 8 support

chore: adjustments to composefile

chore: analyzer setup

chore: analyzer and project settings updated
This commit is contained in:
Timothy Schenk 2023-11-04 10:18:58 +01:00
parent 1d91fe75f7
commit dc6d8316e9
28 changed files with 254 additions and 246 deletions

View file

@ -13,6 +13,11 @@
; This is the default for the codeline. ; This is the default for the codeline.
root = true root = true
; For disabling MA0048 and MA0051 in a specific folder, e.g., Migrations
[**/Migrations/*.cs]
dotnet_diagnostic.MA0048.severity = none
dotnet_diagnostic.MA0051.severity = none
[*] [*]
indent_style = space indent_style = space
charset = utf-8 charset = utf-8

View file

@ -1,24 +1,34 @@
name: Build and Deploy name: Build, Package and Push Images
run-name: ${{ gitea.actor }} is building the Server application run-name: ${{ gitea.actor }} is building the Server application
on: [ push ] on: [ push ]
jobs: jobs:
build-server: preprocess:
runs-on: ubuntu-latest
outputs:
sanitized_branch_name: ${{ steps.sanitize.outputs.sanitized_branch_name }}
steps:
- name: Sanitize branch name
id: sanitize
run: echo "::set-output name=sanitized_branch_name::$(echo ${{ github.ref_name }} | sed 's/\//-/g')"
build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup dotnet - name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3 uses: https://github.com/actions/setup-dotnet@v3
with: with:
dotnet-version: 7.0 dotnet-version: 8.0
- name: Install dependencies - name: Install dependencies
run: dotnet restore run: dotnet restore
- name: Build - name: Build
run: | run: |
dotnet build Server -c Release dotnet build Server -c Release
# dotnet test Server.Tests -c Release # dotnet test Server.Tests -c Release
sonarqube: sonarqube:
needs: build-server needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.ref_name == 'master' if: github.ref_name == 'master'
steps: steps:
@ -26,7 +36,7 @@ jobs:
- name: Setup dotnet - name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3 uses: https://github.com/actions/setup-dotnet@v3
with: with:
dotnet-version: 7.0 dotnet-version: 8.0
- name: Install dependencies - name: Install dependencies
run: | run: |
dotnet restore dotnet restore
@ -48,15 +58,18 @@ jobs:
- name: Sonarqube End - name: Sonarqube End
run: | run: |
dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
dependency-track:
needs: build-server sbom-scan:
needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup dotnet - name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3 uses: https://github.com/actions/setup-dotnet@v3
with: with:
dotnet-version: 7.0 dotnet-version: |
7.0
8.0
- name: Install dependencies - name: Install dependencies
run: | run: |
dotnet restore dotnet restore
@ -77,16 +90,17 @@ jobs:
# set projectversion to be the branch name # set projectversion to be the branch name
projectVersion: "${{ github.ref_name }}" projectVersion: "${{ github.ref_name }}"
bomFilename: "${{ github.workspace }}/bom.xml" bomFilename: "${{ github.workspace }}/bom.xml"
build-push-server-container:
container-build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest container: catthehacker/ubuntu:act-latest
needs: build-server needs: [ build, preprocess ]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup dotnet - name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3 uses: https://github.com/actions/setup-dotnet@v3
with: with:
dotnet-version: 7.0 dotnet-version: 8.0
# Add support for more platforms with QEMU (optional) # Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action # https://github.com/docker/setup-qemu-action
- name: Set up QEMU - name: Set up QEMU
@ -97,7 +111,7 @@ jobs:
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: ${{ github.server_url }} registry: ${{ github.server_url }}
username: ${{ secrets.REGISTRY_USERNAME }} username: ${{ github.actor }}
password: ${{ secrets.REGISTRY_TOKEN }} password: ${{ secrets.REGISTRY_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
@ -105,10 +119,20 @@ jobs:
context: . context: .
file: Server/Dockerfile file: Server/Dockerfile
push: true push: true
tags: forge.rainote.dev/${{ github.repository }}:${{ github.ref_name }} tags: forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }}
platforms: linux/amd64 platforms: linux/amd64,linux/arm64
dependency-track-container: - name: Build and push to latest
needs: build-push-server-container if: github.ref_name == 'master'
uses: docker/build-push-action@v5
with:
context: .
file: Server/Dockerfile
push: true
tags: forge.rainote.dev/${{ github.repository }}:latest
platforms: linux/amd64, linux/arm64
container-sbom-scan:
needs: [ container-build, preprocess ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest container: catthehacker/ubuntu:act-latest
steps: steps:
@ -116,7 +140,7 @@ jobs:
- name: Setup dotnet - name: Setup dotnet
uses: https://github.com/actions/setup-dotnet@v3 uses: https://github.com/actions/setup-dotnet@v3
with: with:
dotnet-version: 7.0 dotnet-version: 8.0
- name: Install dependencies - name: Install dependencies
run: | run: |
dotnet restore dotnet restore
@ -129,11 +153,11 @@ jobs:
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: ${{ github.server_url }} registry: ${{ github.server_url }}
username: ${{ secrets.REGISTRY_USERNAME }} username: ${{ github.actor }}
password: ${{ secrets.REGISTRY_TOKEN }} password: ${{ secrets.REGISTRY_TOKEN }}
- name: Generate SBOM - name: Generate SBOM
run: | run: |
docker sbom forge.rainote.dev/${{ github.repository }}:${{ github.ref_name }} --format cyclonedx-json --output bom.json docker sbom forge.rainote.dev/${{ github.repository }}:${{ needs.preprocess.outputs.sanitized_branch_name }} --format cyclonedx-json --output bom.json
- name: Upload SBOM - name: Upload SBOM
uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1 uses: https://github.com/DependencyTrack/gh-upload-sbom@v2.0.1
with: with:
@ -144,3 +168,4 @@ jobs:
# set projectversion to be the branch name # set projectversion to be the branch name
projectVersion: "${{ github.ref_name }}" projectVersion: "${{ github.ref_name }}"
bomFilename: "${{ github.workspace }}/bom.json" bomFilename: "${{ github.workspace }}/bom.json"

View file

@ -10,6 +10,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.10" /> <PackageReference Include="BenchmarkDotNet" Version="0.13.10" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.104">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -14,7 +14,7 @@ using BenchmarkDotNet.Order;
[ThreadingDiagnoser] [ThreadingDiagnoser]
public class BinaryConversionBenchmarks public class BinaryConversionBenchmarks
{ {
private byte[] _data; private byte[] _data = null!;
private int _offset; private int _offset;
[GlobalSetup] [GlobalSetup]

View file

@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csp
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{7D560FA1-A61C-4B67-8300-835CA5814621}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{7D560FA1-A61C-4B67-8300-835CA5814621}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wonderking", "Wonderking\Wonderking.csproj", "{6B53A10B-C397-4347-BB00-A12272D0528E}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -18,5 +20,9 @@ Global
{7D560FA1-A61C-4B67-8300-835CA5814621}.Debug|Any CPU.Build.0 = Debug|Any CPU {7D560FA1-A61C-4B67-8300-835CA5814621}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.Build.0 = Release|Any CPU {7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.Build.0 = Release|Any CPU
{6B53A10B-C397-4347-BB00-A12272D0528E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B53A10B-C397-4347-BB00-A12272D0528E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B53A10B-C397-4347-BB00-A12272D0528E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B53A10B-C397-4347-BB00-A12272D0528E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View file

@ -1,3 +1,5 @@
using Wonderking.Packets;
namespace Server; namespace Server;
using System.Reflection; using System.Reflection;

View file

@ -1,18 +1,28 @@
FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base FROM mcr.microsoft.com/dotnet/runtime:8.0-bookworm-slim AS base
WORKDIR /app WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim AS build
ARG TARGETARCH
ENV TZ=Etc/UTC
ENV DOTNET_TieredPGO=1
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
RUN echo "Target: $TARGETARCH"
RUN echo "Build: $BUILDPLATFORM"
WORKDIR /src WORKDIR /src
COPY ["Wonderking/Wonderking.csproj", "Wonderking/"]
COPY ["Server/Server.csproj", "Server/"] COPY ["Server/Server.csproj", "Server/"]
RUN dotnet restore "Server/Server.csproj" RUN dotnet restore "Wonderking/Wonderking.csproj" -a $TARGETARCH
RUN dotnet restore "Server/Server.csproj" -a $TARGETARCH
COPY . . COPY . .
WORKDIR "/src/Server"
RUN dotnet build "Server.csproj" -c Release -o /app/build
FROM build AS publish FROM build AS publish
RUN dotnet publish "Server.csproj" -c Release -o /app/publish /p:UseAppHost=false RUN dotnet publish "Server/Server.csproj" -c Release -a $TARGETARCH --no-restore -f net8.0 -o /app
FROM base AS final FROM base AS final
WORKDIR /app WORKDIR /app
COPY --from=publish /app/publish . COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Server.dll"] USER $APP_UID
ENTRYPOINT ["./Server"]

View file

@ -1,8 +1,8 @@
namespace Server;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Packets; using Wonderking.Packets;
namespace Server.LoggerMessages;
public static partial class PacketLoggerMessages public static partial class PacketLoggerMessages
{ {

View file

@ -1,10 +1,12 @@
using Microsoft.EntityFrameworkCore;
using Wonderking.Packets.Incoming;
namespace Server.PacketHandlers; namespace Server.PacketHandlers;
using DB; using DB;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NetCoreServer; using NetCoreServer;
using Packets.Incoming;
public class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket> public class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket>
{ {
@ -27,7 +29,9 @@ public class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket>
public Task HandleAsync(ChannelSelectionPacket packet, TcpSession session) public Task HandleAsync(ChannelSelectionPacket packet, TcpSession session)
{ {
var authSession = (AuthSession)session; var authSession = (AuthSession)session;
var charactersOfAccount = this._wonderkingContext.Accounts.FirstOrDefault(a => a.Id == authSession.AccountId); var charactersOfAccount = this._wonderkingContext.Accounts.Include(account => account.Characters)
.FirstOrDefault(a => a.Id == authSession.AccountId)
?.Characters;
return Task.CompletedTask; return Task.CompletedTask;
} }
} }

View file

@ -1,8 +1,9 @@
using Wonderking.Packets;
namespace Server.PacketHandlers; namespace Server.PacketHandlers;
using JetBrains.Annotations; using JetBrains.Annotations;
using NetCoreServer; using NetCoreServer;
using Packets;
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public interface IPacketHandler<in T> where T : IPacket public interface IPacketHandler<in T> where T : IPacket

View file

@ -1,15 +1,16 @@
namespace Server.PacketHandlers;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using Wonderking.Packets.Incoming;
using Wonderking.Packets.Outgoing;
namespace Server.PacketHandlers;
using DB; using DB;
using DB.Documents; using DB.Documents;
using Konscious.Security.Cryptography; using Konscious.Security.Cryptography;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NetCoreServer; using NetCoreServer;
using Packets.Incoming;
using Packets.Outgoing;
public class LoginHandler : IPacketHandler<LoginInfoPacket> public class LoginHandler : IPacketHandler<LoginInfoPacket>
{ {
@ -78,13 +79,10 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket>
IsGameMaster = true IsGameMaster = true
}; };
var sess = session as AuthSession; var sess = session as AuthSession;
if (account != null) if (account != null && sess != null)
{
if (sess != null)
{ {
sess.AccountId = account.Id; sess.AccountId = account.Id;
} }
}
sess?.Send(loginResponsePacket); sess?.Send(loginResponsePacket);
} }

View file

@ -1,3 +1,5 @@
using Wonderking.Packets;
namespace Server.Packets; namespace Server.Packets;
using MassTransit; using MassTransit;

View file

@ -2,13 +2,32 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>warnings</Nullable> <Nullable>warnings</Nullable>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<RootNamespace>Server</RootNamespace> <RootNamespace>Server</RootNamespace>
<LangVersion>default</LangVersion> <LangVersion>default</LangVersion>
<ServerGarbageCollection>true</ServerGarbageCollection> <ServerGarbageCollection>true</ServerGarbageCollection>
<TargetFrameworks>net8.0;net7.0</TargetFrameworks>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<Features>strict</Features>
<Authors>Timothy (RaiNote) Schenk</Authors>
<Copyright>Timothy (RaiNote) Schenk</Copyright>
<PackageProjectUrl>https://forge.rainote.dev/wonderking/continuity</PackageProjectUrl>
<RepositoryUrl>https://forge.rainote.dev/wonderking/continuity</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<GenerateDocumentationFile>False</GenerateDocumentationFile>
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<AnalysisLevel>latest-recommended</AnalysisLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
<WarningLevel>7</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
<WarningLevel>7</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -18,23 +37,32 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="DotNext" Version="4.15.0" /> <PackageReference Include="DotNext" Version="4.15.0" />
<PackageReference Include="DotNext.IO" Version="4.15.0" /> <PackageReference Include="DotNext.IO" Version="4.15.0" />
<PackageReference Include="DotNext.Metaprogramming" Version="4.15.0" /> <PackageReference Include="DotNext.Metaprogramming" Version="4.15.0" />
<PackageReference Include="DotNext.Reflection" Version="4.9.0" /> <PackageReference Include="DotNext.Reflection" Version="4.9.0" />
<PackageReference Include="DotNext.Threading" Version="4.14.2" /> <PackageReference Include="DotNext.Threading" Version="4.14.2" />
<PackageReference Include="DotNext.Unsafe" Version="4.14.0" /> <PackageReference Include="DotNext.Unsafe" Version="4.14.0" />
<PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="JetBrains.Annotations" Version="2023.2.0" /> <PackageReference Include="JetBrains.Annotations" Version="2023.2.0" />
<PackageReference Include="JetBrains.ExternalAnnotations" Version="10.2.134" />
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0" /> <PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.0" />
<PackageReference Include="MassTransit" Version="8.1.1" /> <PackageReference Include="MassTransit" Version="8.1.1" />
<PackageReference Include="MassTransit.Analyzers" Version="8.1.1"> <PackageReference Include="MassTransit.Analyzers" Version="8.1.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.104">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0-preview1.23165.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.13" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="7.0.13" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="7.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="7.0.13" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="7.0.13" />
@ -45,6 +73,10 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.7.30">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NetCoreServer" Version="7.0.0" /> <PackageReference Include="NetCoreServer" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
@ -57,10 +89,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" /> <PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.12.0.78982">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -68,4 +96,15 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wonderking\Wonderking.csproj" />
</ItemGroup>
</Project> </Project>

View file

@ -1,3 +1,6 @@
using Server.LoggerMessages;
using Wonderking.Packets;
namespace Server.Services; namespace Server.Services;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@ -26,13 +29,10 @@ public class PacketDistributorService : IHostedService
private readonly ILogger<PacketDistributorService> _logger; private readonly ILogger<PacketDistributorService> _logger;
private readonly ConcurrentDictionary<OperationCode, object> _packetHandlersInstantiation; private readonly ConcurrentDictionary<OperationCode, object> _packetHandlersInstantiation;
private readonly IServiceProvider _serviceProvider;
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider) public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
{ {
this._concurrentQueue = new ConcurrentQueue<RawPacket>(); this._concurrentQueue = new ConcurrentQueue<RawPacket>();
this._logger = logger; this._logger = logger;
this._serviceProvider = serviceProvider;
var tempDeserializationMap = var tempDeserializationMap =
new Dictionary<OperationCode, Func<byte[], IPacket>>(); new Dictionary<OperationCode, Func<byte[], IPacket>>();
@ -43,7 +43,7 @@ public class PacketDistributorService : IHostedService
packetHandlers.ForEach(x => packetHandlers.ForEach(x =>
{ {
var packetHandler = var packetHandler =
ActivatorUtilities.GetServiceOrCreateInstance(this._serviceProvider, ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider,
x.Value); x.Value);
this._packetHandlersInstantiation.TryAdd(x.Key, packetHandler); this._packetHandlersInstantiation.TryAdd(x.Key, packetHandler);
}); });
@ -92,12 +92,24 @@ public class PacketDistributorService : IHostedService
private Dictionary<OperationCode, Type> GetAllPacketHandlersWithId(Assembly assembly) private Dictionary<OperationCode, Type> GetAllPacketHandlersWithId(Assembly assembly)
{ {
var packetHandlersWithId = assembly.GetTypes().AsParallel().Where(t => // ! : We are filtering if types that don't have an instance of the required Attribute
t is { IsClass: true, IsAbstract: false } && t var packetHandlersWithId = assembly.GetTypes().AsParallel()
.GetInterfaces().Any(i => .Where(t =>
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketHandler<>))).ToDictionary(type => type.GetInterfaces().First(t => t is { IsClass: true, IsAbstract: false } && Array.Exists(t
t is { IsGenericType: true } && t.GetGenericTypeDefinition() == typeof(IPacketHandler<>)) .GetInterfaces(), i =>
.GetGenericArguments().First().GetCustomAttribute<PacketIdAttribute>().Code); i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketHandler<>)))
.Select(type => new
{
Type = type,
PacketId = type
.GetInterfaces().First(t1 =>
t1 is { IsGenericType: true } && t1.GetGenericTypeDefinition() == typeof(IPacketHandler<>))
.GetGenericArguments()[0].GetCustomAttribute<PacketIdAttribute>()?.Code
})
.Where(x => x.PacketId is not null)
.ToDictionary(
x => x.PacketId!.Value, x => x.Type
);
if (packetHandlersWithId is not { Count: 0 }) if (packetHandlersWithId is not { Count: 0 })
{ {
@ -136,7 +148,8 @@ public class PacketDistributorService : IHostedService
var packet = value(item.MessageBody); var packet = value(item.MessageBody);
this._logger.PacketData(JsonConvert.SerializeObject(packet)); this._logger.PacketData(JsonConvert.SerializeObject(packet));
this._packetHandlersInstantiation[item.OperationCode].GetType().GetMethod(nameof(IPacketHandler<IPacket>.HandleAsync)) this._packetHandlersInstantiation[item.OperationCode].GetType()
.GetMethod(nameof(IPacketHandler<IPacket>.HandleAsync))
?.Invoke(this._packetHandlersInstantiation[item.OperationCode], new object[] { packet, item.Session }); ?.Invoke(this._packetHandlersInstantiation[item.OperationCode], new object[] { packet, item.Session });
this._logger.PacketFinished(item.Session.Id, item.OperationCode); this._logger.PacketFinished(item.Session.Id, item.OperationCode);

View file

@ -1,6 +1,9 @@
services: services:
server: server:
container_name: continuity-server
image: server:latest image: server:latest
depends_on:
- db
environment: environment:
- ENVIRONMENT=Development - ENVIRONMENT=Development
- Testing:CreateAccountOnLogin=true - Testing:CreateAccountOnLogin=true
@ -14,6 +17,7 @@
- "10001:10001" - "10001:10001"
db: db:
container_name: continuity-db
image: postgres:16.0-alpine image: postgres:16.0-alpine
environment: environment:
- POSTGRES_USER=continuity - POSTGRES_USER=continuity
@ -23,6 +27,11 @@
- continuity - continuity
volumes: volumes:
- db-data:/var/lib/postgresql/data - db-data:/var/lib/postgresql/data
healthcheck:
test: [ "CMD-SHELL", "sh -c 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}'" ]
interval: 10s
timeout: 3s
retries: 3
networks: networks:
continuity: continuity:

View file

@ -1,7 +1,7 @@
namespace Server.Packets;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Wonderking.Packets;
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public interface IPacket public interface IPacket
{ {

View file

@ -1,4 +1,4 @@
namespace Server.Packets.Incoming; namespace Wonderking.Packets.Incoming;
[PacketId(OperationCode.ChannelSelection)] [PacketId(OperationCode.ChannelSelection)]
public class ChannelSelectionPacket : IPacket public class ChannelSelectionPacket : IPacket
@ -12,5 +12,5 @@ public class ChannelSelectionPacket : IPacket
this.ChannelId = BitConverter.ToUInt16(data, 2); this.ChannelId = BitConverter.ToUInt16(data, 2);
} }
public byte[] Serialize() => throw new NotImplementedException(); public byte[] Serialize() => throw new NotSupportedException();
} }

View file

@ -1,7 +1,7 @@
namespace Server.Packets.Incoming;
using System.Text; using System.Text;
namespace Wonderking.Packets.Incoming;
[PacketId(OperationCode.LoginInfo)] [PacketId(OperationCode.LoginInfo)]
public class LoginInfoPacket : IPacket public class LoginInfoPacket : IPacket
{ {

View file

@ -1,4 +1,4 @@
namespace Server.Packets; namespace Wonderking.Packets;
public enum OperationCode : ushort public enum OperationCode : ushort
{ {

View file

@ -1,4 +1,4 @@
namespace Server.Packets.Outgoing; namespace Wonderking.Packets.Outgoing;
[PacketId(OperationCode.LoginResponse)] [PacketId(OperationCode.LoginResponse)]
public class LoginResponsePacket : IPacket public class LoginResponsePacket : IPacket

View file

@ -1,4 +1,4 @@
namespace Server.Packets.Outgoing; namespace Wonderking.Packets.Outgoing;
public enum LoginResponseReason : byte public enum LoginResponseReason : byte
{ {

View file

@ -1,5 +1,8 @@
namespace Server.Packets.Outgoing; using System.Runtime.InteropServices;
namespace Wonderking.Packets.Outgoing;
[StructLayout(LayoutKind.Auto)]
public struct ServerChannelData public struct ServerChannelData
{ {
public ushort ServerId { get; set; } public ushort ServerId { get; set; }

View file

@ -1,4 +1,4 @@
namespace Server.Packets; namespace Wonderking.Packets;
[AttributeUsage(AttributeTargets.Class, Inherited = false)] [AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class PacketIdAttribute : Attribute public class PacketIdAttribute : Attribute

View file

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TargetFrameworks>net8.0;net7.0</TargetFrameworks>
<Features>strict</Features>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="JetBrains.Annotations" Version="2023.2.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.104">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0-preview1.23165.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.7.30">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.10.4539">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View file

@ -1,7 +0,0 @@
:; set -eo pipefail
:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
:; ${SCRIPT_DIR}/build.sh "$@"
:; exit $?
@ECHO OFF
powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*

View file

@ -1,74 +0,0 @@
[CmdletBinding()]
Param(
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$BuildArguments
)
Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
###########################################################################
# CONFIGURATION
###########################################################################
$BuildProjectFile = "$PSScriptRoot\build\build.csproj"
$TempDirectory = "$PSScriptRoot\\.nuke\temp"
$DotNetGlobalFile = "$PSScriptRoot\\global.json"
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
$DotNetChannel = "STS"
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
$env:DOTNET_MULTILEVEL_LOOKUP = 0
###########################################################################
# EXECUTION
###########################################################################
function ExecSafe([scriptblock] $cmd) {
& $cmd
if ($LASTEXITCODE) { exit $LASTEXITCODE }
}
# If dotnet CLI is installed globally and it matches requested version, use for execution
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
$(dotnet --version) -and $LASTEXITCODE -eq 0) {
$env:DOTNET_EXE = (Get-Command "dotnet").Path
}
else {
# Download install script
$DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
# If global.json exists, load expected version
if (Test-Path $DotNetGlobalFile) {
$DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
$DotNetVersion = $DotNetGlobal.sdk.version
}
}
# Install by channel or version
$DotNetDirectory = "$TempDirectory\dotnet-win"
if (!(Test-Path variable:DotNetVersion)) {
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
} else {
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
}
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
}
Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"
if (Test-Path env:NUKE_ENTERPRISE_TOKEN) {
& $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null
& $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null
}
ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }

View file

@ -1,66 +0,0 @@
#!/usr/bin/env bash
bash --version 2>&1 | head -n 1
set -eo pipefail
SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
###########################################################################
# CONFIGURATION
###########################################################################
BUILD_PROJECT_FILE="$SCRIPT_DIR/build/build.csproj"
TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
DOTNET_CHANNEL="STS"
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
export DOTNET_MULTILEVEL_LOOKUP=0
###########################################################################
# EXECUTION
###########################################################################
function FirstJsonValue {
perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
}
# If dotnet CLI is installed globally and it matches requested version, use for execution
if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
export DOTNET_EXE="$(command -v dotnet)"
else
# Download install script
DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
mkdir -p "$TEMP_DIRECTORY"
curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
chmod +x "$DOTNET_INSTALL_FILE"
# If global.json exists, load expected version
if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
if [[ "$DOTNET_VERSION" == "" ]]; then
unset DOTNET_VERSION
fi
fi
# Install by channel or version
DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
if [[ -z ${DOTNET_VERSION+x} ]]; then
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
else
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
fi
export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
fi
echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"
if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then
"$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true
"$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true
fi
"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"

View file

@ -1,6 +1,6 @@
{ {
"sdk": { "sdk": {
"version": "7.0.0", "version": "7.0.403",
"rollForward": "latestMajor", "rollForward": "latestMajor",
"allowPrerelease": true "allowPrerelease": true
} }