Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Big Omnibus Patch #3

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/publish-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Publish the Docker image

on:
push:
tags:
- 'v*'

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push-image:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write
attestations: write
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true

27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM mcr.microsoft.com/dotnet/sdk:7.0@sha256:d32bd65cf5843f413e81f5d917057c82da99737cb1637e905a1a4bc2e7ec6c8d AS build-env
WORKDIR /App

# Copy everything
COPY . ./
# Restore
RUN dotnet restore src/Promul.Server~/Promul.Relay.Server.csproj
# Build and publish a release
RUN dotnet publish src/Promul.Server~/Promul.Relay.Server.csproj -c Release -o out /p:UseAppHost=false


# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:7.0@sha256:c7d9ee6cd01afe9aa80642e577c7cec9f5d87f88e5d70bd36fd61072079bc55b
WORKDIR /App

# Exposed Ports
EXPOSE 80
EXPOSE 4098

# Enviroment Variables
ENV JOIN_CODE_LENGTH=6
ENV RELAY_PORT=4098
ENV RELAY_ADDRESS=us628.relays.net.fireworkeyes.com
ENV ENABLE_DESTROY_API=false

COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "Promul.Relay.Server.dll"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Promul is intended to be a free and open-source alternative to [Unity Relay](htt

## Setup
#### Relay server and API
Clone this repository and build and run the program under [/Server](/Server). The relay server will bind on UDP port 4098 while the API server will bind on TCP port 3000.
Clone this repository and build and run the program under [/src/Promul.Server~](/src/Promul.Server~) or build and run the provided docker image. The relay server will bind on UDP port 4098 while the API server will bind on TCP port 3000.

To create a new session, call `PUT /session/create`. The API will respond with the join code.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
meta {
name: Destroy Session
type: http
seq: 2
}

delete {
url: {{baseUrl}}/session/destroy
body: json
auth: none
}

body:json {
{"joinCode": "TEST"}
}
86 changes: 80 additions & 6 deletions src/Promul.Server~/Controllers/SessionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using Promul.Relay.Server.Models.Sessions;
using Promul.Relay.Server.Relay;

using System.Security.Cryptography;

namespace Promul.Relay.Server.Controllers;

[ApiController]
Expand All @@ -21,15 +23,52 @@ public SessionController(ILogger<SessionController> logger, RelayServer server)
public SessionInfo CreateSession()
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int joinCodeLength = 6;

if (System.Environment.GetEnvironmentVariable("JOIN_CODE_LENGTH") != null)
{
if (Int32.TryParse(System.Environment.GetEnvironmentVariable("JOIN_CODE_LENGTH"), out int length))
{
if (length <= 0) {
_logger.LogInformation("Not using JOIN_CODE_LENGTH enviroment variable value: `{}`, below zero",
length);
}

joinCodeLength = length;
}
else
{
_logger.LogInformation("Not using JOIN_CODE_LENGTH enviroment variable: `{}`, not an integer",
System.Environment.GetEnvironmentVariable("JOIN_CODE_LENGTH"));
}
}

var joinCode = new string(Enumerable.Repeat(chars, joinCodeLength).Select(s => s[RandomNumberGenerator.GetInt32(s.Length)]).ToArray());
//var joinCode = "TEST";

// Verify Join Code is unique
// Not the best implementation, but would only cause real theoretical problems with around 26^6/6 (51 million) lobbies
// If that's somehow an issue, just expand join code length using env var JOIN_CODE_LENGTH
while (_relay.GetSession(joinCode) != null)
{
joinCode = new string(Enumerable.Repeat(chars, joinCodeLength).Select(s => s[RandomNumberGenerator.GetInt32(s.Length)]).ToArray());
}

//var joinCode = new string(Enumerable.Repeat(chars, 6).Select(s => s[RandomNumberGenerator.GetInt32(s.Length)]).ToArray());
var joinCode = "TEST";
_relay.CreateSession(joinCode);

int relayPort = 15593;
if (
System.Environment.GetEnvironmentVariable("RELAY_PORT") != null &&
Int32.TryParse(System.Environment.GetEnvironmentVariable("RELAY_PORT"), out int port)
)
{
relayPort = port;
}
var sci = new SessionInfo
{
JoinCode = joinCode,
RelayAddress = "aus628.relays.net.fireworkeyes.com",
RelayPort = 15593
RelayAddress = System.Environment.GetEnvironmentVariable("RELAY_ADDRESS") ?? "aus628.relays.net.fireworkeyes.com",
RelayPort = relayPort
};

_logger.LogInformation("User {}:{} created session with join code {}",
Expand All @@ -45,14 +84,49 @@ public ActionResult<SessionInfo> JoinSession([FromBody] SessionRequestJoinInfo j
{
var session = _relay.GetSession(joinCode.JoinCode);
if (session == null) return NotFound();

int relayPort = 15593;
if (
System.Environment.GetEnvironmentVariable("RELAY_PORT") != null &&
Int32.TryParse(System.Environment.GetEnvironmentVariable("RELAY_PORT"), out int port)
)
{
relayPort = port;
}
return new SessionInfo
{
JoinCode = session.JoinCode,
RelayAddress = "aus628.relays.net.fireworkeyes.com",
RelayPort = 15593
RelayAddress = System.Environment.GetEnvironmentVariable("RELAY_ADDRESS") ?? "aus628.relays.net.fireworkeyes.com",
RelayPort = relayPort
};
}

[HttpDelete("Destroy")]
public ActionResult<SessionInfo> DestroySession([FromBody] SessionRequestJoinInfo joinCode)
{
// For backwards compatability and safety if API public
if (System.Environment.GetEnvironmentVariable("ENABLE_DESTROY_API") != null && !(
System.Environment.GetEnvironmentVariable("ENABLE_DESTROY_API") == "true" ||
System.Environment.GetEnvironmentVariable("ENABLE_DESTROY_API") == "t" ||
System.Environment.GetEnvironmentVariable("ENABLE_DESTROY_API") == "1" )
)
{
return NotFound();
}

var session = _relay.GetSession(joinCode.JoinCode);
if (session == null) return NotFound();

_logger.LogInformation("User {}:{} destroyed session with join code {}",
HttpContext.Connection.RemoteIpAddress,
HttpContext.Connection.RemotePort,
joinCode.JoinCode);

_relay.DestroySession(session);

return Ok();
}

public struct SessionRequestJoinInfo
{
public string JoinCode { get; set; }
Expand Down
20 changes: 0 additions & 20 deletions src/Promul.Server~/Dockerfile

This file was deleted.

25 changes: 25 additions & 0 deletions test~/Promul.Server.Tests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,29 @@ public async Task Test_That_Client_Cannot_Join_Nonexistent_Session()
var invalidJoin = await client.PutAsync("/session/join", JsonContent.Create(new { joinCode = "invalid" }));
Assert.That(invalidJoin.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}

[Test]
public async Task Test_Destroy_Created_Session()
{
var client = _factory.CreateClient();
var rs = _factory.Services.GetRequiredService<RelayServer>();
Assert.That(rs.GetAllSessions(), Is.Empty);
var response = await client.PutAsync("/session/create", null);
response.EnsureSuccessStatusCode();
var r = await response.Content.ReadFromJsonAsync<SessionInfo>();
Assert.That(r.JoinCode, Is.Not.Empty);
Assert.That(rs.GetAllSessions(), Has.Count.EqualTo(1));

// Override Destroy Enviroment Variable
System.Environment.SetEnvironmentVariable("ENABLE_DESTROY_API", "true");

var request = new HttpRequestMessage {
Method = HttpMethod.Delete,
RequestUri = new Uri("/session/destroy"),
Content = JsonContent.Create(new { joinCode = r.JoinCode })
};
var removeResponse = await client.SendAsync(request);
removeResponse.EnsureSuccessStatusCode();
Assert.That(rs.GetAllSessions(), Has.Count.EqualTo(0));
}
}
Loading