panel public release
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
module github.com/dbledeez/panel/proto
|
||||
|
||||
go 1.26
|
||||
|
||||
require (
|
||||
google.golang.org/grpc v1.80.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 h1:sNrWoksmOyF5bvJUcnmbeAmQi8baNhqg5IWaI3llQqU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
||||
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,785 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package panel.v1;
|
||||
|
||||
option go_package = "github.com/dbledeez/panel/proto/panel/v1;panelv1";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "panel/v1/common.proto";
|
||||
|
||||
// Agent is the gRPC service a Target agent dials on the Controller.
|
||||
// A single persistent bidirectional stream carries all control-plane
|
||||
// traffic between Controller and Target: commands downstream, state
|
||||
// and events upstream.
|
||||
service Agent {
|
||||
rpc Connect(stream AgentEnvelope) returns (stream ControllerEnvelope);
|
||||
}
|
||||
|
||||
// ControllerEnvelope — messages from Controller to Target.
|
||||
message ControllerEnvelope {
|
||||
string correlation_id = 1;
|
||||
google.protobuf.Timestamp sent_at = 2;
|
||||
oneof payload {
|
||||
ControllerHello hello = 10;
|
||||
Ping ping = 11;
|
||||
ExecRequest exec = 20;
|
||||
InstanceCreate instance_create = 30;
|
||||
InstanceStart instance_start = 31;
|
||||
InstanceStop instance_stop = 32;
|
||||
InstanceDelete instance_delete = 33;
|
||||
RCONCommand rcon = 40;
|
||||
FsListRequest fs_list = 50;
|
||||
FsReadRequest fs_read = 51;
|
||||
FsWriteRequest fs_write = 52;
|
||||
FsDeleteRequest fs_delete = 53;
|
||||
FsSymlinkRequest fs_symlink = 54;
|
||||
FsExtractRequest fs_extract = 55;
|
||||
FsCompressRequest fs_compress = 56;
|
||||
FsRenameRequest fs_rename = 57;
|
||||
FsWriteChunkRequest fs_write_chunk = 58;
|
||||
ArkSaveRestoreRequest ark_save_restore = 59;
|
||||
DayzModInstallRequest dayz_mod_install = 90;
|
||||
DayzModUninstallRequest dayz_mod_uninstall = 91;
|
||||
UpdateRequest update = 60;
|
||||
BackupRequest backup = 70;
|
||||
RestoreRequest restore = 71;
|
||||
BackupListEntriesRequest backup_list_entries = 72;
|
||||
BackupReadFileRequest backup_read_file = 73;
|
||||
EmpyrionScenarioInstallRequest empyrion_scenario_install = 100;
|
||||
EmpyrionDiscoveriesRequest empyrion_discoveries = 101;
|
||||
EmpyrionPlayerSummaryRequest empyrion_player_summary = 102;
|
||||
RegionScanRequest region_scan = 110;
|
||||
RegionHealRequest region_heal = 111;
|
||||
InstanceRenderConfigRequest instance_render_config = 112;
|
||||
SeedModsRequest seed_mods = 113;
|
||||
UpdateCheckRequest update_check = 114;
|
||||
}
|
||||
}
|
||||
|
||||
// AgentEnvelope — messages from Target to Controller.
|
||||
message AgentEnvelope {
|
||||
string correlation_id = 1;
|
||||
google.protobuf.Timestamp sent_at = 2;
|
||||
oneof payload {
|
||||
AgentHello hello = 10;
|
||||
Heartbeat heartbeat = 11;
|
||||
Pong pong = 12;
|
||||
CommandResult result = 20;
|
||||
InstanceStateUpdate instance_state = 30;
|
||||
AppStateUpdate app_state = 31;
|
||||
LogLine log = 32;
|
||||
PlayerEvent player = 33;
|
||||
RCONResult rcon_result = 40;
|
||||
FsListResult fs_list_result = 50;
|
||||
FsReadResult fs_read_result = 51;
|
||||
FsWriteResult fs_write_result = 52;
|
||||
FsDeleteResult fs_delete_result = 53;
|
||||
FsSymlinkResult fs_symlink_result = 54;
|
||||
FsExtractResult fs_extract_result = 55;
|
||||
FsCompressResult fs_compress_result = 56;
|
||||
FsRenameResult fs_rename_result = 57;
|
||||
FsWriteChunkResult fs_write_chunk_result = 58;
|
||||
ArkSaveRestoreResult ark_save_restore_result = 59;
|
||||
DayzModInstallResult dayz_mod_install_result = 90;
|
||||
DayzModUninstallResult dayz_mod_uninstall_result = 91;
|
||||
UpdateResult update_result = 60;
|
||||
BackupResult backup_result = 70;
|
||||
RestoreResult restore_result = 71;
|
||||
BackupListEntriesResult backup_list_entries_result = 72;
|
||||
BackupReadFileResult backup_read_file_result = 73;
|
||||
InstanceStatsUpdate instance_stats = 80;
|
||||
EmpyrionScenarioInstallResult empyrion_scenario_install_result = 100;
|
||||
EmpyrionDiscoveriesResult empyrion_discoveries_result = 101;
|
||||
EmpyrionPlayerSummaryResult empyrion_player_summary_result = 102;
|
||||
RegionScanResult region_scan_result = 110;
|
||||
RegionHealResult region_heal_result = 111;
|
||||
InstanceRenderConfigResult instance_render_config_result = 112;
|
||||
SeedModsResult seed_mods_result = 113;
|
||||
UpdateCheckResult update_check_result = 114;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Handshake ----
|
||||
|
||||
message AgentHello {
|
||||
string agent_id = 1;
|
||||
string agent_version = 2;
|
||||
string host_os = 3; // "linux", "windows"
|
||||
string host_arch = 4; // "amd64", "arm64"
|
||||
string hostname = 5;
|
||||
repeated string supported_runtimes = 6; // "docker", "host"
|
||||
repeated ModuleSummary modules = 7;
|
||||
}
|
||||
|
||||
// ModuleSummary is what an agent advertises about one locally-loaded
|
||||
// module at handshake time. The controller aggregates these across all
|
||||
// agents so the dashboard can render a "known modules" picker without
|
||||
// needing direct filesystem access to each agent's modules/ dir.
|
||||
message ModuleSummary {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string version = 3;
|
||||
repeated string supported_modes = 4;
|
||||
repeated ModuleUpdateProviderSummary update_providers = 5;
|
||||
bool has_rcon = 6;
|
||||
repeated string authors = 7;
|
||||
}
|
||||
|
||||
message ModuleUpdateProviderSummary {
|
||||
string id = 1;
|
||||
string kind = 2; // "steamcmd" | "github" | "direct"
|
||||
// True when the provider sets `requires_steam_login: true` on the
|
||||
// manifest (DayZ, Arma). Controller uses this to decide whether to
|
||||
// pop the Steam-login modal before forwarding an UpdateRequest.
|
||||
bool requires_steam_login = 3;
|
||||
}
|
||||
|
||||
message ControllerHello {
|
||||
string controller_version = 1;
|
||||
google.protobuf.Timestamp server_time = 2;
|
||||
}
|
||||
|
||||
message Heartbeat {
|
||||
google.protobuf.Timestamp at = 1;
|
||||
double cpu_percent = 2;
|
||||
uint64 mem_used_bytes = 3;
|
||||
uint64 mem_total_bytes = 4;
|
||||
uint32 instance_count = 5;
|
||||
}
|
||||
|
||||
message Ping { string nonce = 1; }
|
||||
message Pong { string nonce = 1; }
|
||||
|
||||
// ---- Exec / commands ----
|
||||
|
||||
message ExecRequest {
|
||||
string instance_id = 1; // empty = run on Target host
|
||||
repeated string argv = 2;
|
||||
map<string, string> env = 3;
|
||||
string working_dir = 4;
|
||||
uint32 timeout_seconds = 5;
|
||||
}
|
||||
|
||||
message CommandResult {
|
||||
int32 exit_code = 1;
|
||||
bytes stdout = 2;
|
||||
bytes stderr = 3;
|
||||
Error error = 4;
|
||||
}
|
||||
|
||||
// ---- Instance lifecycle ----
|
||||
|
||||
message InstanceCreate {
|
||||
string instance_id = 1;
|
||||
string module_id = 2;
|
||||
string version = 3;
|
||||
RunMode run_mode = 4;
|
||||
ResourceLimits limits = 5;
|
||||
map<string, string> config_values = 6; // flattened key/value, module schema-validated
|
||||
repeated PortMap ports = 7;
|
||||
string data_path = 8;
|
||||
// mount_overrides lets the controller swap one of the module's
|
||||
// manifest-defined volume mounts at create time. Keyed by container
|
||||
// path (matching a volume entry's `container:` field in module.yaml).
|
||||
// Value is either a Docker named volume name (no leading slash) or an
|
||||
// absolute host path (leading slash = bind mount).
|
||||
//
|
||||
// Used by the ARK cluster feature to swap an instance's per-instance
|
||||
// `panel-<id>-cluster` named volume for a shared `panel-ark-cluster-<id>`
|
||||
// volume when the server joins a cluster. Generic enough for future
|
||||
// features — any module can benefit from per-instance mount swaps
|
||||
// without needing a manifest change.
|
||||
map<string, string> mount_overrides = 9;
|
||||
}
|
||||
|
||||
message InstanceStart { string instance_id = 1; }
|
||||
message InstanceStop {
|
||||
string instance_id = 1;
|
||||
uint32 grace_seconds = 2;
|
||||
bool force = 3;
|
||||
}
|
||||
// InstanceDelete tears down the instance record. If purge_volumes is
|
||||
// true, every Docker volume labeled panel.instance_id=<instance_id> is
|
||||
// removed too; otherwise volumes survive so a subsequent re-create can
|
||||
// pick up the existing world/save data.
|
||||
message InstanceDelete {
|
||||
string instance_id = 1;
|
||||
uint32 grace_seconds = 2; // if the container is still running, stop with this grace first
|
||||
bool purge_volumes = 3;
|
||||
}
|
||||
|
||||
// ---- State streams ----
|
||||
|
||||
message InstanceStateUpdate {
|
||||
string instance_id = 1;
|
||||
InstanceStatus status = 2;
|
||||
int32 exit_code = 3;
|
||||
google.protobuf.Timestamp at = 4;
|
||||
string detail = 5;
|
||||
}
|
||||
|
||||
message AppStateUpdate {
|
||||
string instance_id = 1;
|
||||
int32 players_online = 2;
|
||||
int32 players_max = 3;
|
||||
int64 uptime_seconds = 4;
|
||||
map<string, string> module_fields = 10; // world_seed, day_number, tps, etc.
|
||||
google.protobuf.Timestamp at = 20;
|
||||
}
|
||||
|
||||
message LogLine {
|
||||
string instance_id = 1;
|
||||
string stream = 2; // "stdout", "stderr", or a named log file
|
||||
google.protobuf.Timestamp at = 3;
|
||||
string line = 4;
|
||||
}
|
||||
|
||||
// InstanceStatsUpdate is emitted periodically (default every 10s) by the
|
||||
// agent's per-instance stats poller. Values come from Docker's stats
|
||||
// stream API. Kept sparse — enough for UI gauges + future scheduler
|
||||
// expressions like "cpu_percent > 80 sustained 5m -> notify".
|
||||
message InstanceStatsUpdate {
|
||||
string instance_id = 1;
|
||||
double cpu_percent = 2; // 100 = 1 vCPU saturated
|
||||
uint64 mem_used_bytes = 3;
|
||||
uint64 mem_limit_bytes = 4; // 0 if no explicit limit set (then use container's view)
|
||||
uint64 net_rx_bytes = 5; // cumulative since container start
|
||||
uint64 net_tx_bytes = 6;
|
||||
uint32 pids = 7;
|
||||
google.protobuf.Timestamp at = 8;
|
||||
// Host core count (docker OnlineCPUs) so UIs can translate the
|
||||
// docker-style cpu_percent (100 = 1 core) into percent-of-host.
|
||||
uint32 host_cpus = 9;
|
||||
}
|
||||
|
||||
// ---- Ad-hoc RCON ----
|
||||
|
||||
message RCONCommand {
|
||||
string instance_id = 1;
|
||||
string command = 2;
|
||||
}
|
||||
|
||||
message RCONResult {
|
||||
string output = 1;
|
||||
string error = 2; // empty on success; short machine-readable on failure
|
||||
}
|
||||
|
||||
// ---- File management (rooted at each instance's data_path) ----
|
||||
|
||||
message FsEntry {
|
||||
string name = 1; // base name
|
||||
string path = 2; // path relative to instance data_path
|
||||
bool is_dir = 3;
|
||||
int64 size = 4; // bytes (for files)
|
||||
google.protobuf.Timestamp mod_time = 5;
|
||||
}
|
||||
|
||||
message FsListRequest { string instance_id = 1; string path = 2; }
|
||||
message FsListResult {
|
||||
repeated FsEntry entries = 1;
|
||||
string path = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
message FsReadRequest { string instance_id = 1; string path = 2; }
|
||||
message FsReadResult {
|
||||
string path = 1;
|
||||
bytes content = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
message FsWriteRequest { string instance_id = 1; string path = 2; bytes content = 3; }
|
||||
message FsWriteResult { int64 bytes_written = 1; string error = 2; }
|
||||
|
||||
message FsDeleteRequest { string instance_id = 1; string path = 2; bool recursive = 3; }
|
||||
message FsDeleteResult { string error = 1; }
|
||||
|
||||
// FsSymlinkRequest creates (or replaces) a symlink inside the instance
|
||||
// container. Used by the DayZ mod manager to link @ModName entries to
|
||||
// the shared workshop tree at /game/steamapps/workshop/content/...
|
||||
message FsSymlinkRequest { string instance_id = 1; string target = 2; string link_path = 3; }
|
||||
message FsSymlinkResult { string error = 1; }
|
||||
|
||||
// FsExtractRequest expands an archive that already lives inside the
|
||||
// instance's volume. Format is auto-detected from the archive bytes
|
||||
// (zip / tar / tar.gz / tar.bz2). dest_dir is rooted in the instance's
|
||||
// browseable root just like every other Fs op; "" means same dir as
|
||||
// the archive.
|
||||
message FsExtractRequest {
|
||||
string instance_id = 1;
|
||||
string archive_path = 2;
|
||||
string dest_dir = 3;
|
||||
bool overwrite = 4;
|
||||
}
|
||||
message FsExtractResult {
|
||||
int64 entries_written = 1;
|
||||
int64 bytes_written = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
// FsCompressRequest produces a zip archive at dest_zip_path containing
|
||||
// the contents of every path in `sources` (recursive for dirs). All
|
||||
// paths must be inside the instance's browseable root.
|
||||
message FsCompressRequest {
|
||||
string instance_id = 1;
|
||||
repeated string sources = 2;
|
||||
string dest_zip_path = 3;
|
||||
bool overwrite = 4;
|
||||
}
|
||||
message FsCompressResult {
|
||||
int64 entries_written = 1;
|
||||
int64 bytes_written = 2;
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
// FsRenameRequest is a path-safe `mv` inside the instance's volume —
|
||||
// supports rename + move-into-sibling-dir within the same root.
|
||||
message FsRenameRequest {
|
||||
string instance_id = 1;
|
||||
string from_path = 2;
|
||||
string to_path = 3;
|
||||
}
|
||||
message FsRenameResult { string error = 1; }
|
||||
|
||||
// FsWriteChunkRequest streams a single chunk of a larger upload. Chunks
|
||||
// are uploaded in order; each one carries the same upload_id (browser-
|
||||
// generated UUID) so the agent can append to the same temp file. On
|
||||
// is_final = true the agent finalizes (closes the temp file, ships it
|
||||
// to the container via CopyToContainer, then unlinks).
|
||||
message FsWriteChunkRequest {
|
||||
string instance_id = 1;
|
||||
string upload_id = 2;
|
||||
string path = 3;
|
||||
int64 offset = 4;
|
||||
bytes data = 5;
|
||||
int64 total_size = 6; // optional; agent uses for sanity checks on final
|
||||
bool is_final = 7;
|
||||
}
|
||||
message FsWriteChunkResult {
|
||||
int64 bytes_received = 1;
|
||||
int64 total_received = 2; // running total per upload_id
|
||||
bool finalized = 3;
|
||||
string error = 4;
|
||||
}
|
||||
|
||||
// ArkSaveRestoreRequest swaps a timestamped rolling backup into the
|
||||
// active save slot under SavedArks/<subdir>/<subdir>.ark. The previous
|
||||
// active save is moved aside (NEVER deleted) by appending a "_replaced"
|
||||
// timestamp suffix so even abandoned attempts are recoverable. Path is
|
||||
// rooted at ShooterGame/Saved/SavedArks/<saved_arks_subdir>/ in the
|
||||
// instance's browseable root.
|
||||
//
|
||||
// Caller (controller) is responsible for stopping the container before
|
||||
// invoking this — the agent only performs file operations. If a backup
|
||||
// rolling file (.arkrbf) is selected, it is renamed to .ark before
|
||||
// installing as the active save.
|
||||
message ArkSaveRestoreRequest {
|
||||
string instance_id = 1;
|
||||
string saved_arks_subdir = 2; // e.g. "TheIsland_WP"
|
||||
string target_filename = 3; // basename within saved_arks_subdir (e.g. "TheIsland_WP_30.04.2026_22.13.00.ark")
|
||||
}
|
||||
message ArkSaveRestoreResult {
|
||||
string aside_filename = 1; // what the previously-active save was renamed to
|
||||
string installed_filename = 2; // the filename that's now active (always "<subdir>.ark")
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
// DayzModInstallRequest asks the agent to (1) copy the mod's bikeys into
|
||||
// /game/keys and (2) create a @ModName symlink at /game/<folder_name>
|
||||
// pointing at the shared workshop content at
|
||||
// /game/steamapps/workshop/content/221100/<workshop_id>. Agent-side so
|
||||
// it can scan the workshop dir and preserve file ownership.
|
||||
message DayzModInstallRequest {
|
||||
string instance_id = 1;
|
||||
string workshop_id = 2;
|
||||
string folder_name = 3; // e.g. "@CommunityOnlineTools"
|
||||
}
|
||||
message DayzModInstallResult {
|
||||
string error = 1;
|
||||
repeated string bikeys_copied = 2; // filenames of bikeys dropped in /game/keys
|
||||
string resolved_mod_path = 3; // /game/steamapps/workshop/content/221100/<id>
|
||||
}
|
||||
|
||||
// DayzModUninstallRequest removes the @ModName symlink and the mod's
|
||||
// bikeys from /game/keys (bikeys are matched by file hash — only keys
|
||||
// whose content originated from this workshop item are removed).
|
||||
message DayzModUninstallRequest {
|
||||
string instance_id = 1;
|
||||
string folder_name = 2;
|
||||
}
|
||||
message DayzModUninstallResult {
|
||||
string error = 1;
|
||||
repeated string bikeys_removed = 2;
|
||||
}
|
||||
|
||||
// ---- Updates ----
|
||||
//
|
||||
// The agent runs the update asynchronously. The synchronous UpdateResult
|
||||
// carries only the acknowledgement + ref-id for later correlation; real
|
||||
// progress + final status flow through LogLine (stream="update") and the
|
||||
// terminal "update:ok"/"update:error:<msg>" LogLine sentinel at the end.
|
||||
|
||||
message UpdateRequest {
|
||||
string instance_id = 1;
|
||||
string provider_id = 2; // empty = use the module's first update_provider
|
||||
// Steam login credentials for apps whose SteamCMD refuses +login
|
||||
// anonymous (DayZ, Arma, etc. — modules with `requires_steam_login`
|
||||
// set on the provider). The controller pulls these from its
|
||||
// encrypted steam_credentials store and forwards them via the
|
||||
// mTLS-protected control stream. Agent never logs them.
|
||||
string steam_username = 3;
|
||||
string steam_password = 4;
|
||||
}
|
||||
|
||||
message UpdateResult {
|
||||
bool accepted = 1; // true = agent kicked off the update goroutine
|
||||
string error = 2; // empty on accept; populated on immediate reject
|
||||
string provider_id = 3;
|
||||
string provider_kind = 4;
|
||||
}
|
||||
|
||||
// ---- Backup + Restore ----
|
||||
//
|
||||
// Synchronous over the bidi stream. The sidecar tars the instance's
|
||||
// volume into a .tar.gz on the agent's --backup-dir; the terminal
|
||||
// BackupResult carries the path + size. Restore takes a backup id
|
||||
// (path resolved by the controller via DB) and reverses.
|
||||
|
||||
message BackupRequest {
|
||||
string instance_id = 1;
|
||||
string description = 2;
|
||||
}
|
||||
|
||||
message BackupResult {
|
||||
string backup_id = 1; // bkp_<hex>
|
||||
string path = 2;
|
||||
int64 size_bytes = 3;
|
||||
string error = 4;
|
||||
}
|
||||
|
||||
message RestoreRequest {
|
||||
string instance_id = 1;
|
||||
string backup_id = 2;
|
||||
string backup_path = 3; // absolute path on the agent
|
||||
}
|
||||
|
||||
message RestoreResult {
|
||||
string error = 1;
|
||||
int64 bytes_restored = 2;
|
||||
}
|
||||
|
||||
// BackupListEntriesRequest asks the agent to enumerate the contents of a
|
||||
// backup tarball without extracting it. Used by the backup-browser UI so
|
||||
// operators can drill into a snapshot to confirm what's inside before
|
||||
// restoring (or to recover a single file).
|
||||
message BackupListEntriesRequest {
|
||||
string instance_id = 1;
|
||||
string backup_id = 2;
|
||||
string backup_path = 3; // absolute path on the agent (resolved controller-side)
|
||||
}
|
||||
|
||||
// BackupTarEntry — one row from `tar -tvzf`. Size is bytes-on-disk, not
|
||||
// compressed size. is_dir distinguishes directories so the UI can render
|
||||
// a tree without a second pass.
|
||||
message BackupTarEntry {
|
||||
string path = 1; // path inside the tarball, no leading slash
|
||||
int64 size = 2;
|
||||
bool is_dir = 3;
|
||||
string mode = 4; // permissions string, e.g. "-rw-r--r--"
|
||||
google.protobuf.Timestamp mod_time = 5;
|
||||
}
|
||||
|
||||
message BackupListEntriesResult {
|
||||
repeated BackupTarEntry entries = 1;
|
||||
int64 total_bytes = 2; // sum of file sizes (not compressed size of the tarball)
|
||||
string error = 3;
|
||||
}
|
||||
|
||||
// BackupReadFileRequest extracts a single entry's bytes to memory by
|
||||
// streaming `tar -xzOf <archive> <path>` into a buffer. Caller-supplied
|
||||
// max_bytes caps the read so a malicious / corrupt archive can't OOM the
|
||||
// agent — the result includes truncated=true if max_bytes was hit.
|
||||
message BackupReadFileRequest {
|
||||
string instance_id = 1;
|
||||
string backup_id = 2;
|
||||
string backup_path = 3;
|
||||
string entry_path = 4;
|
||||
int64 max_bytes = 5; // 0 → controller-side default (8 MiB)
|
||||
}
|
||||
|
||||
message BackupReadFileResult {
|
||||
bytes content = 1;
|
||||
int64 size = 2; // actual entry size from tar header (may be > len(content) if truncated)
|
||||
bool truncated = 3;
|
||||
bool is_binary = 4; // heuristic: NUL byte in first 8 KiB
|
||||
string error = 5;
|
||||
}
|
||||
|
||||
message PlayerEvent {
|
||||
enum Kind {
|
||||
KIND_UNSPECIFIED = 0;
|
||||
KIND_JOIN = 1;
|
||||
KIND_LEAVE = 2;
|
||||
KIND_CHAT = 3;
|
||||
KIND_DEATH = 4;
|
||||
KIND_CUSTOM = 99;
|
||||
}
|
||||
string instance_id = 1;
|
||||
Kind kind = 2;
|
||||
string player_id = 3; // SteamID / UUID where available
|
||||
string player_name = 4;
|
||||
string detail = 5;
|
||||
google.protobuf.Timestamp at = 6;
|
||||
}
|
||||
|
||||
// EmpyrionScenarioInstallRequest is sent controller → agent to install
|
||||
// (or refresh) a workshop scenario into a specific Empyrion instance's
|
||||
// game volume. The agent runs SteamCMD on its OWN Docker daemon — the
|
||||
// previous (single-host) implementation ran on the controller's daemon
|
||||
// which has no view of an agent's volumes.
|
||||
message EmpyrionScenarioInstallRequest {
|
||||
string job_id = 1; // controller-generated; echoed in result + log lines
|
||||
string instance_id = 2; // target empyrion instance (must live on this agent)
|
||||
string workshop_id = 3; // Steam workshop item ID (e.g. "3041847672" for RE2)
|
||||
string scenario_name = 4; // folder name under Content/Scenarios; sanitized by controller
|
||||
string app_id = 5; // empyrion app id; defaults to 530870 if empty
|
||||
// Steam credentials for the workshop_download_item call. Steam policy
|
||||
// (~2023+) requires a logged-in account for most app workshops, even
|
||||
// for public/free items — anonymous returns "Access Denied". Forwarded
|
||||
// from the controller's encrypted steam_credentials store. Same shape
|
||||
// as UpdateRequest's steam_username/steam_password fields.
|
||||
string steam_username = 6;
|
||||
string steam_password = 7;
|
||||
}
|
||||
|
||||
message EmpyrionScenarioInstallResult {
|
||||
string job_id = 1;
|
||||
bool ok = 2;
|
||||
string error = 3; // empty when ok
|
||||
string scenario_name = 4;
|
||||
}
|
||||
|
||||
// EmpyrionDiscoveriesRequest queries the empyrion server's global.db
|
||||
// (SQLite) for what a specific player has discovered. The agent mounts
|
||||
// the instance's saves volume into a tiny alpine+sqlite sidecar, runs
|
||||
// a join query against DiscoveredPOIs / Entities / Playfields /
|
||||
// SolarSystems / LoginLogoff, and returns the rows.
|
||||
//
|
||||
// `mode = "personal"` returns POIs the named player personally
|
||||
// discovered. `mode = "faction"` returns POIs anyone in their faction
|
||||
// has discovered (the in-game shared-map view). Default: personal.
|
||||
message EmpyrionDiscoveriesRequest {
|
||||
string instance_id = 1;
|
||||
string steam_id = 2; // 17-digit SteamID64 of the player
|
||||
string mode = 3; // "personal" | "faction"
|
||||
}
|
||||
|
||||
message DiscoveredPOI {
|
||||
string solar_system = 1;
|
||||
string playfield = 2;
|
||||
string poi_name = 3;
|
||||
int32 poi_type = 4; // Entities.etype enum
|
||||
int64 game_time = 5; // ticks since save start
|
||||
string discoverer_name = 6; // who first discovered (when known)
|
||||
string discoverer_steam_id = 7;
|
||||
int32 faction_group = 8;
|
||||
int32 faction_id = 9;
|
||||
}
|
||||
|
||||
message EmpyrionDiscoveriesResult {
|
||||
bool ok = 1;
|
||||
string error = 2;
|
||||
repeated DiscoveredPOI pois = 3;
|
||||
string mode = 4; // echoed back from request
|
||||
string steam_id = 5;
|
||||
string player_name = 6; // last-known name from LoginLogoff
|
||||
}
|
||||
|
||||
// EmpyrionPlayerSummaryRequest pulls everything we know about a single
|
||||
// player from the empyrion savegame DB: stats, login sessions, current
|
||||
// inventory snapshot. Used by the public /me page on AMP-Monitor.
|
||||
message EmpyrionPlayerSummaryRequest {
|
||||
string instance_id = 1;
|
||||
string steam_id = 2; // 17-digit SteamID64
|
||||
int32 max_login_rows = 3; // limit on session history; default 50
|
||||
}
|
||||
|
||||
message PlayerStatsRow {
|
||||
int64 killed_enemies = 1;
|
||||
int64 killed_allied = 2;
|
||||
int64 killed_animals = 3;
|
||||
int64 killed_drones = 4;
|
||||
int64 killed_players = 5;
|
||||
int64 killed_allied_players = 6;
|
||||
int64 died = 7;
|
||||
int64 score = 8;
|
||||
int64 blocks_placed = 9;
|
||||
int64 blocks_digged = 10;
|
||||
int64 walked_meters = 11;
|
||||
int64 jetpack_meters = 12;
|
||||
int64 hv_meters = 13;
|
||||
int64 sv_meters = 14;
|
||||
int64 cv_meters = 15;
|
||||
double playtime = 16; // hours per the schema
|
||||
double light_years = 17; // travly
|
||||
double astronomical_units = 18; // travau
|
||||
}
|
||||
|
||||
message PlayerLoginRow {
|
||||
int64 login_ticks = 1;
|
||||
int64 logoff_ticks = 2;
|
||||
string player_name = 3;
|
||||
int64 build_nr = 4;
|
||||
string ip = 5;
|
||||
string os = 6;
|
||||
string gfx = 7;
|
||||
string cpu = 8;
|
||||
}
|
||||
|
||||
message PlayerInventoryItem {
|
||||
int32 item_id = 1;
|
||||
int32 count = 2;
|
||||
}
|
||||
|
||||
message EmpyrionPlayerSummaryResult {
|
||||
bool ok = 1;
|
||||
string error = 2;
|
||||
string steam_id = 3;
|
||||
string player_name = 4;
|
||||
int64 entity_id = 5;
|
||||
int32 faction_group = 6;
|
||||
int32 faction_id = 7;
|
||||
|
||||
// Aggregate stats. nil when player has no PlayerStatistics row yet
|
||||
// (very new player).
|
||||
PlayerStatsRow stats = 8;
|
||||
|
||||
// Recent login sessions, newest first.
|
||||
repeated PlayerLoginRow sessions = 9;
|
||||
|
||||
// Most recent inventory snapshot. May be empty for players without
|
||||
// a recorded snapshot.
|
||||
int64 inventory_gametime = 10;
|
||||
repeated PlayerInventoryItem inventory = 11;
|
||||
|
||||
// Last-known position.
|
||||
string last_playfield = 12;
|
||||
double last_x = 13;
|
||||
double last_y = 14;
|
||||
double last_z = 15;
|
||||
int64 credits = 16;
|
||||
}
|
||||
|
||||
// ---- Region Medic (7DTD .7rg region-corruption detect + heal) ----
|
||||
|
||||
// RegionScanRequest asks the agent to scan an instance's active-world Region
|
||||
// directory for corruption evidence (error_backup salvage files + invalid
|
||||
// region files).
|
||||
message RegionScanRequest {
|
||||
string instance_id = 1;
|
||||
}
|
||||
|
||||
// AffectedRegionMsg is one region flagged by a scan.
|
||||
message AffectedRegionMsg {
|
||||
string region = 1; // canonical id, e.g. "r.-2.0"
|
||||
int32 error_backups = 2; // salvage files whose chunks fall in this region
|
||||
bool file_present = 3; // r.X.Z.7rg exists on disk
|
||||
bool file_corrupt = 4; // region file failed structural validation
|
||||
int32 bad_chunks = 5; // count of invalid chunks if validated
|
||||
}
|
||||
|
||||
message RegionScanResult {
|
||||
int32 error_backups = 1; // total salvage files found
|
||||
repeated AffectedRegionMsg affected = 2;
|
||||
string region_dir = 3; // resolved active Region dir (container path)
|
||||
Error error = 4;
|
||||
}
|
||||
|
||||
// RegionHealRequest asks the agent to heal one region from the newest clean
|
||||
// backup. The agent stops the instance (graceful save first), swaps the region
|
||||
// file in place, quarantines the region's error_backups, then restarts (if
|
||||
// restart=true).
|
||||
message RegionHealRequest {
|
||||
string instance_id = 1;
|
||||
string region = 2; // "r.-2.0"
|
||||
bool restart = 3; // restart the instance after healing
|
||||
}
|
||||
|
||||
message RegionHealResult {
|
||||
string region = 1;
|
||||
string source_backup = 2; // backup id the clean copy came from
|
||||
int64 bytes_written = 3;
|
||||
int32 quarantined = 4; // error_backup files moved aside
|
||||
string snapshot_path = 5; // where the corrupt original was saved
|
||||
bool healed = 6;
|
||||
Error error = 7;
|
||||
}
|
||||
|
||||
// ---- Durable config re-render (no container recreate) ----
|
||||
|
||||
// InstanceRenderConfigRequest asks the agent to re-render the module's
|
||||
// declared config_files (templates) into the instance's host DataPath,
|
||||
// WITHOUT recreating or restarting the container. For modules whose
|
||||
// rendered output is bind-mounted into the container (7dtd's
|
||||
// serverconfig.xml.rendered), the entrypoint picks the new content up on
|
||||
// the instance's NEXT boot — this is the durable, no-recreate config path.
|
||||
//
|
||||
// config_values is the FULL desired value map (the controller sends its
|
||||
// merged DB row, not a delta), mirroring what InstanceCreate would render.
|
||||
message InstanceRenderConfigRequest {
|
||||
string instance_id = 1;
|
||||
map<string, string> config_values = 2;
|
||||
}
|
||||
|
||||
message InstanceRenderConfigResult {
|
||||
repeated string rendered_files = 1; // config_file paths written (manifest-relative)
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
// SeedModsRequest asks an agent to clone the Mods/ folder of src_instance_id
|
||||
// (the cluster master) onto instance_id (a member), live — no container
|
||||
// recreate. Per-server state (RefugeBot homes.json) is excluded from the copy
|
||||
// and the member's own homes.json is preserved. The member keeps running on
|
||||
// its currently-loaded mods; the new files take effect on its NEXT restart.
|
||||
// Both instances must live on the same agent (the sidecar mounts local volumes).
|
||||
message SeedModsRequest {
|
||||
string instance_id = 1; // destination member to receive the mods
|
||||
string src_instance_id = 2; // source cluster master to copy mods from
|
||||
}
|
||||
|
||||
message SeedModsResult {
|
||||
string instance_id = 1;
|
||||
bool ok = 2;
|
||||
string error = 3;
|
||||
int32 mod_count = 4; // number of mods present on the member after the copy
|
||||
}
|
||||
|
||||
// ---- Update-available check (WI-14) ----
|
||||
//
|
||||
// CHECK-ONLY: this RPC never triggers an update or restart. The agent
|
||||
// reads the installed buildid from the Steam appmanifest_<appid>.acf in
|
||||
// the instance volume and fetches the latest buildid for the instance's
|
||||
// branch via a one-shot `steamcmd +app_info_print` sidecar (cached per
|
||||
// app_id for 15 minutes agent-side).
|
||||
|
||||
message UpdateCheckRequest {
|
||||
string instance_id = 1;
|
||||
// provider_id selects the module update_provider (steamcmd kind) whose
|
||||
// app_id/beta define what "installed vs latest" means. Empty = same
|
||||
// default the Update RPC uses (first provider in the manifest).
|
||||
string provider_id = 2;
|
||||
// refresh forces a fresh steamcmd app_info fetch, bypassing the
|
||||
// agent-side 15-minute cache.
|
||||
bool refresh = 3;
|
||||
}
|
||||
|
||||
message UpdateCheckResult {
|
||||
string instance_id = 1;
|
||||
string app_id = 2;
|
||||
string branch = 3; // Steam branch compared ("public" when no -beta)
|
||||
string installed_buildid = 4; // from appmanifest ACF; "" if unreadable
|
||||
string latest_buildid = 5; // from app_info branches map; "" if fetch failed
|
||||
bool update_available = 6; // installed != latest (both non-empty)
|
||||
bool cached = 7; // latest came from the agent-side cache
|
||||
string error = 8; // non-empty on failure; other fields best-effort
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc (unknown)
|
||||
// source: panel/v1/agent.proto
|
||||
|
||||
package panelv1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Agent_Connect_FullMethodName = "/panel.v1.Agent/Connect"
|
||||
)
|
||||
|
||||
// AgentClient is the client API for Agent service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// Agent is the gRPC service a Target agent dials on the Controller.
|
||||
// A single persistent bidirectional stream carries all control-plane
|
||||
// traffic between Controller and Target: commands downstream, state
|
||||
// and events upstream.
|
||||
type AgentClient interface {
|
||||
Connect(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AgentEnvelope, ControllerEnvelope], error)
|
||||
}
|
||||
|
||||
type agentClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewAgentClient(cc grpc.ClientConnInterface) AgentClient {
|
||||
return &agentClient{cc}
|
||||
}
|
||||
|
||||
func (c *agentClient) Connect(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AgentEnvelope, ControllerEnvelope], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &Agent_ServiceDesc.Streams[0], Agent_Connect_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[AgentEnvelope, ControllerEnvelope]{ClientStream: stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Agent_ConnectClient = grpc.BidiStreamingClient[AgentEnvelope, ControllerEnvelope]
|
||||
|
||||
// AgentServer is the server API for Agent service.
|
||||
// All implementations must embed UnimplementedAgentServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// Agent is the gRPC service a Target agent dials on the Controller.
|
||||
// A single persistent bidirectional stream carries all control-plane
|
||||
// traffic between Controller and Target: commands downstream, state
|
||||
// and events upstream.
|
||||
type AgentServer interface {
|
||||
Connect(grpc.BidiStreamingServer[AgentEnvelope, ControllerEnvelope]) error
|
||||
mustEmbedUnimplementedAgentServer()
|
||||
}
|
||||
|
||||
// UnimplementedAgentServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedAgentServer struct{}
|
||||
|
||||
func (UnimplementedAgentServer) Connect(grpc.BidiStreamingServer[AgentEnvelope, ControllerEnvelope]) error {
|
||||
return status.Error(codes.Unimplemented, "method Connect not implemented")
|
||||
}
|
||||
func (UnimplementedAgentServer) mustEmbedUnimplementedAgentServer() {}
|
||||
func (UnimplementedAgentServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeAgentServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to AgentServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeAgentServer interface {
|
||||
mustEmbedUnimplementedAgentServer()
|
||||
}
|
||||
|
||||
func RegisterAgentServer(s grpc.ServiceRegistrar, srv AgentServer) {
|
||||
// If the following call panics, it indicates UnimplementedAgentServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Agent_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Agent_Connect_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(AgentServer).Connect(&grpc.GenericServerStream[AgentEnvelope, ControllerEnvelope]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Agent_ConnectServer = grpc.BidiStreamingServer[AgentEnvelope, ControllerEnvelope]
|
||||
|
||||
// Agent_ServiceDesc is the grpc.ServiceDesc for Agent service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Agent_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "panel.v1.Agent",
|
||||
HandlerType: (*AgentServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Connect",
|
||||
Handler: _Agent_Connect_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "panel/v1/agent.proto",
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc (unknown)
|
||||
// source: panel/v1/common.proto
|
||||
|
||||
package panelv1
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// RunMode selects how a game instance is launched on a Target.
|
||||
type RunMode int32
|
||||
|
||||
const (
|
||||
RunMode_RUN_MODE_UNSPECIFIED RunMode = 0
|
||||
RunMode_RUN_MODE_DOCKER RunMode = 1
|
||||
RunMode_RUN_MODE_HOST RunMode = 2
|
||||
)
|
||||
|
||||
// Enum value maps for RunMode.
|
||||
var (
|
||||
RunMode_name = map[int32]string{
|
||||
0: "RUN_MODE_UNSPECIFIED",
|
||||
1: "RUN_MODE_DOCKER",
|
||||
2: "RUN_MODE_HOST",
|
||||
}
|
||||
RunMode_value = map[string]int32{
|
||||
"RUN_MODE_UNSPECIFIED": 0,
|
||||
"RUN_MODE_DOCKER": 1,
|
||||
"RUN_MODE_HOST": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x RunMode) Enum() *RunMode {
|
||||
p := new(RunMode)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x RunMode) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (RunMode) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_panel_v1_common_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (RunMode) Type() protoreflect.EnumType {
|
||||
return &file_panel_v1_common_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x RunMode) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RunMode.Descriptor instead.
|
||||
func (RunMode) EnumDescriptor() ([]byte, []int) {
|
||||
return file_panel_v1_common_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
// InstanceStatus is the coarse lifecycle state of an instance.
|
||||
type InstanceStatus int32
|
||||
|
||||
const (
|
||||
InstanceStatus_INSTANCE_STATUS_UNSPECIFIED InstanceStatus = 0
|
||||
InstanceStatus_INSTANCE_STATUS_STOPPED InstanceStatus = 1
|
||||
InstanceStatus_INSTANCE_STATUS_STARTING InstanceStatus = 2
|
||||
InstanceStatus_INSTANCE_STATUS_RUNNING InstanceStatus = 3
|
||||
InstanceStatus_INSTANCE_STATUS_STOPPING InstanceStatus = 4
|
||||
InstanceStatus_INSTANCE_STATUS_CRASHED InstanceStatus = 5
|
||||
InstanceStatus_INSTANCE_STATUS_UPDATING InstanceStatus = 6
|
||||
)
|
||||
|
||||
// Enum value maps for InstanceStatus.
|
||||
var (
|
||||
InstanceStatus_name = map[int32]string{
|
||||
0: "INSTANCE_STATUS_UNSPECIFIED",
|
||||
1: "INSTANCE_STATUS_STOPPED",
|
||||
2: "INSTANCE_STATUS_STARTING",
|
||||
3: "INSTANCE_STATUS_RUNNING",
|
||||
4: "INSTANCE_STATUS_STOPPING",
|
||||
5: "INSTANCE_STATUS_CRASHED",
|
||||
6: "INSTANCE_STATUS_UPDATING",
|
||||
}
|
||||
InstanceStatus_value = map[string]int32{
|
||||
"INSTANCE_STATUS_UNSPECIFIED": 0,
|
||||
"INSTANCE_STATUS_STOPPED": 1,
|
||||
"INSTANCE_STATUS_STARTING": 2,
|
||||
"INSTANCE_STATUS_RUNNING": 3,
|
||||
"INSTANCE_STATUS_STOPPING": 4,
|
||||
"INSTANCE_STATUS_CRASHED": 5,
|
||||
"INSTANCE_STATUS_UPDATING": 6,
|
||||
}
|
||||
)
|
||||
|
||||
func (x InstanceStatus) Enum() *InstanceStatus {
|
||||
p := new(InstanceStatus)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x InstanceStatus) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (InstanceStatus) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_panel_v1_common_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (InstanceStatus) Type() protoreflect.EnumType {
|
||||
return &file_panel_v1_common_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x InstanceStatus) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use InstanceStatus.Descriptor instead.
|
||||
func (InstanceStatus) EnumDescriptor() ([]byte, []int) {
|
||||
return file_panel_v1_common_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
// ResourceLimits caps an instance's CPU / memory / disk usage.
|
||||
type ResourceLimits struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
CpuShares uint32 `protobuf:"varint,1,opt,name=cpu_shares,json=cpuShares,proto3" json:"cpu_shares,omitempty"` // relative weight, 1024 = 1 core equivalent
|
||||
MemBytes uint64 `protobuf:"varint,2,opt,name=mem_bytes,json=memBytes,proto3" json:"mem_bytes,omitempty"` // hard memory ceiling
|
||||
DiskBytes uint64 `protobuf:"varint,3,opt,name=disk_bytes,json=diskBytes,proto3" json:"disk_bytes,omitempty"` // data dir quota, 0 = unlimited
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ResourceLimits) Reset() {
|
||||
*x = ResourceLimits{}
|
||||
mi := &file_panel_v1_common_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ResourceLimits) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ResourceLimits) ProtoMessage() {}
|
||||
|
||||
func (x *ResourceLimits) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_panel_v1_common_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ResourceLimits.ProtoReflect.Descriptor instead.
|
||||
func (*ResourceLimits) Descriptor() ([]byte, []int) {
|
||||
return file_panel_v1_common_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ResourceLimits) GetCpuShares() uint32 {
|
||||
if x != nil {
|
||||
return x.CpuShares
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResourceLimits) GetMemBytes() uint64 {
|
||||
if x != nil {
|
||||
return x.MemBytes
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ResourceLimits) GetDiskBytes() uint64 {
|
||||
if x != nil {
|
||||
return x.DiskBytes
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// PortMap declares a port exposed by an instance.
|
||||
type PortMap struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // logical name: "game", "rcon", "query"
|
||||
Proto string `protobuf:"bytes,2,opt,name=proto,proto3" json:"proto,omitempty"` // "tcp" or "udp"
|
||||
ContainerPort uint32 `protobuf:"varint,3,opt,name=container_port,json=containerPort,proto3" json:"container_port,omitempty"` // port inside the sandbox
|
||||
HostPort uint32 `protobuf:"varint,4,opt,name=host_port,json=hostPort,proto3" json:"host_port,omitempty"` // port on the Target host (0 = same as container_port)
|
||||
Internal bool `protobuf:"varint,5,opt,name=internal,proto3" json:"internal,omitempty"` // true = not exposed outside the Target
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PortMap) Reset() {
|
||||
*x = PortMap{}
|
||||
mi := &file_panel_v1_common_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *PortMap) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PortMap) ProtoMessage() {}
|
||||
|
||||
func (x *PortMap) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_panel_v1_common_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PortMap.ProtoReflect.Descriptor instead.
|
||||
func (*PortMap) Descriptor() ([]byte, []int) {
|
||||
return file_panel_v1_common_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *PortMap) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PortMap) GetProto() string {
|
||||
if x != nil {
|
||||
return x.Proto
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PortMap) GetContainerPort() uint32 {
|
||||
if x != nil {
|
||||
return x.ContainerPort
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PortMap) GetHostPort() uint32 {
|
||||
if x != nil {
|
||||
return x.HostPort
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PortMap) GetInternal() bool {
|
||||
if x != nil {
|
||||
return x.Internal
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Error is a structured error payload carried on the wire.
|
||||
type Error struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` // short machine-readable code
|
||||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` // human-readable message
|
||||
At *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=at,proto3" json:"at,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Error) Reset() {
|
||||
*x = Error{}
|
||||
mi := &file_panel_v1_common_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Error) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Error) ProtoMessage() {}
|
||||
|
||||
func (x *Error) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_panel_v1_common_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Error.ProtoReflect.Descriptor instead.
|
||||
func (*Error) Descriptor() ([]byte, []int) {
|
||||
return file_panel_v1_common_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Error) GetCode() string {
|
||||
if x != nil {
|
||||
return x.Code
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Error) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Error) GetAt() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.At
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_panel_v1_common_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_panel_v1_common_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x15panel/v1/common.proto\x12\bpanel.v1\x1a\x1fgoogle/protobuf/timestamp.proto\"k\n" +
|
||||
"\x0eResourceLimits\x12\x1d\n" +
|
||||
"\n" +
|
||||
"cpu_shares\x18\x01 \x01(\rR\tcpuShares\x12\x1b\n" +
|
||||
"\tmem_bytes\x18\x02 \x01(\x04R\bmemBytes\x12\x1d\n" +
|
||||
"\n" +
|
||||
"disk_bytes\x18\x03 \x01(\x04R\tdiskBytes\"\x93\x01\n" +
|
||||
"\aPortMap\x12\x12\n" +
|
||||
"\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" +
|
||||
"\x05proto\x18\x02 \x01(\tR\x05proto\x12%\n" +
|
||||
"\x0econtainer_port\x18\x03 \x01(\rR\rcontainerPort\x12\x1b\n" +
|
||||
"\thost_port\x18\x04 \x01(\rR\bhostPort\x12\x1a\n" +
|
||||
"\binternal\x18\x05 \x01(\bR\binternal\"a\n" +
|
||||
"\x05Error\x12\x12\n" +
|
||||
"\x04code\x18\x01 \x01(\tR\x04code\x12\x18\n" +
|
||||
"\amessage\x18\x02 \x01(\tR\amessage\x12*\n" +
|
||||
"\x02at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x02at*K\n" +
|
||||
"\aRunMode\x12\x18\n" +
|
||||
"\x14RUN_MODE_UNSPECIFIED\x10\x00\x12\x13\n" +
|
||||
"\x0fRUN_MODE_DOCKER\x10\x01\x12\x11\n" +
|
||||
"\rRUN_MODE_HOST\x10\x02*\xe2\x01\n" +
|
||||
"\x0eInstanceStatus\x12\x1f\n" +
|
||||
"\x1bINSTANCE_STATUS_UNSPECIFIED\x10\x00\x12\x1b\n" +
|
||||
"\x17INSTANCE_STATUS_STOPPED\x10\x01\x12\x1c\n" +
|
||||
"\x18INSTANCE_STATUS_STARTING\x10\x02\x12\x1b\n" +
|
||||
"\x17INSTANCE_STATUS_RUNNING\x10\x03\x12\x1c\n" +
|
||||
"\x18INSTANCE_STATUS_STOPPING\x10\x04\x12\x1b\n" +
|
||||
"\x17INSTANCE_STATUS_CRASHED\x10\x05\x12\x1c\n" +
|
||||
"\x18INSTANCE_STATUS_UPDATING\x10\x06B2Z0github.com/dbledeez/panel/proto/panel/v1;panelv1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_panel_v1_common_proto_rawDescOnce sync.Once
|
||||
file_panel_v1_common_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_panel_v1_common_proto_rawDescGZIP() []byte {
|
||||
file_panel_v1_common_proto_rawDescOnce.Do(func() {
|
||||
file_panel_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_panel_v1_common_proto_rawDesc), len(file_panel_v1_common_proto_rawDesc)))
|
||||
})
|
||||
return file_panel_v1_common_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_panel_v1_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_panel_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_panel_v1_common_proto_goTypes = []any{
|
||||
(RunMode)(0), // 0: panel.v1.RunMode
|
||||
(InstanceStatus)(0), // 1: panel.v1.InstanceStatus
|
||||
(*ResourceLimits)(nil), // 2: panel.v1.ResourceLimits
|
||||
(*PortMap)(nil), // 3: panel.v1.PortMap
|
||||
(*Error)(nil), // 4: panel.v1.Error
|
||||
(*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp
|
||||
}
|
||||
var file_panel_v1_common_proto_depIdxs = []int32{
|
||||
5, // 0: panel.v1.Error.at:type_name -> google.protobuf.Timestamp
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_panel_v1_common_proto_init() }
|
||||
func file_panel_v1_common_proto_init() {
|
||||
if File_panel_v1_common_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_panel_v1_common_proto_rawDesc), len(file_panel_v1_common_proto_rawDesc)),
|
||||
NumEnums: 2,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_panel_v1_common_proto_goTypes,
|
||||
DependencyIndexes: file_panel_v1_common_proto_depIdxs,
|
||||
EnumInfos: file_panel_v1_common_proto_enumTypes,
|
||||
MessageInfos: file_panel_v1_common_proto_msgTypes,
|
||||
}.Build()
|
||||
File_panel_v1_common_proto = out.File
|
||||
file_panel_v1_common_proto_goTypes = nil
|
||||
file_panel_v1_common_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package panel.v1;
|
||||
|
||||
option go_package = "github.com/dbledeez/panel/proto/panel/v1;panelv1";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
// RunMode selects how a game instance is launched on a Target.
|
||||
enum RunMode {
|
||||
RUN_MODE_UNSPECIFIED = 0;
|
||||
RUN_MODE_DOCKER = 1;
|
||||
RUN_MODE_HOST = 2;
|
||||
}
|
||||
|
||||
// InstanceStatus is the coarse lifecycle state of an instance.
|
||||
enum InstanceStatus {
|
||||
INSTANCE_STATUS_UNSPECIFIED = 0;
|
||||
INSTANCE_STATUS_STOPPED = 1;
|
||||
INSTANCE_STATUS_STARTING = 2;
|
||||
INSTANCE_STATUS_RUNNING = 3;
|
||||
INSTANCE_STATUS_STOPPING = 4;
|
||||
INSTANCE_STATUS_CRASHED = 5;
|
||||
INSTANCE_STATUS_UPDATING = 6;
|
||||
}
|
||||
|
||||
// ResourceLimits caps an instance's CPU / memory / disk usage.
|
||||
message ResourceLimits {
|
||||
uint32 cpu_shares = 1; // relative weight, 1024 = 1 core equivalent
|
||||
uint64 mem_bytes = 2; // hard memory ceiling
|
||||
uint64 disk_bytes = 3; // data dir quota, 0 = unlimited
|
||||
}
|
||||
|
||||
// PortMap declares a port exposed by an instance.
|
||||
message PortMap {
|
||||
string name = 1; // logical name: "game", "rcon", "query"
|
||||
string proto = 2; // "tcp" or "udp"
|
||||
uint32 container_port = 3; // port inside the sandbox
|
||||
uint32 host_port = 4; // port on the Target host (0 = same as container_port)
|
||||
bool internal = 5; // true = not exposed outside the Target
|
||||
}
|
||||
|
||||
// Error is a structured error payload carried on the wire.
|
||||
message Error {
|
||||
string code = 1; // short machine-readable code
|
||||
string message = 2; // human-readable message
|
||||
google.protobuf.Timestamp at = 3;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,179 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package panel.v1;
|
||||
|
||||
option go_package = "github.com/dbledeez/panel/proto/panel/v1;panelv1";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "panel/v1/agent.proto";
|
||||
import "panel/v1/common.proto";
|
||||
|
||||
// Panel is the operator-facing API — what panelctl, the web UI, and future
|
||||
// automation talk to. The controller fulfils these by forwarding commands
|
||||
// to the appropriate Target agent over the Agent bidi stream.
|
||||
service Panel {
|
||||
rpc ListAgents(ListAgentsRequest) returns (ListAgentsResponse);
|
||||
rpc ListInstances(ListInstancesRequest) returns (ListInstancesResponse);
|
||||
rpc CreateInstance(CreateInstanceRequest) returns (CreateInstanceResponse);
|
||||
rpc StartInstance(StartInstanceRequest) returns (StartInstanceResponse);
|
||||
rpc StopInstance(StopInstanceRequest) returns (StopInstanceResponse);
|
||||
rpc DeleteInstance(DeleteInstanceRequest) returns (DeleteInstanceResponse);
|
||||
rpc ExecRCON(ExecRCONRequest) returns (ExecRCONResponse);
|
||||
rpc UpdateInstance(UpdateInstanceRequest) returns (UpdateInstanceResponse);
|
||||
rpc CreateBackup(CreateBackupRequest) returns (CreateBackupResponse);
|
||||
rpc RestoreBackup(RestoreBackupRequest) returns (RestoreBackupResponse);
|
||||
rpc StreamEvents(StreamEventsRequest) returns (stream Event);
|
||||
}
|
||||
|
||||
message ListAgentsRequest {}
|
||||
message ListAgentsResponse {
|
||||
repeated AgentInfo agents = 1;
|
||||
}
|
||||
|
||||
message AgentInfo {
|
||||
string agent_id = 1;
|
||||
string version = 2;
|
||||
string host_os = 3;
|
||||
string host_arch = 4;
|
||||
string hostname = 5;
|
||||
google.protobuf.Timestamp connected_at = 6;
|
||||
google.protobuf.Timestamp last_seen = 7;
|
||||
}
|
||||
|
||||
message CreateInstanceRequest {
|
||||
string agent_id = 1;
|
||||
string instance_id = 2;
|
||||
string module_id = 3;
|
||||
string version = 4;
|
||||
RunMode run_mode = 5;
|
||||
string data_path = 6; // optional; agent will derive if empty
|
||||
map<string, string> config_values = 7; // user-supplied overrides, module-validated
|
||||
repeated PortMap ports = 8; // port overrides
|
||||
}
|
||||
message CreateInstanceResponse {
|
||||
string instance_id = 1;
|
||||
string correlation_id = 2;
|
||||
}
|
||||
|
||||
message StartInstanceRequest {
|
||||
string agent_id = 1;
|
||||
string instance_id = 2;
|
||||
}
|
||||
message StartInstanceResponse {
|
||||
string correlation_id = 1;
|
||||
}
|
||||
|
||||
message StopInstanceRequest {
|
||||
string agent_id = 1;
|
||||
string instance_id = 2;
|
||||
uint32 grace_seconds = 3;
|
||||
}
|
||||
message StopInstanceResponse {
|
||||
string correlation_id = 1;
|
||||
}
|
||||
|
||||
message DeleteInstanceRequest {
|
||||
string agent_id = 1;
|
||||
string instance_id = 2;
|
||||
uint32 grace_seconds = 3;
|
||||
bool purge_volumes = 4;
|
||||
}
|
||||
message DeleteInstanceResponse {
|
||||
string correlation_id = 1;
|
||||
}
|
||||
|
||||
// ExecRCON sends an ad-hoc RCON command to the running instance and waits
|
||||
// synchronously for the agent's response. The controller correlates the
|
||||
// request → response round-trip by correlation_id.
|
||||
message ExecRCONRequest {
|
||||
string agent_id = 1;
|
||||
string instance_id = 2;
|
||||
string command = 3;
|
||||
uint32 timeout_ms = 4; // optional; default 10000
|
||||
}
|
||||
message ExecRCONResponse {
|
||||
string output = 1;
|
||||
string error = 2;
|
||||
string correlation_id = 3;
|
||||
}
|
||||
|
||||
// UpdateInstance kicks off a module-declared update provider against the
|
||||
// target instance. The agent runs it asynchronously; progress streams as
|
||||
// LogLines on the event bus.
|
||||
message UpdateInstanceRequest {
|
||||
string agent_id = 1;
|
||||
string instance_id = 2;
|
||||
string provider_id = 3; // empty = first provider
|
||||
}
|
||||
message UpdateInstanceResponse {
|
||||
bool accepted = 1;
|
||||
string error = 2;
|
||||
string provider_id = 3;
|
||||
string provider_kind = 4;
|
||||
string correlation_id = 5;
|
||||
}
|
||||
|
||||
message CreateBackupRequest {
|
||||
string agent_id = 1;
|
||||
string instance_id = 2;
|
||||
string description = 3;
|
||||
}
|
||||
message CreateBackupResponse {
|
||||
string backup_id = 1;
|
||||
string path = 2;
|
||||
int64 size_bytes = 3;
|
||||
string error = 4;
|
||||
}
|
||||
|
||||
message RestoreBackupRequest {
|
||||
string agent_id = 1;
|
||||
string instance_id = 2;
|
||||
string backup_id = 3;
|
||||
}
|
||||
message RestoreBackupResponse {
|
||||
int64 bytes_restored = 1;
|
||||
string error = 2;
|
||||
}
|
||||
|
||||
message InstanceInfo {
|
||||
string instance_id = 1;
|
||||
string agent_id = 2;
|
||||
string module_id = 3;
|
||||
string module_version = 4;
|
||||
RunMode run_mode = 5;
|
||||
InstanceStatus status = 6;
|
||||
int32 last_exit_code = 7;
|
||||
string data_path = 8;
|
||||
string detail = 9;
|
||||
google.protobuf.Timestamp created_at = 10;
|
||||
google.protobuf.Timestamp updated_at = 11;
|
||||
}
|
||||
|
||||
message ListInstancesRequest {
|
||||
string agent_id = 1; // optional filter by agent
|
||||
}
|
||||
message ListInstancesResponse {
|
||||
repeated InstanceInfo instances = 1;
|
||||
}
|
||||
|
||||
// StreamEvents — server streaming of the live event bus. Filters are
|
||||
// optional AND-ed; empty strings = no filter on that field.
|
||||
message StreamEventsRequest {
|
||||
string instance_id = 1;
|
||||
string agent_id = 2;
|
||||
}
|
||||
|
||||
// Event is the controller's normalized form of everything an agent sends
|
||||
// up that isn't a one-shot command result. It wraps the original payload
|
||||
// and annotates it with the agent_id for filtering + display.
|
||||
message Event {
|
||||
string agent_id = 1;
|
||||
google.protobuf.Timestamp at = 2;
|
||||
oneof payload {
|
||||
InstanceStateUpdate instance_state = 10;
|
||||
AppStateUpdate app_state = 11;
|
||||
PlayerEvent player = 12;
|
||||
LogLine log = 13;
|
||||
InstanceStatsUpdate instance_stats = 14;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,513 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc (unknown)
|
||||
// source: panel/v1/panel.proto
|
||||
|
||||
package panelv1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Panel_ListAgents_FullMethodName = "/panel.v1.Panel/ListAgents"
|
||||
Panel_ListInstances_FullMethodName = "/panel.v1.Panel/ListInstances"
|
||||
Panel_CreateInstance_FullMethodName = "/panel.v1.Panel/CreateInstance"
|
||||
Panel_StartInstance_FullMethodName = "/panel.v1.Panel/StartInstance"
|
||||
Panel_StopInstance_FullMethodName = "/panel.v1.Panel/StopInstance"
|
||||
Panel_DeleteInstance_FullMethodName = "/panel.v1.Panel/DeleteInstance"
|
||||
Panel_ExecRCON_FullMethodName = "/panel.v1.Panel/ExecRCON"
|
||||
Panel_UpdateInstance_FullMethodName = "/panel.v1.Panel/UpdateInstance"
|
||||
Panel_CreateBackup_FullMethodName = "/panel.v1.Panel/CreateBackup"
|
||||
Panel_RestoreBackup_FullMethodName = "/panel.v1.Panel/RestoreBackup"
|
||||
Panel_StreamEvents_FullMethodName = "/panel.v1.Panel/StreamEvents"
|
||||
)
|
||||
|
||||
// PanelClient is the client API for Panel service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// Panel is the operator-facing API — what panelctl, the web UI, and future
|
||||
// automation talk to. The controller fulfils these by forwarding commands
|
||||
// to the appropriate Target agent over the Agent bidi stream.
|
||||
type PanelClient interface {
|
||||
ListAgents(ctx context.Context, in *ListAgentsRequest, opts ...grpc.CallOption) (*ListAgentsResponse, error)
|
||||
ListInstances(ctx context.Context, in *ListInstancesRequest, opts ...grpc.CallOption) (*ListInstancesResponse, error)
|
||||
CreateInstance(ctx context.Context, in *CreateInstanceRequest, opts ...grpc.CallOption) (*CreateInstanceResponse, error)
|
||||
StartInstance(ctx context.Context, in *StartInstanceRequest, opts ...grpc.CallOption) (*StartInstanceResponse, error)
|
||||
StopInstance(ctx context.Context, in *StopInstanceRequest, opts ...grpc.CallOption) (*StopInstanceResponse, error)
|
||||
DeleteInstance(ctx context.Context, in *DeleteInstanceRequest, opts ...grpc.CallOption) (*DeleteInstanceResponse, error)
|
||||
ExecRCON(ctx context.Context, in *ExecRCONRequest, opts ...grpc.CallOption) (*ExecRCONResponse, error)
|
||||
UpdateInstance(ctx context.Context, in *UpdateInstanceRequest, opts ...grpc.CallOption) (*UpdateInstanceResponse, error)
|
||||
CreateBackup(ctx context.Context, in *CreateBackupRequest, opts ...grpc.CallOption) (*CreateBackupResponse, error)
|
||||
RestoreBackup(ctx context.Context, in *RestoreBackupRequest, opts ...grpc.CallOption) (*RestoreBackupResponse, error)
|
||||
StreamEvents(ctx context.Context, in *StreamEventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Event], error)
|
||||
}
|
||||
|
||||
type panelClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewPanelClient(cc grpc.ClientConnInterface) PanelClient {
|
||||
return &panelClient{cc}
|
||||
}
|
||||
|
||||
func (c *panelClient) ListAgents(ctx context.Context, in *ListAgentsRequest, opts ...grpc.CallOption) (*ListAgentsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListAgentsResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_ListAgents_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) ListInstances(ctx context.Context, in *ListInstancesRequest, opts ...grpc.CallOption) (*ListInstancesResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListInstancesResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_ListInstances_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) CreateInstance(ctx context.Context, in *CreateInstanceRequest, opts ...grpc.CallOption) (*CreateInstanceResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreateInstanceResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_CreateInstance_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) StartInstance(ctx context.Context, in *StartInstanceRequest, opts ...grpc.CallOption) (*StartInstanceResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(StartInstanceResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_StartInstance_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) StopInstance(ctx context.Context, in *StopInstanceRequest, opts ...grpc.CallOption) (*StopInstanceResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(StopInstanceResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_StopInstance_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) DeleteInstance(ctx context.Context, in *DeleteInstanceRequest, opts ...grpc.CallOption) (*DeleteInstanceResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeleteInstanceResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_DeleteInstance_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) ExecRCON(ctx context.Context, in *ExecRCONRequest, opts ...grpc.CallOption) (*ExecRCONResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ExecRCONResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_ExecRCON_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) UpdateInstance(ctx context.Context, in *UpdateInstanceRequest, opts ...grpc.CallOption) (*UpdateInstanceResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UpdateInstanceResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_UpdateInstance_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) CreateBackup(ctx context.Context, in *CreateBackupRequest, opts ...grpc.CallOption) (*CreateBackupResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreateBackupResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_CreateBackup_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) RestoreBackup(ctx context.Context, in *RestoreBackupRequest, opts ...grpc.CallOption) (*RestoreBackupResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RestoreBackupResponse)
|
||||
err := c.cc.Invoke(ctx, Panel_RestoreBackup_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *panelClient) StreamEvents(ctx context.Context, in *StreamEventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Event], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &Panel_ServiceDesc.Streams[0], Panel_StreamEvents_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[StreamEventsRequest, Event]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Panel_StreamEventsClient = grpc.ServerStreamingClient[Event]
|
||||
|
||||
// PanelServer is the server API for Panel service.
|
||||
// All implementations must embed UnimplementedPanelServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// Panel is the operator-facing API — what panelctl, the web UI, and future
|
||||
// automation talk to. The controller fulfils these by forwarding commands
|
||||
// to the appropriate Target agent over the Agent bidi stream.
|
||||
type PanelServer interface {
|
||||
ListAgents(context.Context, *ListAgentsRequest) (*ListAgentsResponse, error)
|
||||
ListInstances(context.Context, *ListInstancesRequest) (*ListInstancesResponse, error)
|
||||
CreateInstance(context.Context, *CreateInstanceRequest) (*CreateInstanceResponse, error)
|
||||
StartInstance(context.Context, *StartInstanceRequest) (*StartInstanceResponse, error)
|
||||
StopInstance(context.Context, *StopInstanceRequest) (*StopInstanceResponse, error)
|
||||
DeleteInstance(context.Context, *DeleteInstanceRequest) (*DeleteInstanceResponse, error)
|
||||
ExecRCON(context.Context, *ExecRCONRequest) (*ExecRCONResponse, error)
|
||||
UpdateInstance(context.Context, *UpdateInstanceRequest) (*UpdateInstanceResponse, error)
|
||||
CreateBackup(context.Context, *CreateBackupRequest) (*CreateBackupResponse, error)
|
||||
RestoreBackup(context.Context, *RestoreBackupRequest) (*RestoreBackupResponse, error)
|
||||
StreamEvents(*StreamEventsRequest, grpc.ServerStreamingServer[Event]) error
|
||||
mustEmbedUnimplementedPanelServer()
|
||||
}
|
||||
|
||||
// UnimplementedPanelServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedPanelServer struct{}
|
||||
|
||||
func (UnimplementedPanelServer) ListAgents(context.Context, *ListAgentsRequest) (*ListAgentsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListAgents not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) ListInstances(context.Context, *ListInstancesRequest) (*ListInstancesResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListInstances not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) CreateInstance(context.Context, *CreateInstanceRequest) (*CreateInstanceResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateInstance not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) StartInstance(context.Context, *StartInstanceRequest) (*StartInstanceResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method StartInstance not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) StopInstance(context.Context, *StopInstanceRequest) (*StopInstanceResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method StopInstance not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) DeleteInstance(context.Context, *DeleteInstanceRequest) (*DeleteInstanceResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteInstance not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) ExecRCON(context.Context, *ExecRCONRequest) (*ExecRCONResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ExecRCON not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) UpdateInstance(context.Context, *UpdateInstanceRequest) (*UpdateInstanceResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateInstance not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) CreateBackup(context.Context, *CreateBackupRequest) (*CreateBackupResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateBackup not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) RestoreBackup(context.Context, *RestoreBackupRequest) (*RestoreBackupResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RestoreBackup not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) StreamEvents(*StreamEventsRequest, grpc.ServerStreamingServer[Event]) error {
|
||||
return status.Error(codes.Unimplemented, "method StreamEvents not implemented")
|
||||
}
|
||||
func (UnimplementedPanelServer) mustEmbedUnimplementedPanelServer() {}
|
||||
func (UnimplementedPanelServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafePanelServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to PanelServer will
|
||||
// result in compilation errors.
|
||||
type UnsafePanelServer interface {
|
||||
mustEmbedUnimplementedPanelServer()
|
||||
}
|
||||
|
||||
func RegisterPanelServer(s grpc.ServiceRegistrar, srv PanelServer) {
|
||||
// If the following call panics, it indicates UnimplementedPanelServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Panel_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Panel_ListAgents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListAgentsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).ListAgents(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_ListAgents_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).ListAgents(ctx, req.(*ListAgentsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_ListInstances_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListInstancesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).ListInstances(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_ListInstances_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).ListInstances(ctx, req.(*ListInstancesRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_CreateInstance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateInstanceRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).CreateInstance(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_CreateInstance_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).CreateInstance(ctx, req.(*CreateInstanceRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_StartInstance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StartInstanceRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).StartInstance(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_StartInstance_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).StartInstance(ctx, req.(*StartInstanceRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_StopInstance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StopInstanceRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).StopInstance(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_StopInstance_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).StopInstance(ctx, req.(*StopInstanceRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_DeleteInstance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteInstanceRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).DeleteInstance(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_DeleteInstance_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).DeleteInstance(ctx, req.(*DeleteInstanceRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_ExecRCON_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ExecRCONRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).ExecRCON(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_ExecRCON_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).ExecRCON(ctx, req.(*ExecRCONRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_UpdateInstance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateInstanceRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).UpdateInstance(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_UpdateInstance_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).UpdateInstance(ctx, req.(*UpdateInstanceRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_CreateBackup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateBackupRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).CreateBackup(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_CreateBackup_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).CreateBackup(ctx, req.(*CreateBackupRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_RestoreBackup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RestoreBackupRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(PanelServer).RestoreBackup(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Panel_RestoreBackup_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(PanelServer).RestoreBackup(ctx, req.(*RestoreBackupRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Panel_StreamEvents_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(StreamEventsRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(PanelServer).StreamEvents(m, &grpc.GenericServerStream[StreamEventsRequest, Event]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Panel_StreamEventsServer = grpc.ServerStreamingServer[Event]
|
||||
|
||||
// Panel_ServiceDesc is the grpc.ServiceDesc for Panel service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Panel_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "panel.v1.Panel",
|
||||
HandlerType: (*PanelServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "ListAgents",
|
||||
Handler: _Panel_ListAgents_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListInstances",
|
||||
Handler: _Panel_ListInstances_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateInstance",
|
||||
Handler: _Panel_CreateInstance_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "StartInstance",
|
||||
Handler: _Panel_StartInstance_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "StopInstance",
|
||||
Handler: _Panel_StopInstance_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DeleteInstance",
|
||||
Handler: _Panel_DeleteInstance_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ExecRCON",
|
||||
Handler: _Panel_ExecRCON_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateInstance",
|
||||
Handler: _Panel_UpdateInstance_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateBackup",
|
||||
Handler: _Panel_CreateBackup_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RestoreBackup",
|
||||
Handler: _Panel_RestoreBackup_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "StreamEvents",
|
||||
Handler: _Panel_StreamEvents_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "panel/v1/panel.proto",
|
||||
}
|
||||
Reference in New Issue
Block a user