Step 2 — Define RPC Contract
Ganti IpcMessageCommand ad-hoc dengan interface bertipe. StreamJsonRpc akan otomatis route method call ke implementasi.
2.1 Interface IHermesRpc
Buat file:
HermesServices/HermesIpc.Contracts/IHermesRpc.cs
using System.Threading;
using System.Threading.Tasks;
namespace HermesIpc.Contracts;
/// <summary>
/// Kontrak RPC antara HermesNetwork (UI) dan HermesServiceEngine (helper).
/// Method dipanggil oleh client, dieksekusi di server.
/// Semua method async dan accept CancellationToken — wajib.
/// </summary>
public interface IHermesRpc
{
// ====== Logging ======
Task<RpcResult> SetLogPathAsync(string path, CancellationToken ct);
// ====== XDR ======
Task<RpcResult> StartXdrAsync(string config, CancellationToken ct);
Task<RpcResult> StopXdrAsync(CancellationToken ct);
// ====== RMM ======
Task<RpcResult> InstallRmmAsync(CancellationToken ct);
Task<RpcResult> ActivateRmmAsync(string config, CancellationToken ct);
Task<RpcResult> StartRmmAsync(CancellationToken ct);
Task<RpcResult> StopRmmAsync(CancellationToken ct);
// ====== SASE / WireGuard ======
Task<RpcResult> StartSaseAsync(string wireGuardConfig, CancellationToken ct);
Task<RpcResult> StopSaseAsync(CancellationToken ct);
// ====== Diagnostics (optional) ======
Task<HealthReport> GetHealthAsync(CancellationToken ct);
}
2.2 DTO sederhana
HermesServices/HermesIpc.Contracts/RpcResult.cs
namespace HermesIpc.Contracts;
public sealed record RpcResult(bool Success, string? Message, string? ErrorCode = null)
{
public static RpcResult Ok(string? message = null) => new(true, message);
public static RpcResult Fail(string message, string? code = null) => new(false, message, code);
}
HermesServices/HermesIpc.Contracts/HealthReport.cs
namespace HermesIpc.Contracts;
public sealed record HealthReport(
bool ServiceRunning,
bool XdrRunning,
bool RmmRunning,
bool SaseRunning,
string Version
);
2.3 Interface event push (server → client)
StreamJsonRpc mendukung event C# yang otomatis di-marshal jadi notification JSON-RPC. Tapi cara paling robust adalah definisikan interface client terpisah:
HermesServices/HermesIpc.Contracts/IHermesRpcClient.cs
using System.Threading.Tasks;
namespace HermesIpc.Contracts;
/// <summary>
/// Method yang dipanggil SERVER ke CLIENT (push event).
/// Di sisi UI, implementasi ini me-route ke MessageBusProvider.IpcMessageBus.
/// </summary>
public interface IHermesRpcClient
{
Task OnSaseStatusChangedAsync(SaseStatus status);
Task OnKcptunLogAsync(string line);
Task OnXdrStatusChangedAsync(bool running);
Task OnLogEntryAsync(LogLevel level, string source, string message);
}
public enum SaseStatus { Disconnected, Connecting, Connected, Reconnecting, Failed }
public enum LogLevel { Trace, Debug, Info, Warn, Error }
2.4 Constants tetap dipakai? Bisa, tapi tidak wajib
Karena method sudah bertipe, IpcConst.Services.Xdr + Arguments.Start tidak diperlukan lagi sebagai routing key. Anda bisa:
- Pertahankan
IpcConstuntuk konsumsi di domain layer (misal log key). - Hapus kalau hanya dipakai routing IPC.
2.5 Mapping lama → baru
Sebelum (IpcMessageCommand) | Sesudah (method call) |
|---|---|
{Service:"Xdr", Arg:"Start", Config:"..."} | await rpc.StartXdrAsync(config, ct) |
{Service:"Sase", Arg:"Start", Config:"<wg>"} | await rpc.StartSaseAsync(wgConfig, ct) |
{Service:"Log", Arg:"Path", Config:"C:\\..."} | await rpc.SetLogPathAsync(path, ct) |
Lebih readable, type-safe, IDE autocomplete jalan, refactor aman.
Checklist
-
IHermesRpc.csdibuat diHermesIpc.Contracts -
RpcResult.cs&HealthReport.csdibuat -
IHermesRpcClient.csdibuat untuk event push - Build sukses
- Tim sepakat naming method (review!)
Lanjut: Step 3: Transport Factory.