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
+43 -15
View File
@@ -92,20 +92,38 @@ type RunJobResultRequest struct {
}
type RunJobExecutionInputBody struct {
WorkspaceScope string `json:"workspaceScope,omitempty"`
Content string `json:"content,omitempty"`
ExpectedVersion int `json:"expectedVersion,omitempty"`
ExpectedChecksum string `json:"expectedChecksum,omitempty"`
MaxReadBytes int `json:"maxReadBytes,omitempty"`
RemoteAdapterKey string `json:"remoteAdapterKey,omitempty"`
RemoteAdapterKind string `json:"remoteAdapterKind,omitempty"`
TimeoutSeconds int `json:"timeoutSeconds,omitempty"`
PluginID string `json:"pluginId,omitempty"`
LifecycleOperation string `json:"lifecycleOperation,omitempty"`
TargetVersion string `json:"targetVersion,omitempty"`
Inputs map[string]string `json:"inputs,omitempty"`
DLLExtensions []RuntimeDLLExtensionPlanBody `json:"dllExtensions,omitempty"`
SourceRCON *RuntimeSourceRCONPlanBody `json:"sourceRcon,omitempty"`
WorkspaceScope string `json:"workspaceScope,omitempty"`
Content string `json:"content,omitempty"`
ExpectedVersion int `json:"expectedVersion,omitempty"`
ExpectedChecksum string `json:"expectedChecksum,omitempty"`
MaxReadBytes int `json:"maxReadBytes,omitempty"`
RemoteAdapterKey string `json:"remoteAdapterKey,omitempty"`
RemoteAdapterKind string `json:"remoteAdapterKind,omitempty"`
TimeoutSeconds int `json:"timeoutSeconds,omitempty"`
PluginID string `json:"pluginId,omitempty"`
LifecycleOperation string `json:"lifecycleOperation,omitempty"`
TargetVersion string `json:"targetVersion,omitempty"`
Inputs map[string]string `json:"inputs,omitempty"`
DLLExtensions []RuntimeDLLExtensionPlanBody `json:"dllExtensions,omitempty"`
SourceRCON *RuntimeSourceRCONPlanBody `json:"sourceRcon,omitempty"`
Deployment *ServerDeploymentExecutionBody `json:"deployment,omitempty"`
}
// ServerDeploymentExecutionBody is included only in a leased Run assignment.
// It is intentionally absent from all public server and job response DTOs.
type ServerDeploymentExecutionBody struct {
Mode domain.ServerDeploymentMode `json:"mode"`
ProfileKey string `json:"profileKey,omitempty"`
RuntimeBindings map[string]string `json:"runtimeBindings,omitempty"`
CreateInputs map[string]string `json:"createInputs,omitempty"`
ServerRoot string `json:"serverRoot,omitempty"`
WorkingDirectory string `json:"workingDirectory,omitempty"`
InstallCommand string `json:"installCommand,omitempty"`
StartCommand string `json:"startCommand,omitempty"`
StopCommand string `json:"stopCommand,omitempty"`
StatusCommand string `json:"statusCommand,omitempty"`
Shell domain.ServerCommandShell `json:"shell,omitempty"`
Revision int `json:"revision"`
}
type RuntimeSourceRCONPlanBody struct {
@@ -565,7 +583,7 @@ func RunJobAssignmentFromDomain(assignment domain.RunJobAssignment) RunJobAssign
State: assignment.State,
Progress: progressReportFromDomain(assignment.Progress),
ResultRef: assignment.ResultRef,
ExecutionInput: RunJobExecutionInputBody{WorkspaceScope: assignment.ExecutionInput.WorkspaceScope, Content: assignment.ExecutionInput.Content, ExpectedVersion: assignment.ExecutionInput.ExpectedVersion, ExpectedChecksum: assignment.ExecutionInput.ExpectedChecksum, MaxReadBytes: assignment.ExecutionInput.MaxReadBytes, RemoteAdapterKey: assignment.ExecutionInput.RemoteAdapterKey, RemoteAdapterKind: assignment.ExecutionInput.RemoteAdapterKind, TimeoutSeconds: assignment.ExecutionInput.TimeoutSeconds, PluginID: assignment.ExecutionInput.PluginID, LifecycleOperation: assignment.ExecutionInput.LifecycleOperation, TargetVersion: assignment.ExecutionInput.TargetVersion, Inputs: domain.CopyStringMap(assignment.ExecutionInput.Inputs), DLLExtensions: dllExtensionPlansFromDomain(assignment.ExecutionInput.DLLExtensions), SourceRCON: runtimeSourceRCONPlanFromDomain(assignment.ExecutionInput.SourceRCON)},
ExecutionInput: RunJobExecutionInputBody{WorkspaceScope: assignment.ExecutionInput.WorkspaceScope, Content: assignment.ExecutionInput.Content, ExpectedVersion: assignment.ExecutionInput.ExpectedVersion, ExpectedChecksum: assignment.ExecutionInput.ExpectedChecksum, MaxReadBytes: assignment.ExecutionInput.MaxReadBytes, RemoteAdapterKey: assignment.ExecutionInput.RemoteAdapterKey, RemoteAdapterKind: assignment.ExecutionInput.RemoteAdapterKind, TimeoutSeconds: assignment.ExecutionInput.TimeoutSeconds, PluginID: assignment.ExecutionInput.PluginID, LifecycleOperation: assignment.ExecutionInput.LifecycleOperation, TargetVersion: assignment.ExecutionInput.TargetVersion, Inputs: domain.CopyStringMap(assignment.ExecutionInput.Inputs), DLLExtensions: dllExtensionPlansFromDomain(assignment.ExecutionInput.DLLExtensions), SourceRCON: runtimeSourceRCONPlanFromDomain(assignment.ExecutionInput.SourceRCON), Deployment: deploymentExecutionFromDomain(assignment.ExecutionInput.Deployment)},
LeaseToken: assignment.LeaseToken,
Attempt: assignment.Attempt,
MaxAttempts: assignment.MaxAttempts,
@@ -578,6 +596,14 @@ func RunJobAssignmentFromDomain(assignment domain.RunJobAssignment) RunJobAssign
}
}
func deploymentExecutionFromDomain(definition *domain.ServerDeploymentDefinition) *ServerDeploymentExecutionBody {
if definition == nil {
return nil
}
copy := domain.CopyServerDeploymentDefinition(*definition)
return &ServerDeploymentExecutionBody{Mode: copy.Mode, ProfileKey: copy.ProfileKey, RuntimeBindings: copy.RuntimeBindings, CreateInputs: copy.CreateInputs, ServerRoot: copy.ServerRoot, WorkingDirectory: copy.WorkingDirectory, InstallCommand: copy.InstallCommand, StartCommand: copy.StartCommand, StopCommand: copy.StopCommand, StatusCommand: copy.StatusCommand, Shell: copy.Shell, Revision: copy.Revision}
}
func runtimeSourceRCONPlanFromDomain(plan *domain.RuntimeSourceRCONPlan) *RuntimeSourceRCONPlanBody {
if plan == nil {
return nil
@@ -588,6 +614,7 @@ func runtimeSourceRCONPlanFromDomain(plan *domain.RuntimeSourceRCONPlan) *Runtim
func progressReportToDomain(progress JobProgressBody) domain.RunJobProgressReport {
return domain.RunJobProgressReport{
Percent: progress.Percent,
Phase: progress.Phase,
Message: progress.Message,
}
}
@@ -595,6 +622,7 @@ func progressReportToDomain(progress JobProgressBody) domain.RunJobProgressRepor
func progressReportFromDomain(progress domain.RunJobProgressReport) JobProgressBody {
return JobProgressBody{
Percent: progress.Percent,
Phase: progress.Phase,
Message: progress.Message,
}
}
+45 -4
View File
@@ -187,11 +187,22 @@ type GamePluginBridgeBody struct {
Actions []string `json:"actions"`
}
type PluginCreateFieldBody struct {
Key string `json:"key"`
Label string `json:"label"`
Type string `json:"type"`
Required bool `json:"required,omitempty"`
DefaultValue string `json:"defaultValue,omitempty"`
Options []string `json:"options,omitempty"`
ConfigKey string `json:"configKey,omitempty"`
}
type GamePluginManifestServerBody struct {
Type string `json:"type"`
DisplayName string `json:"displayName"`
SupportedOS []string `json:"supportedOs,omitempty"`
CreateFormSchema string `json:"createFormSchema"`
Type string `json:"type"`
DisplayName string `json:"displayName"`
SupportedOS []string `json:"supportedOs,omitempty"`
CreateFormSchema string `json:"createFormSchema"`
CreateFields []PluginCreateFieldBody `json:"createFields,omitempty"`
}
type GamePluginManifestAIBody struct {
@@ -314,6 +325,7 @@ type GamePluginCreateRequest struct {
SupportedOS []string `json:"supportedOs,omitempty"`
ManifestRef string `json:"manifestRef"`
CreateFormSchemaRef string `json:"createFormSchemaRef"`
CreateFields []PluginCreateFieldBody `json:"createFields,omitempty"`
RequiredRunCapabilities []string `json:"requiredRunCapabilities"`
DeclaredPermissions []string `json:"declaredPermissions,omitempty"`
Permissions PluginPermissionsResponse `json:"permissions"`
@@ -339,6 +351,7 @@ type GamePluginResponse struct {
SupportedOS []string `json:"supportedOs,omitempty"`
ManifestRef string `json:"manifestRef"`
CreateFormSchemaRef string `json:"createFormSchemaRef"`
CreateFields []PluginCreateFieldBody `json:"createFields,omitempty"`
RequiredRunCapabilities []string `json:"requiredRunCapabilities"`
DeclaredPermissions []string `json:"declaredPermissions"`
Permissions PluginPermissionsResponse `json:"permissions"`
@@ -656,6 +669,7 @@ type JobCreateRequest struct {
type JobProgressBody struct {
Percent int `json:"percent"`
Phase string `json:"phase,omitempty"`
Message string `json:"message,omitempty"`
}
@@ -929,12 +943,35 @@ func (bridge GamePluginBridgeBody) ToDomain() domain.GamePluginBridge {
return domain.GamePluginBridge{Actions: domain.CopyStringSlice(bridge.Actions)}
}
func pluginCreateFieldsToDomain(fields []PluginCreateFieldBody) []domain.PluginCreateField {
if fields == nil {
return nil
}
out := make([]domain.PluginCreateField, len(fields))
for i, field := range fields {
out[i] = domain.PluginCreateField{Key: field.Key, Label: field.Label, Type: field.Type, Required: field.Required, DefaultValue: field.DefaultValue, Options: domain.CopyStringSlice(field.Options), ConfigKey: field.ConfigKey}
}
return out
}
func pluginCreateFieldsFromDomain(fields []domain.PluginCreateField) []PluginCreateFieldBody {
if fields == nil {
return nil
}
out := make([]PluginCreateFieldBody, len(fields))
for i, field := range fields {
out[i] = PluginCreateFieldBody{Key: field.Key, Label: field.Label, Type: field.Type, Required: field.Required, DefaultValue: field.DefaultValue, Options: domain.CopyStringSlice(field.Options), ConfigKey: field.ConfigKey}
}
return out
}
func (server GamePluginManifestServerBody) ToDomain() domain.GamePluginManifestServer {
return domain.GamePluginManifestServer{
Type: server.Type,
DisplayName: server.DisplayName,
SupportedOS: domain.CopyStringSlice(server.SupportedOS),
CreateFormSchema: server.CreateFormSchema,
CreateFields: pluginCreateFieldsToDomain(server.CreateFields),
}
}
@@ -1001,6 +1038,7 @@ func (request GamePluginCreateRequest) ToDomain() domain.GamePlugin {
SupportedOS: domain.CopyStringSlice(request.SupportedOS),
ManifestRef: request.ManifestRef,
CreateFormSchemaRef: request.CreateFormSchemaRef,
CreateFields: pluginCreateFieldsToDomain(request.CreateFields),
RequiredRunCapabilities: domain.CopyStringSlice(request.RequiredRunCapabilities),
DeclaredPermissions: domain.CopyStringSlice(request.DeclaredPermissions),
Permissions: permissionsToDomain(request.Permissions),
@@ -1247,6 +1285,7 @@ func GamePluginFromDomain(plugin domain.GamePlugin) GamePluginResponse {
SupportedOS: plugin.SupportedOS,
ManifestRef: plugin.ManifestRef,
CreateFormSchemaRef: plugin.CreateFormSchemaRef,
CreateFields: pluginCreateFieldsFromDomain(plugin.CreateFields),
RequiredRunCapabilities: plugin.RequiredRunCapabilities,
DeclaredPermissions: plugin.DeclaredPermissions,
Permissions: permissionsFromDomain(plugin.Permissions),
@@ -1785,6 +1824,7 @@ func capacityToDomain(capacity RunCapacityResponse) domain.RunCapacity {
func progressFromDomain(progress domain.JobProgress) JobProgressBody {
return JobProgressBody{
Percent: progress.Percent,
Phase: progress.Phase,
Message: progress.Message,
}
}
@@ -1792,6 +1832,7 @@ func progressFromDomain(progress domain.JobProgress) JobProgressBody {
func progressToDomain(progress JobProgressBody) domain.JobProgress {
return domain.JobProgress{
Percent: progress.Percent,
Phase: progress.Phase,
Message: progress.Message,
}
}
+59 -9
View File
@@ -1,16 +1,52 @@
package dto
import "browser.local/platform/domain"
import (
"time"
"browser.local/platform/domain"
)
type ServerDeploymentRequest struct {
RunEndpointID string `json:"runEndpointId,omitempty"`
Mode domain.ServerDeploymentMode `json:"mode"`
ProfileKey string `json:"profileKey,omitempty"`
RuntimeBindings map[string]string `json:"runtimeBindings,omitempty"`
CreateInputs map[string]string `json:"createInputs,omitempty"`
ServerRoot string `json:"serverRoot,omitempty"`
WorkingDirectory string `json:"workingDirectory,omitempty"`
InstallCommand string `json:"installCommand,omitempty"`
StartCommand string `json:"startCommand,omitempty"`
StopCommand string `json:"stopCommand,omitempty"`
StatusCommand string `json:"statusCommand,omitempty"`
Shell domain.ServerCommandShell `json:"shell,omitempty"`
}
type ServerDeploymentResponse struct {
ServerInstanceID string `json:"serverInstanceId"`
Mode domain.ServerDeploymentMode `json:"mode,omitempty"`
ProfileKey string `json:"profileKey,omitempty"`
CreateInputs map[string]string `json:"createInputs,omitempty"`
ServerRootConfigured bool `json:"serverRootConfigured"`
WorkingDirectoryConfigured bool `json:"workingDirectoryConfigured"`
InstallCommandConfigured bool `json:"installCommandConfigured"`
StartCommandConfigured bool `json:"startCommandConfigured"`
StopCommandConfigured bool `json:"stopCommandConfigured"`
StatusCommandConfigured bool `json:"statusCommandConfigured"`
Shell domain.ServerCommandShell `json:"shell,omitempty"`
Revision int `json:"revision"`
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
}
type ServerLifecycleCreateRequest struct {
ID string `json:"id"`
PluginID string `json:"pluginId"`
RunEndpointID string `json:"runEndpointId"`
Name string `json:"name"`
OwnerUserID string `json:"ownerUserId,omitempty"`
IdempotencyKey string `json:"idempotencyKey"`
ProfileKey string `json:"profileKey"`
Bindings map[string]string `json:"bindings,omitempty"`
ID string `json:"id"`
PluginID string `json:"pluginId"`
RunEndpointID string `json:"runEndpointId"`
Name string `json:"name"`
OwnerUserID string `json:"ownerUserId,omitempty"`
IdempotencyKey string `json:"idempotencyKey"`
ProfileKey string `json:"profileKey"`
Bindings map[string]string `json:"bindings,omitempty"`
Deployment ServerDeploymentRequest `json:"deployment,omitempty"`
}
type ServerLifecycleCommandRequest struct {
@@ -35,9 +71,23 @@ func (request ServerLifecycleCreateRequest) ToDomain() domain.ServerLifecycleCre
IdempotencyKey: request.IdempotencyKey,
ProfileKey: request.ProfileKey,
Bindings: domain.CopyStringMap(request.Bindings),
Deployment: request.Deployment.deploymentDefinition(),
}
}
func (request ServerDeploymentRequest) ToDomain() domain.ServerDeploymentUpdate {
return domain.ServerDeploymentUpdate{RunEndpointID: request.RunEndpointID, Mode: request.Mode, ProfileKey: request.ProfileKey, RuntimeBindings: domain.CopyStringMap(request.RuntimeBindings), CreateInputs: domain.CopyStringMap(request.CreateInputs), ServerRoot: request.ServerRoot, WorkingDirectory: request.WorkingDirectory, InstallCommand: request.InstallCommand, StartCommand: request.StartCommand, StopCommand: request.StopCommand, StatusCommand: request.StatusCommand, Shell: request.Shell}
}
func (request ServerDeploymentRequest) deploymentDefinition() domain.ServerDeploymentDefinition {
update := request.ToDomain()
return domain.ServerDeploymentDefinition{Mode: update.Mode, ProfileKey: update.ProfileKey, RuntimeBindings: update.RuntimeBindings, CreateInputs: update.CreateInputs, ServerRoot: update.ServerRoot, WorkingDirectory: update.WorkingDirectory, InstallCommand: update.InstallCommand, StartCommand: update.StartCommand, StopCommand: update.StopCommand, StatusCommand: update.StatusCommand, Shell: update.Shell}
}
func ServerDeploymentFromDomain(view domain.ServerDeploymentView) ServerDeploymentResponse {
return ServerDeploymentResponse{ServerInstanceID: view.ServerInstanceID, Mode: view.Mode, ProfileKey: view.ProfileKey, CreateInputs: domain.CopyStringMap(view.CreateInputs), ServerRootConfigured: view.ServerRootConfigured, WorkingDirectoryConfigured: view.WorkingDirectoryConfigured, InstallCommandConfigured: view.InstallCommandConfigured, StartCommandConfigured: view.StartCommandConfigured, StopCommandConfigured: view.StopCommandConfigured, StatusCommandConfigured: view.StatusCommandConfigured, Shell: view.Shell, Revision: view.Revision, UpdatedAt: optionalTime(view.UpdatedAt)}
}
func (request ServerLifecycleCommandRequest) ToDomain(serverInstanceID string) domain.ServerLifecycleCommand {
return domain.ServerLifecycleCommand{
ServerInstanceID: serverInstanceID,