Skip to content

Commit

Permalink
WIP: Separate Reloaded.Utils.Server Mod for Services
Browse files Browse the repository at this point in the history
  • Loading branch information
Sewer56 committed Jul 23, 2022
1 parent 32d5e13 commit 37c26fd
Show file tree
Hide file tree
Showing 71 changed files with 2,492 additions and 819 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/build-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ jobs:

- name: Setup AutoChangelog
run: npm install -g auto-changelog

- name: Setup Dotnet SDK (5.0)
uses: actions/setup-dotnet@v2
with:
dotnet-version: '5.0.x'
include-prerelease: true

- name: Setup Dotnet SDK (7.0)
uses: actions/setup-dotnet@v2
with:
dotnet-version: '7.0.x'
include-prerelease: true

- name: Get Dotnet Info
run: dotnet --info
Expand Down
147 changes: 147 additions & 0 deletions source/Mods/Reloaded.Utils.Server/.github/workflows/reloaded.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Script to build and publish a Reloaded Mod.
# by Sewer56

# Produces:
# - Build to Upload to GameBanana
# - Build to Upload to GitHub
# - Build to Upload to NuGet
# - Changelog

# When pushing a tag
# - Upload to GitHub Releases
# - Upload to Reloaded NuGet Repository (if GitHub Secret RELOADED_NUGET_KEY is specified)

name: Build and Publish Reloaded Mod

on:
push:
branches: [ main ]
tags:
- '*'
pull_request:
branches: [ main ]
workflow_dispatch:

env:
PUBLISH_COMMON_PATH: ./Publish/ToUpload/

PUBLISH_GAMEBANANA_PATH: ./Publish/ToUpload/GameBanana
PUBLISH_GITHUB_PATH: ./Publish/ToUpload/Generic
PUBLISH_NUGET_PATH: ./Publish/ToUpload/NuGet

PUBLISH_CHANGELOG_PATH: ./Publish/Changelog.md
PUBLISH_PATH: ./Publish

# Default value is official Reloaded package server.
NUGET_URL: http://packages.sewer56.moe:5000/v3/index.json

IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/') }}
RELEASE_TAG: ${{ github.ref_name }}

jobs:
build:
runs-on: windows-latest
defaults:
run:
shell: pwsh

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: 'recursive'

- name: Setup .NET Core SDK (5.0)
uses: actions/setup-dotnet@v1.8.2
with:
dotnet-version: 5.0.x

- name: Setup .NET Core SDK (6.0)
uses: actions/setup-dotnet@v1.8.2
with:
dotnet-version: 6.0.x

- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'

- name: Setup AutoChangelog
run: npm install -g auto-changelog

- name: Create Changelog
run: |
[System.IO.Directory]::CreateDirectory("$env:PUBLISH_PATH")
if ($env:IS_RELEASE -eq 'true') {
auto-changelog --sort-commits date --hide-credit --template keepachangelog --commit-limit false --starting-version "$env:RELEASE_TAG" --output "$env:PUBLISH_CHANGELOG_PATH"
}
else {
auto-changelog --sort-commits date --hide-credit --template keepachangelog --commit-limit false --unreleased --output "$env:PUBLISH_CHANGELOG_PATH"
}
- name: Build
run: ./Publish.ps1 -ChangelogPath "$env:PUBLISH_CHANGELOG_PATH"

- name: Upload GitHub Release Artifact
uses: actions/upload-artifact@v2.2.4
with:
# Artifact name
name: GitHub Release
# A file, directory or wildcard pattern that describes what to upload
path: |
${{ env.PUBLISH_GITHUB_PATH }}/*
- name: Upload GameBanana Release Artifact
uses: actions/upload-artifact@v2.2.4
with:
# Artifact name
name: GameBanana Release
# A file, directory or wildcard pattern that describes what to upload
path: |
${{ env.PUBLISH_GAMEBANANA_PATH }}/*
- name: Upload NuGet Release Artifact
uses: actions/upload-artifact@v2.2.4
with:
# Artifact name
name: NuGet Release
# A file, directory or wildcard pattern that describes what to upload
path: |
${{ env.PUBLISH_NUGET_PATH }}/*
- name: Upload Changelog Artifact
uses: actions/upload-artifact@v2.2.4
with:
# Artifact name
name: Changelog
# A file, directory or wildcard pattern that describes what to upload
path: ${{ env.PUBLISH_CHANGELOG_PATH }}
retention-days: 0

- name: Upload to GitHub Releases (on Tag)
uses: softprops/action-gh-release@v0.1.14
if: env.IS_RELEASE == 'true'
with:
# Path to load note-worthy description of changes in release from
body_path: ${{ env.PUBLISH_CHANGELOG_PATH }}
# Newline-delimited list of path globs for asset files to upload
files: |
${{ env.PUBLISH_GITHUB_PATH }}/*
- name: Push to NuGet (on Tag)
env:
NUGET_KEY: ${{ secrets.RELOADED_NUGET_KEY }}
if: env.IS_RELEASE == 'true'
run: |
if ([string]::IsNullOrEmpty("$env:NUGET_KEY"))
{
Write-Host "NuGet Repository Key (GitHub Secrets -> RELOADED_NUGET_KEY) Not Specified. Skipping."
return
}
$items = Get-ChildItem -Path "$env:PUBLISH_NUGET_PATH/*.nupkg"
Foreach ($item in $items)
{
Write-Host "Pushing $item"
dotnet nuget push "$item" -k "$env:NUGET_KEY" -s "$env:NUGET_URL" --skip-duplicate
}
9 changes: 9 additions & 0 deletions source/Mods/Reloaded.Utils.Server/BuildLinked.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Set Working Directory
Split-Path $MyInvocation.MyCommand.Path | Push-Location
[Environment]::CurrentDirectory = $PWD

Remove-Item "$env:RELOADEDIIMODS/Reloaded.Utils.Server/*" -Force -Recurse
dotnet publish "./Reloaded.Utils.Server.csproj" -c Release -o "$env:RELOADEDIIMODS/Reloaded.Utils.Server" /p:OutputPath="./bin/Release" /p:RobustILLink="true"

# Restore Working Directory
Pop-Location
39 changes: 39 additions & 0 deletions source/Mods/Reloaded.Utils.Server/Configuration/Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.ComponentModel;
using Reloaded.Utils.Server.Configuration.Implementation;

namespace Reloaded.Utils.Server.Configuration;

public class Config : Configurable<Config>
{
/*
User Properties:
- Please put all of your configurable properties here.
By default, configuration saves as "Config.json" in mod user config folder.
Need more config files/classes? See Configuration.cs
Available Attributes:
- Category
- DisplayName
- Description
- DefaultValue
// Technically Supported but not Useful
- Browsable
- Localizable
The `DefaultValue` attribute is used as part of the `Reset` button in Reloaded-Launcher.
*/


