Phosphor.Core.Sdk
0.2.2
dotnet add package Phosphor.Core.Sdk --version 0.2.2
NuGet\Install-Package Phosphor.Core.Sdk -Version 0.2.2
<PackageReference Include="Phosphor.Core.Sdk" Version="0.2.2" />
<PackageVersion Include="Phosphor.Core.Sdk" Version="0.2.2" />
<PackageReference Include="Phosphor.Core.Sdk" />
paket add Phosphor.Core.Sdk --version 0.2.2
#r "nuget: Phosphor.Core.Sdk, 0.2.2"
#:package Phosphor.Core.Sdk@0.2.2
#addin nuget:?package=Phosphor.Core.Sdk&version=0.2.2
#tool nuget:?package=Phosphor.Core.Sdk&version=0.2.2
phosphor-adapter-sdk
The contract library for the Phosphor real-time operational visualization platform. Defines the interfaces, message envelopes, and plugin discovery contract that all Phosphor adapters implement.
Published to NuGet as Phosphor.Core.Sdk.
What It Defines
This package is interfaces only — no transport dependencies, no runtime behavior. It defines the contracts that phosphor-core and all adapters agree on.
Bus Connection (IBusConnection)
The transport abstraction. Adapters publish, subscribe, and issue request/reply queries through this interface without knowing whether the underlying transport is an in-process bus or a NATS cluster.
public interface IBusConnection : IAsyncDisposable
{
Task PublishAsync(string subject, PhosphorMessage message, CancellationToken ct = default);
IDisposable Subscribe(string pattern, Func<PhosphorMessage, Task> handler);
Task<PhosphorMessage?> RequestAsync(string subject, PhosphorMessage request, TimeSpan timeout, CancellationToken ct = default);
}
phosphor-core provides the implementations (InternalBusConnection, NatsBusConnection). Adapters never reference a transport directly.
Adapter Lifecycle (IPhosphorAdapter)
Every adapter implements this. Core discovers, initializes, and manages adapters through this interface.
public interface IPhosphorAdapter : IAsyncDisposable
{
string AdapterId { get; }
string DisplayName { get; }
AdapterCapabilities Capabilities { get; }
// busConnection is null in standalone mode — adapter creates its own connection.
// busConnection is provided when hosted by phosphor-core.
Task InitializeAsync(PhosphorAdapterConfig config, IBusConnection? busConnection = null, CancellationToken ct = default);
Task StartAsync(CancellationToken ct = default);
Task StopAsync(CancellationToken ct = default);
Task PublishAsync(PhosphorCommand command, CancellationToken ct = default);
}
Dual-mode initialization
The same adapter binary works in two contexts without code changes:
- Core-hosted:
phosphor-coreinjects itsIBusConnectionviaInitializeAsync. The adapter publishes through whatever transport core configured. - Standalone:
busConnectionis null. The adapter null-checks it inInitializeAsyncand creates its own connection using settings fromconfig.
public async Task InitializeAsync(PhosphorAdapterConfig config, IBusConnection? busConnection = null, CancellationToken ct = default)
{
_bus = busConnection ?? await CreateStandaloneConnectionAsync(config, ct);
}
Adapter Capabilities
[Flags]
public enum AdapterCapabilities
{
None = 0,
CanSubscribe = 1 << 0, // Produces inbound telemetry
CanPublish = 1 << 1, // Accepts outbound commands (write-back)
CanDiscoverTopology = 1 << 2, // Emits structural/topology events
CanReplay = 1 << 3, // Historical replay (JetStream, Kafka offsets)
CanPersist = 1 << 4, // Stores and retrieves historical data
CanQuery = 1 << 5, // Responds to request/reply queries
CanStream = 1 << 6, // Continuous streaming output
ReadOnly = CanSubscribe,
ReadWrite = CanSubscribe | CanPublish,
}
Core uses capabilities for routing — e.g., history query requests route to the adapter advertising CanPersist | CanQuery.
Extended Interfaces
IStructuralAdapter— for adapters that emit topology events (hardware discovery, Prometheus targets, K8s resources)IHealthReporter— adapter self-monitoring (throughput, errors, connection state)
Message Envelope
public sealed class PhosphorMessage
{
public required string Subject { get; init; }
public required byte[] Payload { get; init; }
public long Timestamp { get; init; } // Unix epoch ms, source time
public Dictionary<string, string>? Headers { get; init; }
public string? ReplyTo { get; init; } // For request/reply patterns
}
Payload is raw bytes — by convention JSON, but any format is valid. The consumer owns deserialization.
Query Contract
Standardized request/reply messages for historical data access. Any adapter can issue these via IBusConnection.RequestAsync. Whichever adapter advertises CanPersist | CanQuery handles them.
public sealed class HistoryQueryRequest
{
public required string SubjectPattern { get; init; }
public required DateTime StartTime { get; init; }
public required DateTime EndTime { get; init; }
public TimeSpan? DownsampleInterval { get; init; }
public string? AggregateFunction { get; init; } // avg, min, max, sum, count
public int? MaxResults { get; init; }
}
Well-known query subjects: phosphor.query.history, phosphor.query.latest, phosphor.query.aggregate.
Plugin Discovery
Adapters ship as DLL assemblies. Core discovers them by scanning the adapters/ folder at startup for types implementing IPhosphorAdapter. The implementing class must have a parameterless constructor — config and bus wiring happen through InitializeAsync.
Declare adapter metadata with the assembly attribute:
[assembly: PhosphorAdapter(
Name = "hwmon",
Description = "Hardware sensor monitoring via LibreHardwareMonitor",
Version = "1.0.0",
License = "Apache-2.0"
)]
Open source adapters are included in the distribution's adapters/ folder. Proprietary adapters are separate DLLs dropped into the same folder.
Subject Naming Convention
Hierarchical, dot-separated: domain.category.source.metric
Examples: sensors.temperature.floor1.zone3, transfers.node7.progress
Supports NATS-compatible wildcards: * (single token), > (deep wildcard).
Installation
dotnet add package Phosphor.Core.Sdk
Writing an Adapter
using Phosphor.Core.Sdk.Abstractions;
using Phosphor.Core.Sdk.Configuration;
using Phosphor.Core.Sdk.Envelopes;
using Phosphor.Core.Sdk.Health;
[assembly: PhosphorAdapter(Name = "my-adapter", Description = "Example", Version = "1.0.0")]
public class MyAdapter : IPhosphorAdapter, IHealthReporter
{
public string AdapterId => _config.AdapterId;
public string DisplayName => _config.DisplayName;
public AdapterCapabilities Capabilities => AdapterCapabilities.ReadOnly;
private IBusConnection _bus = null!;
private MyAdapterConfig _config = null!;
public MyAdapter() { }
public async Task InitializeAsync(PhosphorAdapterConfig config, IBusConnection? busConnection = null, CancellationToken ct = default)
{
_config = (MyAdapterConfig)config;
_bus = busConnection ?? await CreateStandaloneConnectionAsync(_config, ct);
}
public Task StartAsync(CancellationToken ct = default)
{
// Begin reading from external system.
// On each data point:
// var msg = PhosphorSerializer.CreateJsonMessage("sensors.temp.zone1", value);
// await _bus.PublishAsync(msg.Subject, msg, ct);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken ct = default) => Task.CompletedTask;
public Task PublishAsync(PhosphorCommand command, CancellationToken ct = default)
=> throw new NotSupportedException("Read-only adapter.");
public AdapterHealthReport GetHealthReport() => new()
{
AdapterId = AdapterId,
ConnectionState = AdapterConnectionState.Connected,
};
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
private Task<IBusConnection> CreateStandaloneConnectionAsync(MyAdapterConfig cfg, CancellationToken ct)
=> throw new NotImplementedException("Provide a standalone IBusConnection.");
}
public class MyAdapterConfig : PhosphorAdapterConfig
{
public string ConnectionString { get; set; } = string.Empty;
}
License
Apache 2.0 — see LICENSE.
Releasing a New Version
CI runs on every push to main (build + test). Publishing to NuGet only fires when a version tag is pushed.
- Update
<Version>in src/Phosphor.Core.Sdk/Phosphor.Core.Sdk.csproj, commit, and push tomain. - Tag the commit and push the tag:
git tag v0.2.0
git push origin v0.2.0
The v*.*.* tag triggers the Pack and Push steps in the workflow. The NUGET_API_KEY secret must be set in Settings → Secrets and variables → Actions.
Part of the Phosphor Platform
Phosphor translates operational telemetry into real-time 3D visualizations using Unreal Engine 5. Learn more at github.com/phosphor-unreal.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.