1. Setup The Plagues Protocol

Preparing Your Environment

For this example, let's copy the format of Plagues Protocol

  1. Download Pariah Cybersecurity's DLL from Here
  2. Install MagicOnion

Setup The Projects

  1. Create A Service Worker from templates (Ensuring it's the one which supports Windows/Linux and others) and name it XRUIOS.Windows.PublicAccountDataHandler, then create another named XRUIOS.Linux.PublicAccountDataHandler

These will be our service workers (As the name suggests)

  1. Create A .DLL Project Named XRUIOS.Windows and a second named XRUIOS.Linux

These will be the DLLs responsible for platform specific code

  1. Create a .DLL Project Named XRUIOS.Interfaces

This will contain shared definitions between platforms and the main core

  1. Create a .DLL Named XRUIOS.Core

This will contain cross platform code and the code responsible for selecting between XRUIOS.Windows or XRUIOS.Linux at runtime

  1. (Optional) For testing, create a CMD Project Named XRUIOS Arch Test

A simple test site for CMD related issues

Connecting Dependencies

Project Dependencies To Add Project Refs To Add
XRUIOS.Windows.
PublicAccountDataHandler
- Pariah Cybersecurity
- Magic Onion
-XRUIOS.Windows
-XRUIOS.Interface
XRUIOS.Linux.PublicAccountDataHandler - Pariah Cybersecurity
- Magic Onion
-XRUIOS.Linux
-XRUIOS.Interface
XRUIOS.Windows - Pariah Cybersecurity
- Magic Onion
-XRUIOS.Interfaces
XRUIOS.Linux - Pariah Cybersecurity
- Magic Onion
-XRUIOS.Interfaces
XRUIOS.Interfaces - Pariah Cybersecurity
- Magic Onion
XRUIOS.Core - Pariah Cybersecurity -XRUIOS.Windows
-XRUIOS.Linux

Creating Your First Worker

1. Create the Shared Interface (XRUIOS.Interfaces)

This is the only contract that crosses the Plagues boundary.

// XRUIOS.Interfaces/IPublicAcc.cs
using MagicOnion;

public interface IPublicAcc : IService<IPublicAcc>
{
    UnaryResult<PublicAccount> GetAccInfo(string accountName);
}
// XRUIOS.Interfaces/PublicAccount.cs
using System.Runtime.Serialization;

[DataContract]
public struct PublicAccount
{
    [DataMember] public string Name;
    [DataMember] public string LastCheck;
    [DataMember] public string OSFolder;

    public PublicAccount(string name, string lastCheck, string osFolder)
    {
        Name = name; LastCheck = lastCheck; OSFolder = osFolder;
    }
}

2. Create the Worker (Windows Example)

Project: XRUIOS.Windows.PublicAccountDataHandler (Worker Service template)

// Program.cs
using MagicOnion.Server;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using XRUIOS.Windows.PublicAccountDataHandler;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(5000, o => o.Protocols = HttpProtocols.Http2);
    // Later: switch to named pipe → options.ListenNamedPipe("xruios-publicacc");
});

builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<Worker>();
builder.Services.AddHostedService<Worker>();
builder.Services.AddMagicOnion();

var app = builder.Build();
app.MapMagicOnionService<PublicAccService>();
app.Run();
// Worker.cs + PublicAccService
using MagicOnion;
using MagicOnion.Server;
using XRUIOS.Interfaces;
using Pariah_Cybersecurity;
using static Pariah_Cybersecurity.EasyPQC;
using System.Diagnostics;

namespace XRUIOS.Windows.PublicAccountDataHandler
{
    public class PublicAccService : ServiceBase<IPublicAcc>, IPublicAcc
    {
        private readonly Worker _worker;
        public PublicAccService(Worker worker) => _worker = worker;
        public async UnaryResult<PublicAccount> GetAccInfo(string accountName)
            => await _worker.GetAccInfo(accountName);
    }

    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IHttpContextAccessor _httpContext;
        private readonly IServer _server;

        public Worker(ILogger<Worker> logger, IHttpContextAccessor http, IServer server)
        {
            _logger = logger; _httpContext = http; _server = server;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await Start();
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Windows Plague alive: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }

        public async UnaryResult<PublicAccount> GetAccInfo(string accountName)
        {
            if (!await VerifyIntegrity2())
                throw new Exception("Integrity Check 2 Failed");

            var folder = $@"C:\Users\{accountName}\XRUIOS";
            var lastCheck = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            _logger.LogInformation("[Windows] Served account: {name}", accountName);

            return new PublicAccount(accountName, lastCheck, folder);
        }

        private async Task Start()
        {
            // Optional startup integrity
        }

        private async Task<bool> VerifyIntegrity2()
        {
            try
            {
                string exePath = Process.GetCurrentProcess().MainModule!.FileName;
                byte[] hash;
                using (var fs = new FileStream(exePath, FileMode.Open, FileAccess.Read))
                    hash = await FileOperations.HashFile(fs);

                using (var fs = new FileStream(exePath, FileMode.Open, FileAccess.Read))
                    return await FileOperations.VerifyHash(fs, hash);
            }
            catch { return false; }
        }
    }
}

3. Create the Client Proxy (XRUIOS.Windows / XRUIOS.Linux)

// XRUIOS.Windows/Accounts.cs
using Grpc.Net.Client;
using MagicOnion.Client;
using XRUIOS.Interfaces;

namespace XRUIOS.Windows
{
    public class Accounts
    {
        public async Task<PublicAccount?> GetAccData(string accountName)
        {
            var addr = Utils.SecureStore.Get<string>("worker_addr") 
                       ?? "https://localhost:5000";
            using var channel = GrpcChannel.ForAddress(addr);
            var client = MagicOnionClient.Create<IPublicAcc>(channel);
            return await client.GetAccInfo(accountName);
        }
    }
}

Same for Linux — just change the fallback path

4. Cross-Platform Dispatcher (XRUIOS.Core)

// XRUIOS.Core/AccountsProvider.cs
using System.Runtime.InteropServices;
using XRUIOS.Interfaces;

#if WINDOWS
using XRUIOS.Windows;
#elif LINUX
using XRUIOS.Linux;
#endif

namespace XRUIOS.Core
{
    public static class AccountsProvider
    {
        public static async Task<PublicAccount> GetPublicAcc(string username)
        {
            return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
                ? await new Windows.Accounts().GetAccData(username)
                : await new Linux.Accounts().GetAccData(username)
                  ?? throw new Exception("Failed to get account data");
        }
    }
}

5. Test Client (Console)

using XRUIOS.Core;
using XRUIOS.Interfaces;

var result = await AccountsProvider.GetPublicAcc(Environment.UserName);
Console.WriteLine($"Name: {result.Name}");
Console.WriteLine($"Folder: {result.OSFolder}");
Console.WriteLine($"Checked: {result.LastCheck}");