const string CategoryCommon = "Common Server Settings";

[DefaultValue(false)]
[Category(CategoryCommon)]
[DisplayName("Log Actions")]
[Description("If enabled, actions performed on the server are logged for debugging purposes.\n" +
"Otherwise, only errors are logged.")]
public bool Log { get; set; } = false;

public LiteNetLibConfig LiteNetLibConfig { get; set; } = new LiteNetLibConfig();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
using Reloaded.Mod.Interfaces;
using System;
using System.ComponentModel;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Reloaded.Utils.Server.Configuration.Implementation;

public class Configurable<TParentType> : IUpdatableConfigurable where TParentType : Configurable<TParentType>, new()
{
// Default Serialization Options
public static JsonSerializerOptions SerializerOptions { get; } = new JsonSerializerOptions()
{
Converters = { new JsonStringEnumConverter() },
WriteIndented = true
};

/* Events */

/// <summary>
/// Automatically executed when the external configuration file is updated.
/// Passes a new instance of the configuration as parameter.
/// Inside your event handler, replace the variable storing the configuration with the new one.
/// </summary>
[Browsable(false)]
public event Action<IUpdatableConfigurable>? ConfigurationUpdated;

/* Class Properties */

/// <summary>
/// Full path to the configuration file.
/// </summary>
[JsonIgnore]
[Browsable(false)]
public string? FilePath { get; private set; }

/// <summary>
/// The name of the configuration file.
/// </summary>
[JsonIgnore]
[Browsable(false)]
public string? ConfigName { get; private set; }

/// <summary>
/// Receives events on whenever the file is actively changed or updated.
/// </summary>
[JsonIgnore]
[Browsable(false)]
private FileSystemWatcher? ConfigWatcher { get; set; }

/* Construction */
public Configurable() { }

private void Initialize(string filePath, string configName)
{
// Initializes an instance after construction by e.g. a serializer.
FilePath = filePath;
ConfigName = configName;

MakeConfigWatcher();
Save = OnSave;
}

/* Cleanup */
public void DisposeEvents()
{
// Halts the FilesystemWatcher and all events associated with this instance.
ConfigWatcher?.Dispose();
ConfigurationUpdated = null;
}

/* Load/Save support. */

/// <summary>
/// Saves the configuration to the hard disk.
/// </summary>
[JsonIgnore]
[Browsable(false)]
public Action? Save { get; private set; }

/// <summary>
/// Safety lock for when changed event gets raised twice on file save.
/// </summary>
[Browsable(false)]
private static object _readLock = new object();

/// <summary>
/// Loads a specified configuration from the hard disk, or creates a default if it does not exist.
/// </summary>
/// <param name="filePath">The full file path of the config.</param>
/// <param name="configName">The name of the configuration.</param>
public static TParentType FromFile(string filePath, string configName) => ReadFrom(filePath, configName);

/* Event */

/// <summary>
/// Creates a <see cref="FileSystemWatcher"/> that will automatically raise an
/// <see cref="OnConfigurationUpdated"/> event when the config file is changed.
/// </summary>
/// <returns></returns>
private void MakeConfigWatcher()
{
ConfigWatcher = new FileSystemWatcher(Path.GetDirectoryName(FilePath)!, Path.GetFileName(FilePath)!);
ConfigWatcher.Changed += (sender, e) => OnConfigurationUpdated();
ConfigWatcher.EnableRaisingEvents = true;
}

/// <summary>
/// Reloads the configuration from the hard disk and raises the updated event.
/// </summary>
private void OnConfigurationUpdated()
{
lock (_readLock)
{
// Load and copy events.
// Note: External program might still be writing to file while this is being executed, so we need to keep retrying.
var newConfig = Utilities.TryGetValue(() => ReadFrom(this.FilePath!, this.ConfigName!), 250, 2);
newConfig.ConfigurationUpdated = ConfigurationUpdated;

// Disable events for this instance.
DisposeEvents();

// Call subscribers through the new config.
newConfig.ConfigurationUpdated?.Invoke(newConfig);
}
}

private void OnSave()
{
var parent = (TParentType)this;
File.WriteAllText(FilePath!, JsonSerializer.Serialize(parent, SerializerOptions));
}

/* Utility */
private static TParentType ReadFrom(string filePath, string configName)
{
var result = (File.Exists(filePath)
? JsonSerializer.Deserialize<TParentType>(File.ReadAllBytes(filePath), SerializerOptions)
: new TParentType()) ?? new TParentType();

result.Initialize(filePath, configName);
return result;
}
}
Loading

0 comments on commit 37c26fd

Please sign in to comment.