feat: support custom server deployment drafts

This commit is contained in:
npc0-hue
2026-07-24 16:56:28 +08:00
parent 292b380f3c
commit 220ef91a8e
36 changed files with 1520 additions and 85 deletions
+1
View File
@@ -4,6 +4,7 @@ import "time"
type RunJobProgressReport struct {
Percent int
Phase string
Message string
}
+134
View File
@@ -320,11 +320,25 @@ type GamePluginBridge struct {
Actions []string
}
// PluginCreateField is a safe, declarative game setting exposed in the
// management console during server definition creation. It deliberately
// excludes command text, host paths, secrets, and arbitrary JSON schemas.
type PluginCreateField struct {
Key string
Label string
Type string
Required bool
DefaultValue string
Options []string
ConfigKey string
}
type GamePluginManifestServer struct {
Type string
DisplayName string
SupportedOS []string
CreateFormSchema string
CreateFields []PluginCreateField
}
type GamePluginManifestAI struct {
@@ -554,6 +568,7 @@ type GamePlugin struct {
SupportedOS []string
ManifestRef string
CreateFormSchemaRef string
CreateFields []PluginCreateField
RequiredRunCapabilities []string
DeclaredPermissions []string
Permissions PluginPermissions
@@ -580,6 +595,7 @@ type PluginMarketplacePlugin struct {
SupportedOS []string
ManifestRef string
CreateFormSchemaRef string
CreateFields []PluginCreateField
Capabilities []string
DeclaredPermissions []string
Permissions PluginPermissions
@@ -676,6 +692,9 @@ type ServerInstance struct {
ConfigUpdatedAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
// Deployment stores operator-supplied deployment inputs. Its protected path
// and command values are never included in normal platform read projections.
Deployment ServerDeploymentDefinition
}
type ServerInstanceUpdate struct {
@@ -715,6 +734,77 @@ type ServerConfig struct {
UpdatedAt time.Time
}
// ServerDeploymentMode selects how Run prepares and launches a server.
type ServerDeploymentMode string
const (
ServerDeploymentModeGuided ServerDeploymentMode = "guided-install"
ServerDeploymentModeExisting ServerDeploymentMode = "existing-server"
ServerDeploymentModeCustom ServerDeploymentMode = "custom-command"
)
// ServerCommandShell controls deliberate shell interpretation of a command.
// Empty means Run receives the command as its default argv-compatible form.
type ServerCommandShell string
const (
ServerCommandShellNone ServerCommandShell = ""
ServerCommandShellPosix ServerCommandShell = "posix-sh"
ServerCommandShellPowerShell ServerCommandShell = "powershell"
ServerCommandShellCmd ServerCommandShell = "cmd"
)
// ServerDeploymentDefinition persists game inputs plus write-only execution
// material. It is copied into a leased Run assignment but never into DTO read
// views; callers receive ServerDeploymentView instead.
type ServerDeploymentDefinition struct {
Mode ServerDeploymentMode
ProfileKey string
RuntimeBindings map[string]string
CreateInputs map[string]string
ServerRoot string
WorkingDirectory string
InstallCommand string
StartCommand string
StopCommand string
StatusCommand string
Shell ServerCommandShell
Revision int
UpdatedAt time.Time
}
type ServerDeploymentUpdate struct {
RunEndpointID string
Mode ServerDeploymentMode
ProfileKey string
RuntimeBindings map[string]string
CreateInputs map[string]string
ServerRoot string
WorkingDirectory string
InstallCommand string
StartCommand string
StopCommand string
StatusCommand string
Shell ServerCommandShell
}
// ServerDeploymentView is the intentionally redacted read model.
type ServerDeploymentView struct {
ServerInstanceID string
Mode ServerDeploymentMode
ProfileKey string
CreateInputs map[string]string
ServerRootConfigured bool
WorkingDirectoryConfigured bool
InstallCommandConfigured bool
StartCommandConfigured bool
StopCommandConfigured bool
StatusCommandConfigured bool
Shell ServerCommandShell
Revision int
UpdatedAt time.Time
}
type ConfigDiffLine struct {
Kind string
OldNumber int
@@ -821,6 +911,12 @@ const (
JobCapabilityDependenciesCheck = "dependencies.check"
JobCapabilityDependenciesInstall = "dependencies.install"
JobCapabilityLogsBackfill = "logs.backfill"
// JobCapabilityDeploymentPlan gates Run implementations that understand
// protected deployment definitions, absolute paths, and custom commands.
JobCapabilityDeploymentPlan = "deployment.plan.v1"
JobCapabilityDeploymentShellPosix = "deployment.shell.posix-sh"
JobCapabilityDeploymentShellPowerShell = "deployment.shell.powershell"
JobCapabilityDeploymentShellCmd = "deployment.shell.cmd"
)
type RunEndpoint struct {
@@ -837,6 +933,7 @@ type RunEndpoint struct {
type JobProgress struct {
Percent int
Phase string
Message string
}
@@ -861,6 +958,7 @@ type JobExecutionInput struct {
Inputs map[string]string
DLLExtensions []RuntimeDLLExtensionPlan
SourceRCON *RuntimeSourceRCONPlan
Deployment *ServerDeploymentDefinition
}
type JobExecutionResult struct {
@@ -1372,6 +1470,7 @@ func CopyGamePlugin(plugin GamePlugin) GamePlugin {
plugin.RequiredRunCapabilities = CopyStringSlice(plugin.RequiredRunCapabilities)
plugin.DeclaredPermissions = CopyStringSlice(plugin.DeclaredPermissions)
plugin.SupportedOS = CopyStringSlice(plugin.SupportedOS)
plugin.CreateFields = CopyPluginCreateFields(plugin.CreateFields)
plugin.BridgeActions = CopyStringSlice(plugin.BridgeActions)
plugin.Pages = CopyGamePluginPageSlice(plugin.Pages)
plugin.Tags = CopyStringSlice(plugin.Tags)
@@ -1387,6 +1486,7 @@ func CopyGamePlugin(plugin GamePlugin) GamePlugin {
func CopyPluginMarketplacePlugin(plugin PluginMarketplacePlugin) PluginMarketplacePlugin {
plugin.SupportedOS = CopyStringSlice(plugin.SupportedOS)
plugin.Capabilities = CopyStringSlice(plugin.Capabilities)
plugin.CreateFields = CopyPluginCreateFields(plugin.CreateFields)
plugin.DeclaredPermissions = CopyStringSlice(plugin.DeclaredPermissions)
plugin.BridgeActions = CopyStringSlice(plugin.BridgeActions)
plugin.Pages = CopyGamePluginPageSlice(plugin.Pages)
@@ -1419,6 +1519,7 @@ func CopyGamePluginManifestRegistration(registration GamePluginManifestRegistrat
func CopyGamePluginManifest(manifest GamePluginManifest) GamePluginManifest {
manifest.Tags = CopyStringSlice(manifest.Tags)
manifest.Server.SupportedOS = CopyStringSlice(manifest.Server.SupportedOS)
manifest.Server.CreateFields = CopyPluginCreateFields(manifest.Server.CreateFields)
manifest.Bridge.Actions = CopyStringSlice(manifest.Bridge.Actions)
manifest.Capabilities = CopyStringSlice(manifest.Capabilities)
manifest.Permissions = CopyStringSlice(manifest.Permissions)
@@ -1431,6 +1532,17 @@ func CopyGamePluginManifest(manifest GamePluginManifest) GamePluginManifest {
return manifest
}
func CopyPluginCreateFields(fields []PluginCreateField) []PluginCreateField {
if fields == nil {
return nil
}
copy := append([]PluginCreateField(nil), fields...)
for i := range copy {
copy[i].Options = CopyStringSlice(copy[i].Options)
}
return copy
}
func CopyGamePluginProductionLifecycle(lifecycle GamePluginProductionLifecycle) GamePluginProductionLifecycle {
lifecycle.Operations = CopyStringSlice(lifecycle.Operations)
lifecycle.ApprovalRequired = CopyStringSlice(lifecycle.ApprovalRequired)
@@ -1524,9 +1636,27 @@ func CopyPluginBridgeExecuteResponse(response PluginBridgeExecuteResponse) Plugi
func CopyServerInstance(instance ServerInstance) ServerInstance {
instance.AdminUserIDs = CopyStringSlice(instance.AdminUserIDs)
instance.Deployment = CopyServerDeploymentDefinition(instance.Deployment)
return instance
}
func CopyServerDeploymentDefinition(definition ServerDeploymentDefinition) ServerDeploymentDefinition {
definition.RuntimeBindings = CopyStringMap(definition.RuntimeBindings)
definition.CreateInputs = CopyStringMap(definition.CreateInputs)
return definition
}
func CopyServerDeploymentUpdate(update ServerDeploymentUpdate) ServerDeploymentUpdate {
update.RuntimeBindings = CopyStringMap(update.RuntimeBindings)
update.CreateInputs = CopyStringMap(update.CreateInputs)
return update
}
func CopyServerDeploymentView(view ServerDeploymentView) ServerDeploymentView {
view.CreateInputs = CopyStringMap(view.CreateInputs)
return view
}
func CopyPlatformResourceUsage(usage PlatformResourceUsage) PlatformResourceUsage {
return usage
}
@@ -1583,6 +1713,10 @@ func CopyJob(job Job) Job {
job.ExecutionInput.Inputs = CopyStringMap(job.ExecutionInput.Inputs)
job.ExecutionInput.DLLExtensions = append([]RuntimeDLLExtensionPlan(nil), job.ExecutionInput.DLLExtensions...)
job.ExecutionInput.SourceRCON = CopyRuntimeSourceRCONPlan(job.ExecutionInput.SourceRCON)
if job.ExecutionInput.Deployment != nil {
copy := CopyServerDeploymentDefinition(*job.ExecutionInput.Deployment)
job.ExecutionInput.Deployment = &copy
}
return job
}
+2
View File
@@ -25,6 +25,7 @@ type ServerLifecycleCreate struct {
IdempotencyKey string
ProfileKey string
Bindings map[string]string
Deployment ServerDeploymentDefinition
}
type ServerLifecycleCommand struct {
@@ -57,6 +58,7 @@ func LifecycleCapabilityForAction(action ServerLifecycleAction) string {
func CopyServerLifecycleCreate(create ServerLifecycleCreate) ServerLifecycleCreate {
create.Bindings = CopyStringMap(create.Bindings)
create.Deployment = CopyServerDeploymentDefinition(create.Deployment)
return create
}