manager

package
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 12, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// OutboxEventTypeCreateRequest is the outbox event type for container creation requests.
	OutboxEventTypeCreateRequest = "ContainerCreateRequest"
	// OutboxEventTypeStopRequest is the outbox event type for container stop requests.
	OutboxEventTypeStopRequest = "ContainerStopRequest"
	// OutboxEventTypeDeleteRequest is the outbox event type for container delete requests.
	OutboxEventTypeDeleteRequest = "ContainerDeleteRequest"
	// OutboxEventTypeStartRequest is the outbox event type for container start requests.
	OutboxEventTypeRecreateRequest = "AppSessionContainerRecreateRequest"

	OutboxEventTypeStartRequest = "ContainerStartRequest"
)
View Source
const ContainerQueueRealtimeCategory = "container-queue"

ContainerQueueRealtimeCategory 是「容器队列」实时通知在前端的组件类目。

前端 ContainerQueueMonitor 用 useComponentStore 注册 category=container-queue 的 handler(method=containerChanged),后端每次推送都会触发它重新拉取 /container/queue/status。

View Source
const OutboxEventTypeAISummaryGenerateRequest = "AISummaryGenerateRequest"

OutboxEventTypeAISummaryGenerateRequest 是 AI 摘要生成请求的 outbox 事件类型。

Variables

View Source
var (
	// ErrTerminalSessionNotFound 表示没有可用的会话,且调用方不允许自动创建。
	ErrTerminalSessionNotFound = errors.New("terminal session not found")
	// ErrTerminalSessionClosed 表示会话已经结束(shell 退出或容器被删除)。
	ErrTerminalSessionClosed = errors.New("terminal session is closed")
	// ErrTerminalBusy 表示命令队列已满。
	ErrTerminalBusy = errors.New("terminal session is busy")
	// ErrTerminalSessionQuotaExceeded 表示当前用户的终端会话数已达上限。
	ErrTerminalSessionQuotaExceeded = errors.New("terminal session quota exceeded")
)

Functions

func ResolveProjectID added in v0.2.0

func ResolveProjectID(ctx context.Context, projectRepo interfaces.ProjectRepository, projectID int64) int64

ResolveProjectID 校验项目数值主键(t_project.id)存在并返回它。

磁盘上的项目目录统一按项目主键组织(见 utils.GetProjectDir、utils.GetAISummaryFile 等), 而 Analysis / AnalysisNode / AISummary 记录里保存的也是这个数值主键,因此读写项目下的 文件前只需确认该项目存在即可。项目不存在时返回 0。

func RunOutboxDispatcher

func RunOutboxDispatcher(dispatcher *OutboxDispatcher)

Types

type AISummaryContent added in v0.1.2

type AISummaryContent struct {
	// Title 是摘要标题的候选值。
	Title string
	// SystemPromptVars 是渲染摘要 AgentProfile 系统提示词模板(pongo2)所需的变量。
	//
	// 与 RuntimeContextResolver 一致:这里只提供业务上下文事实(输出目录、输出文件等),
	// 真正的系统提示词由 AgentService 用 Profile 模板 + 这些变量渲染。
	SystemPromptVars map[string]any

	// WorkingDir 是 Agent 执行任务时的工作目录。
	WorkingDir string

	// ProjectID 是摘要所属对象(Analysis / AnalysisNode)归属的项目 ID,
	// 供 AISummaryWorker 回填到摘要记录。
	ProjectID int64
}

AISummaryContent 是生成摘要所需的原始内容。

type AISummaryContentProvider added in v0.1.2

type AISummaryContentProvider interface {
	Resolve(ctx context.Context, ownerType types.SummaryOwnerType, ownerID int64) (AISummaryContent, error)
}

AISummaryContentProvider 根据摘要所属对象解析用于生成摘要的原始内容。 当前基于 Analysis / AnalysisNode 的字段组装文本;后续可扩展为读取 实际 output 文件内容。

func NewAISummaryContentProvider added in v0.1.2

func NewAISummaryContentProvider(analysisRepo interfaces.AnalysisRepository,
	workflowRepo interfaces.WorkflowRepository,
	cfg *config.Config) AISummaryContentProvider

NewAISummaryContentProvider 创建 AISummaryContentProvider。 系统提示词优先读取配置 cfg.AISummary.SystemPrompt,未配置时回退到默认值。

type AISummaryEventHandler added in v0.1.2

type AISummaryEventHandler struct {
	// contains filtered or unexported fields
}

AISummaryEventHandler 订阅 AISummaryStatusEvent,并将摘要状态变更推送给 所属项目用户,前端据此刷新 AISummaryPanel。

func NewAISummaryEventHandler added in v0.1.2

func NewAISummaryEventHandler(db *gorm.DB, analysisRepo interfaces.AnalysisRepository, projectRepo interfaces.ProjectRepository, hub *realtime.Hub) *AISummaryEventHandler

func (*AISummaryEventHandler) Handle added in v0.1.2

func (h *AISummaryEventHandler) Handle(evt event.Event)

type AISummaryGenerateRequestEvent added in v0.1.2

type AISummaryGenerateRequestEvent struct {
	OutboxID   int64
	RawPayload []byte
}

AISummaryGenerateRequestEvent is published to the event bus when an AISummaryGenerateRequest outbox event is picked up.

type AISummaryWorker added in v0.1.2

type AISummaryWorker struct {
	// contains filtered or unexported fields
}

AISummaryWorker 订阅 AISummaryGenerateRequestEvent,异步执行 AI 摘要生成。

func NewAISummaryWorker added in v0.1.2

func NewAISummaryWorker(
	summaryRepo interfaces.AISummaryRepository,
	containerRepo interfaces.ContainerRepository,
	projectRepo interfaces.ProjectRepository,
	bus event.Bus,
	agentService *agentservice.AgentService,
	content AISummaryContentProvider,
	cfg *config.Config,
) *AISummaryWorker

NewAISummaryWorker 创建 AISummaryWorker。

func (*AISummaryWorker) Handle added in v0.1.2

func (w *AISummaryWorker) Handle(evt event.Event)

Handle 分发事件到对应的处理逻辑。

type AgentProjectContextProvider added in v0.1.2

type AgentProjectContextProvider struct {
	// contains filtered or unexported fields
}

AgentProjectContextProvider 实现 ProjectContextProvider: 查询当前用户激活项目下已完成(status=done)的分析节点,以及项目关联的参考文献, 并格式化为上下文的文本。

采用实时查询而非写入 memory repo 的设计:analysis_nodes / project_literature 是领域状态的唯一数据源,状态在运行期间频繁变化,实时查询可保证内容始终最新。

func NewAgentProjectContextProvider added in v0.1.2

func NewAgentProjectContextProvider(
	projects interfaces.ProjectRepository,
	analyses interfaces.AnalysisRepository,
	cfg *config.Config,
) *AgentProjectContextProvider

NewAgentProjectContextProvider 创建项目上下文提供者。

func (*AgentProjectContextProvider) ProjectContext added in v0.1.2

func (p *AgentProjectContextProvider) ProjectContext(ctx context.Context, userID int64) (string, error)

ProjectContext 实现 ProjectContextProvider。

type AppSessionEventHandler

type AppSessionEventHandler struct {
	// contains filtered or unexported fields
}

AppSessionEventHandler 是「应用会话」对前端的唯一推送出口。

它订阅两类事件:

  1. types.ContainerEvent(容器生命周期,来自 outbox dispatcher): 把容器状态同步到所属 AppSession 的 Status / StartedAt / StoppedAt。 只处理 OwnerType == ContainerOwnerAppSession 的容器,DAG 节点 / 服务忽略。

  2. types.AppSessionEvent(会话运行态,来自 manager.TerminalSessionRegistry): 终端会话(= AppSession)的创建 / 删除 / busy / 订阅者变化,以及 Agent 在终端里 执行命令,都由会话层发布到这里,再统一推给前端。

之所以只保留这一处推送:会话层不再直接持有 realtime.Hub,避免同一次状态变化 被「容器事件」和「会话事件」各推一遍(前端会连续 refetch 两次)。

func (*AppSessionEventHandler) Handle

func (h *AppSessionEventHandler) Handle(evt event.Event)

type ContainerCreateOptions added in v0.2.0

type ContainerCreateOptions struct {
	TemplateID int64
	OwnerType  types.ContainerOwnerType
	OwnerID    int64
	Name       string

	// Kind 是容器运行形态(terminal / web / dag_node)。
	// 为空时按 OwnerType 推断(见 types.ContainerInstance.NormalizedKind)。
	Kind types.ContainerInstanceKind

	// Sync 为 true 时同步创建并等待容器 running:
	//   - 不写 outbox,直接由 worker 调用 runtime.Create + runtime.Start;
	//   - 创建过程中的状态迁移不计入创建并发额度(长期占用 running 的实例);
	//   - 返回前等待 ContainerManager.OnEvent 广播的 ContainerStarted(running)。
	//
	// Sync 为 false(默认)时保持旧行为:写 outbox,由 OutboxDispatcher 异步创建。
	Sync bool
	// WaitTimeout 是 Sync=true 时等待容器 running 的上限;<=0 使用默认 2 分钟。
	WaitTimeout time.Duration
}
	return nil
}

ContainerCreateOptions 是 CreateByTemplateWithOptions 的参数。

与仅按模板 + owner 创建相比,它额外支持:

  • 显式指定容器运行形态(Kind):决定 executeCreateInstance 如何组装运行时 spec; 未指定时按 OwnerType 推断(见 types.ContainerInstance.NormalizedKind), 并随实例一起落库;
  • 同步创建:不写 outbox、由 ContainerCreateWorker 直接调用 runtime.Create + runtime.Start,并在返回前等待容器进入 running(终端会话需要立刻 exec shell)。

启动命令、workload 类型、运行用户等只由 Kind 决定(见 executeCreateInstance), 这里不再接受 Command / Entrypoint 覆盖。

type ContainerCreateWorker

type ContainerCreateWorker struct {
	// contains filtered or unexported fields
}

ContainerCreateWorker subscribes to OutboxCreateRequestEvent and ContainerEvent from the event bus. For creation requests it executes rt.Create + rt.Start, and updates the active create request count while the request is being handled.

func NewContainerCreateWorker

NewContainerCreateWorker creates a new worker.

func (*ContainerCreateWorker) AttachTerminalRuntime added in v0.2.0

AttachTerminalRuntime 在已有容器上执行交互式 shell(等价于 kubectl/docker exec -it)。

这是进程重启后「认领」原容器的唯一方式:容器还在,但原来的 shell 已经随连接 结束,所以这里得到的是一个新的 bash(cwd / 环境变量不会保留,历史输出由滚动缓冲回放)。

instance 是 ContainerInstance 记录:RuntimeName / RuntimeID 由它提供, Cleanup 也会按 owner 关系把实例与容器一并回收。

func (*ContainerCreateWorker) ContainerTemplateName added in v0.2.0

func (w *ContainerCreateWorker) ContainerTemplateName(ctx context.Context, templateID int64) (string, string)

ContainerTemplateName 返回模板的展示名与名称,供终端会话生成默认展示名。

模板不可读 / 未配置时返回空串,调用方会回退到模板 ID。

func (*ContainerCreateWorker) DropTerminalRuntime added in v0.2.0

func (w *ContainerCreateWorker) DropTerminalRuntime(ctx context.Context, runtimeName, runtimeID string)

DropTerminalRuntime 删除一个(可能来自旧进程的)终端容器,失败只记日志。

func (*ContainerCreateWorker) Handle

func (w *ContainerCreateWorker) Handle(evt event.Event)

Handle dispatches events from the event bus. It handles four event types:

  • OutboxCreateRequestEvent: executes deferred container creation
  • OutboxStopRequestEvent: executes deferred container stop
  • OutboxDeleteRequestEvent: executes deferred container delete
  • OutboxStartRequestEvent: executes deferred container start

func (*ContainerCreateWorker) StartTerminalRuntime added in v0.2.0

func (w *ContainerCreateWorker) StartTerminalRuntime(ctx context.Context, userID, projectID, templateID, sessionID int64, opts containerruntime.TerminalOptions) (*TerminalRuntimeHandle, error)

StartTerminalRuntime 创建终端容器并打开交互式 shell。

容器由 ContainerManager.CreateByTemplateWithOptions(Sync=true, Kind=terminal) 同步 创建并启动(复用 ContainerCreateWorker.executeCreateInstance,模板 / 项目 env、挂载、 变量解析、storage 挂载与普通容器完全一致)。启动命令 / workload / 运行用户等 终端容器特有的差异全部由 buildInstanceSpec 按 Kind=terminal 处理。

sessionID 是终端会话(AppSession)主键:容器以 owner_type=app_session + owner_id=sessionID 归属该会话,进程重启后可按 owner 认领原容器。

type ContainerLifecycle added in v0.2.0

type ContainerLifecycle struct {
	// contains filtered or unexported fields
}

ContainerLifecycle 收敛 ContainerManager 与 ContainerCreateWorker 共同依赖的 无状态基础设施,避免两者互相持有指针。

它只负责「实例状态迁移 + 运行时解析 + 运行 spec 组装」这三类地基层能力:

  • 状态迁移:transition/TransitionAndEnqueue(FSM 校验 + 落库 + outbox);
  • 运行时解析:GetRuntime / GetRuntimeByInstance;
  • spec 组装:ApplyRuntimeUser / ApplyDagNodeRuntimeSpec。

依赖方向被固定为单向:ContainerManager → ContainerCreateWorker → ContainerLifecycle, ContainerLifecycle 不依赖任何一方。ContainerManager 仍保留同名导出方法作为薄委托, 对外 API 保持不变。

func NewContainerLifecycle added in v0.2.0

func NewContainerLifecycle(
	repo interfaces.ContainerRepository,
	reg *containerruntime.Registry,
	cfg *config.Config,
) *ContainerLifecycle

NewContainerLifecycle 构造共享生命周期基础设施。

func (*ContainerLifecycle) ApplyDagNodeRuntimeSpec added in v0.2.0

func (l *ContainerLifecycle) ApplyDagNodeRuntimeSpec(spec *types.ContainerSpec, resolveVars map[string]string)

ApplyDagNodeRuntimeSpec 按 DAG 节点的约定覆盖容器启动命令(bash ./run.sh)与运行用户。

func (*ContainerLifecycle) ApplyRuntimeUser added in v0.2.0

func (l *ContainerLifecycle) ApplyRuntimeUser(spec *types.ContainerSpec, resolveVars map[string]string)

ApplyRuntimeUser maps USERID/GROUPID to the runtime's user field. Docker uses uid:gid, while Kubernetes currently maps ContainerSpec.User to runAsUser.

以非 root 用户运行时,镜像里的 HOME(常见是 /root)对该用户不可写, 直接跑会失败(R / python / pip 都要写家目录)。因此这里等价于:

docker run --user "$UID:$GID" \
  -e HOME=/home/app \
  --tmpfs /home/app:rw,uid=$UID,gid=$GID,mode=700

即:User=uid[:gid]、HomeDir=/home/app、Tmpfs 挂一个属主为该用户的 700 内存盘。 如果调用方 / 模板已经显式设置了 HomeDir 或为同一路径配置了 tmpfs,则不再覆盖。

func (*ContainerLifecycle) GetRuntime added in v0.2.0

func (l *ContainerLifecycle) GetRuntime() (containerruntime.Runtime, error)

GetRuntime 按当前配置解析默认运行时。

func (*ContainerLifecycle) GetRuntimeByInstance added in v0.2.0

func (l *ContainerLifecycle) GetRuntimeByInstance(inst *types.ContainerInstance) (containerruntime.Runtime, error)

GetRuntimeByInstance 优先按实例的 RuntimeName 解析运行时,找不到时回退到默认运行时。

func (*ContainerLifecycle) MaxConcurrency added in v0.2.0

func (l *ContainerLifecycle) MaxConcurrency() int

MaxConcurrency 返回创建并发额度(未配置时默认 3)。

func (*ContainerLifecycle) ResolveRuntimeName added in v0.2.0

func (l *ContainerLifecycle) ResolveRuntimeName() string

ResolveRuntimeName 解析当前生效的运行时名称。

func (*ContainerLifecycle) Transition added in v0.2.0

func (l *ContainerLifecycle) Transition(ctx context.Context, inst *types.ContainerInstance, to types.ContainerStatus, eventType string, enforceConcurrency bool, enqueueOutbox bool) error

Transition 是容器实例状态迁移的唯一实现:读取最新状态 → FSM 校验 → 落库 → (可选)写 outbox 事件。

enforceConcurrency 控制是否把本次迁移计入创建并发额度;终端容器这类长期占用 running 的实例不参与该额度(false)。enqueueOutbox 控制是否写 outbox 事件; 由调用方同步驱动的内部迁移不需要 outbox(false)。

func (*ContainerLifecycle) TransitionAndEnqueue added in v0.2.0

func (l *ContainerLifecycle) TransitionAndEnqueue(ctx context.Context, inst *types.ContainerInstance, to types.ContainerStatus, eventType string) error

TransitionAndEnqueue 以「计入并发额度 + 写 outbox」的默认语义迁移实例状态。

type ContainerManager

type ContainerManager struct {
	// contains filtered or unexported fields
}

func (*ContainerManager) CreateByTemplateWithOptions added in v0.2.0

func (m *ContainerManager) CreateByTemplateWithOptions(ctx context.Context, opts ContainerCreateOptions) (*types.ContainerInstance, error)

CreateByTemplateWithOptions 按模板创建容器实例(创建容器的唯一入口)。

默认走 outbox 异步链路,Sync=true 时改为同步创建并等待 running (见 ContainerCreateOptions)。

func (*ContainerManager) CreateQueueMaxPending

func (m *ContainerManager) CreateQueueMaxPending() int

func (*ContainerManager) Delete

func (m *ContainerManager) Delete(ctx context.Context, id int64) error

func (*ContainerManager) Describe added in v0.1.4

Describe 按 ContainerInstance ID 从运行时获取详情(docker inspect / kubectl describe)。

func (*ContainerManager) GetLogs

func (m *ContainerManager) GetLogs(ctx context.Context, id int64, tail int) (string, error)

func (*ContainerManager) GetMaxConcurrency

func (s *ContainerManager) GetMaxConcurrency() int

func (*ContainerManager) GetRuntime added in v0.2.2

func (m *ContainerManager) GetRuntime() (containerruntime.Runtime, error)

GetRuntime 按当前配置解析默认运行时,语义与容器实际创建时完全一致 (同为 ContainerLifecycle.GetRuntime,解析顺序见 ResolveContainerRuntime)。 供配置检测接口复用,保证「检测结果」与「真实执行」不会出现口径差异。

func (*ContainerManager) Lifecycle added in v0.2.0

func (s *ContainerManager) Lifecycle() *ContainerLifecycle

Lifecycle 返回 Manager 持有的共享生命周期基础设施,供 ContainerCreateWorker 注入使用。

func (*ContainerManager) OnEvent

如果容器运行太快,ContainerStarted与 ContainerExited可能会竞争

func (*ContainerManager) OpenTerminal added in v0.2.0

OpenTerminal 为运行中的容器实例打开一条交互式终端(kubectl exec -it / docker exec -it)。

只有容器实例处于 running 状态时才允许连接:命令结束、容器退出后终端也随之不可用。

func (*ContainerManager) QueueStatus

func (m *ContainerManager) QueueStatus(ctx context.Context) (*CreateQueueStatus, error)

func (*ContainerManager) RecoverRuntimeMonitoring

func (m *ContainerManager) RecoverRuntimeMonitoring(ctx context.Context) (int, error)

func (*ContainerManager) ResolveRuntimeName added in v0.2.2

func (m *ContainerManager) ResolveRuntimeName() string

ResolveRuntimeName 解析当前生效的运行时名称,语义与容器实际执行时一致 (ContainerLifecycle.ResolveRuntimeName)。

func (*ContainerManager) RunRuntimeReconciler

func (m *ContainerManager) RunRuntimeReconciler(ctx context.Context, interval time.Duration)

RunRuntimeReconciler periodically reconnects runtime monitoring.

func (*ContainerManager) SetCreateWorker added in v0.2.0

func (s *ContainerManager) SetCreateWorker(worker *ContainerCreateWorker)

SetCreateWorker 注入同步创建容器所需的 worker(容器装配阶段调用一次)。

之所以不在构造函数里注入:ContainerCreateWorker 自身依赖 ContainerManager, 直接双向构造会形成循环依赖;装配阶段回填一个指针即可。

同时把 Manager 自己的 lifecycle 共享给 worker(worker 构造期可能未拿到), 并回填 worker.owner,供 StartTerminalRuntime 复用 CreateByTemplateWithOptions。

func (*ContainerManager) SetHub added in v0.2.4

func (s *ContainerManager) SetHub(hub *realtime.Hub)

SetHub 回填实时推送出口(由容器装配阶段调用一次)。

不走构造函数的原因见 hub 字段的注释:这是装配顺序问题,不是包级循环依赖。

func (*ContainerManager) Start

func (m *ContainerManager) Start(ctx context.Context, id int64) error

func (*ContainerManager) Stop

func (m *ContainerManager) Stop(ctx context.Context, id int64) error

func (*ContainerManager) StopByOwner

func (m *ContainerManager) StopByOwner(ctx context.Context, ownerType types.ContainerOwnerType, ownerID int64) error

func (*ContainerManager) TransitionContainerAndEnqueueOutbox

func (s *ContainerManager) TransitionContainerAndEnqueueOutbox(ctx context.Context, inst *types.ContainerInstance, to types.ContainerStatus, eventType string) error

func (*ContainerManager) WaitForInstanceStatus added in v0.2.0

func (s *ContainerManager) WaitForInstanceStatus(ctx context.Context, instanceID int64, wanted ...types.ContainerStatus) (types.ContainerStatus, error)

WaitForInstanceStatus 阻塞等待实例进入 wanted 中的任一状态。

状态推进完全由运行时事件驱动(ContainerManager.OnEvent),因此等待方只需要 订阅状态广播:先注册订阅者,再读一次数据库,避免“注册前事件已到”的竞态。 实例进入 failed / stopped / exited 且不在 wanted 中时返回错误。

type ContainerRuntimeResolveInput

type ContainerRuntimeResolveInput struct {
	Spec      *types.ContainerSpec
	Variables map[string]string
}

type ContainerRuntimeResolver

type ContainerRuntimeResolver interface {
	Resolve(ctx context.Context, in *ContainerRuntimeResolveInput) (*types.ContainerSpec, error)
}

func NewDefaultContainerRuntimeResolver

func NewDefaultContainerRuntimeResolver() ContainerRuntimeResolver

type CreateQueueStatus

type CreateQueueStatus struct {
	ActiveCount    int64
	PendingCount   int64
	MaxConcurrency int
	MaxPending     int
}

type GormTerminalSessionStore added in v0.2.0

type GormTerminalSessionStore struct {
	// contains filtered or unexported fields
}

GormTerminalSessionStore 是 TerminalSessionStore 的默认实现(底层是 go_container_app_session)。

func NewGormTerminalSessionStore added in v0.2.0

func NewGormTerminalSessionStore(db *gorm.DB) *GormTerminalSessionStore

NewGormTerminalSessionStore 构造基于 GORM 的会话记录存储。

func (*GormTerminalSessionStore) Create added in v0.2.0

Create 新增一条会话记录,并回填 rec.ID。

只在新会话创建时调用:name 在这里写入一次,之后 Update 不会修改它。

func (*GormTerminalSessionStore) Delete added in v0.2.0

func (*GormTerminalSessionStore) DeleteByID added in v0.2.0

func (s *GormTerminalSessionStore) DeleteByID(ctx context.Context, id int64) error

func (*GormTerminalSessionStore) FindAgentSession added in v0.2.0

func (s *GormTerminalSessionStore) FindAgentSession(ctx context.Context, userID, projectID, templateID, agentSessionID int64) (*types.AppSession, error)

func (*GormTerminalSessionStore) Get added in v0.2.0

func (*GormTerminalSessionStore) GetByID added in v0.2.0

func (*GormTerminalSessionStore) List added in v0.2.0

func (*GormTerminalSessionStore) ListByUser added in v0.2.0

func (s *GormTerminalSessionStore) ListByUser(ctx context.Context, userID int64) ([]*types.AppSession, error)

func (*GormTerminalSessionStore) MarkPersistent added in v0.2.0

func (s *GormTerminalSessionStore) MarkPersistent(ctx context.Context, key TerminalSessionKey) error

MarkPersistent 把会话标记为持久(只会 false → true)。

记录不存在时是空操作:真正的持久化由随后的 Upsert 写回。

func (*GormTerminalSessionStore) Touch added in v0.2.0

func (*GormTerminalSessionStore) Update added in v0.2.0

Update 按主键更新已存在记录的运行时字段。

刻意不包含 name:name 只在 Create 时写入,DB 是它的唯一真相;否则一旦改名 接口改写了 DB,后续任何一次运行态更新都会把旧名字写回去。

type ManagedTerminalSession added in v0.2.0

type ManagedTerminalSession struct {
	// contains filtered or unexported fields
}

ManagedTerminalSession 是注册表持有一个 PTY(容器 + bash -l)。

func (*ManagedTerminalSession) Attach added in v0.2.0

func (s *ManagedTerminalSession) Attach(sinceSeq int64) (*TerminalSubscriber, []byte)

Attach 注册一个订阅者并返回重放数据。

前端(ContainerTemplateTerminal)接入时调用者还应调用 MarkPersistent, 把会话升级为持久会话。需要知道回放序号区间 / 是否需要清屏时用 AttachWithInfo。

sinceSeq <= 0 表示「尽可能早」(整段缓冲);否则从该序号开始回放。 注意 sinceSeq 是会话输出流的全局序号(见 TerminalReplayInfo),不是「本地收到的 字节数」;超过当前序号时会被当作失效序号整段重放(Reset)。 重放与订阅在同一临界区内完成,不会丢帧。

func (*ManagedTerminalSession) AttachObserver added in v0.2.0

func (s *ManagedTerminalSession) AttachObserver() func()

AttachObserver 登记一个「只占位、不接收输出」的订阅者,返回幂等的 Detach 函数。

供 terminal_exec 这类「我只需要保证执行期间不被回收」的调用使用:

  • 它与 WS 订阅者共用 subs 计数,因此有前端终端在线时 Detach 不会触发回收;
  • 它的 Data 是无缓冲 channel 且无人读取,publish 会走 default 分支丢弃, 不会像普通订阅者那样占用 2048 块的缓冲内存。

func (*ManagedTerminalSession) AttachWithInfo added in v0.2.0

func (s *ManagedTerminalSession) AttachWithInfo(sinceSeq int64) (*TerminalSubscriber, TerminalReplayInfo)

AttachWithInfo 与 Attach 相同,但额外返回本次回放的序号区间与续传状态。

为什么需要:调用方(前端)把「已消费到哪个序号」传回来才能增量回放,而序号是 环形缓冲里的全局偏移(bufStart 可能在缓冲滚动后不为 0)。如果客户端自己按 「收到多少字节」计数,一旦缓冲滚动、或会话被重建 / 认领(序号基准归零), 续传位置就会错位:轻则重复/跳过一段,重则 since 超出当前序号 → 空回放、历史全丢。

因此这里把边界情况显式告知调用方:

  • sinceSeq > To:客户端位置超出本会话(会话重建 / 认领后序号基准改变), 回退为整段重放并置 Reset=true,客户端应先清屏;
  • sinceSeq < bufStart:中间那段已被缓冲覆盖,置 Truncated=true;
  • From/To 是本次回放覆盖的序号区间,客户端下次应从这里继续。

func (*ManagedTerminalSession) Close added in v0.2.0

func (s *ManagedTerminalSession) Close()

Close 关闭 shell 并删除容器;可重复调用。

func (*ManagedTerminalSession) Detach added in v0.2.0

Detach 注销订阅者;最后一个订阅者离开后按会话类型决定是否立即回收。

func (*ManagedTerminalSession) ID added in v0.2.0

ID 返回会话 ID(终端会话主键的字符串形式)。

func (*ManagedTerminalSession) Key added in v0.2.0

Key 返回会话 key。

func (*ManagedTerminalSession) Resize added in v0.2.0

func (s *ManagedTerminalSession) Resize(rows, cols uint16) error

Resize 调整 PTY 尺寸(前端 xterm 是尺寸的唯一来源)。

func (*ManagedTerminalSession) SendEvent added in v0.2.0

func (s *ManagedTerminalSession) SendEvent(payload map[string]any)

SendEvent 向所有订阅者广播一条 JSON 控制事件。

func (*ManagedTerminalSession) Size added in v0.2.0

func (s *ManagedTerminalSession) Size() (rows, cols uint16)

Size 返回 PTY 当前尺寸(前端据此渲染回放,保证宽度一致)。

func (*ManagedTerminalSession) WriteInput added in v0.2.0

func (s *ManagedTerminalSession) WriteInput(data []byte) (int, error)

WriteInput 写入用户按键(终端原始输入)。

type OutboxCreateRequestEvent

type OutboxCreateRequestEvent struct {
	OutboxID   int64
	RawPayload []byte
}

OutboxCreateRequestEvent is published to the event bus when a ContainerCreateRequest outbox event is picked up. Handlers that need to process deferred container creation subscribe to this.

type OutboxDeleteRequestEvent

type OutboxDeleteRequestEvent struct {
	OutboxID   int64
	RawPayload []byte
}

OutboxDeleteRequestEvent is published to the event bus when a ContainerDeleteRequest outbox event is picked up.

type OutboxDispatcher

type OutboxDispatcher struct {
	// contains filtered or unexported fields
}

func NewOutboxDispatcher

func NewOutboxDispatcher(repo interfaces.ContainerRepository, bus event.Bus) *OutboxDispatcher

func (*OutboxDispatcher) Start

func (d *OutboxDispatcher) Start(ctx context.Context)

type OutboxRecreateRequestEvent

type OutboxRecreateRequestEvent struct {
	OutboxID   int64
	RawPayload []byte
}

type OutboxStartRequestEvent

type OutboxStartRequestEvent struct {
	OutboxID   int64
	RawPayload []byte
}

OutboxStartRequestEvent is published to the event bus when a ContainerStartRequest outbox event is picked up.

type OutboxStopRequestEvent

type OutboxStopRequestEvent struct {
	OutboxID   int64
	RawPayload []byte
}

OutboxStopRequestEvent is published to the event bus when a ContainerStopRequest outbox event is picked up.

type ProjectContextProvider added in v0.2.0

type ProjectContextProvider interface {
	// ProjectContext 返回当前用户激活项目下的上下文文本块;无可用内容时返回空串。
	ProjectContext(ctx context.Context, userID int64) (string, error)
}

ProjectContextProvider 是领域上下文提供者接口的窄定义。

它描述「按用户解析当前项目上下文文本块」的能力,具体实现见 AgentProjectContextProvider。当前 Agent 系统提示词的注入调用已被移除,本接口 仅作为保留能力定义,供后续按需接入。

type RuntimeVariableSet added in v0.1.4

type RuntimeVariableSet struct {
	// contains filtered or unexported fields
}

RuntimeVariableSet 是一组已求值的运行时变量,可派生扁平 map 或分类列表。

func (*RuntimeVariableSet) ByCategory added in v0.1.4

ByCategory 返回指定分类的变量,供前端分组展示。

func (*RuntimeVariableSet) List added in v0.1.4

List 返回全部变量(含元数据),供 API 返回。

func (*RuntimeVariableSet) ToMap added in v0.1.4

func (s *RuntimeVariableSet) ToMap() map[string]string

ToMap 派生扁平 map,供 ContainerRuntimeResolver 替换占位符,行为与原 setRuntimeVar 一致(跳过空值)。

type TerminalCommand added in v0.2.0

type TerminalCommand struct {
	// Command 是要执行的 shell 命令,可多行。
	Command string
	// Wait 为 true 时等待命令结束后返回退出码与输出;false 时只负责投递。
	Wait bool
	// Timeout <= 0 时使用默认超时。
	Timeout time.Duration
	// Source 标记来源(ui / agent),用于前端展示与审计。
	Source string
	// NotifyUI 为 true 时通过 realtime 推送 terminal.exec 事件。
	NotifyUI bool
	// CreateIfMissing 为 true 时允许自动创建会话。
	CreateIfMissing bool
	// Persistent 为 true 时,本命令「新建」的会话直接按持久会话创建。
	//
	// 原因:一次性会话在命令结束且没有订阅者时会被立即回收(容器也会删除),
	// 因此「先投递命令、再由前端打开终端看输出」的场景必须建持久会话,
	// 否则命令执行完容器就没了,前端随后接入拿到的是另一台新容器(看不到输出)。
	Persistent bool
}

TerminalCommand 是一次写入终端的命令。

type TerminalCommandResult added in v0.2.0

type TerminalCommandResult struct {
	SessionID       string
	Accepted        bool
	Running         bool
	ExitCode        int
	TimedOut        bool
	DurationSeconds float64
	Output          string
	OutputTruncated bool
}

TerminalCommandResult 是一次命令投递 / 执行的结果。

type TerminalInstanceStore added in v0.2.0

type TerminalInstanceStore interface {
	GetContainerInstanceByOwner(ctx context.Context, ownerType types.ContainerOwnerType, ownerID int64) (*types.ContainerInstance, error)
	DeleteContainerInstance(ctx context.Context, id int64) error
}

TerminalInstanceStore 定位「终端会话对应的 ContainerInstance」。

容器实例是会话容器的唯一真相:认领(进程重启后在原容器上重新 exec shell)与 删除(关闭会话时回收容器)都按 (owner_type=app_session, owner_id=会话 ID) 查询。

type TerminalRegistryOptions added in v0.2.0

type TerminalRegistryOptions struct {
	// SessionTTL 是持久会话的空闲上限:超过即回收容器并删除记录。<=0 使用默认 2 小时。
	SessionTTL time.Duration
	// MaxSessionsPerUser 限制单个用户同时存在的终端会话数;<=0 使用默认 4。
	MaxSessionsPerUser int
	// ScrollbackDir / ScrollbackBytes 控制滚动缓冲落盘目录与单会话上限。
	ScrollbackDir   string
	ScrollbackBytes int
	ReadyWait       time.Duration
	CreateWait      time.Duration
	BufferBytes     int
	ExecTimeout     time.Duration
	ExecQueueSize   int
}

TerminalRegistryOptions 控制会话生命周期,零值使用默认值。

type TerminalReplayInfo added in v0.2.0

type TerminalReplayInfo struct {
	// Data 是从 From 到 To 的输出字节。客户端下次重连应把 To + 本连接新收到的字节数
	// 作为新的 since 传回来(不要自己从 0 开始数字节,否则缓冲滚动后会错位)。
	Data []byte
	// From / To 是本次回放在会话输出流里的序号区间([From, To))。
	From int64
	To   int64
	// Truncated 表示客户端请求的位置早于环形缓冲起点:中间有一段输出已被滚动覆盖。
	Truncated bool
	// Reset 表示客户端持有的序号超出了本会话(会话被重建 / 认领后序号基准改变),
	// 已回退为「整段重放」,客户端应先清屏再写入 Data,否则会出现重复内容。
	Reset bool
}

TerminalReplayInfo 描述一次回放覆盖的序号区间。

type TerminalRuntimeHandle added in v0.2.0

type TerminalRuntimeHandle struct {
	Runtime             containerruntime.Runtime
	RuntimeName         string
	RuntimeID           string
	ContainerName       string
	ContainerInstanceID int64
	Session             containerruntime.TerminalSession
	Cleanup             func()
}

TerminalRuntimeHandle 是一次「终端容器 + 交互式 shell」的句柄。

它把创建/认领两条路径统一起来:

  • StartTerminalRuntime 同步创建容器(keep-alive 常驻)后打开 shell;
  • AttachTerminalRuntime 在已有容器上重新 exec 一个 shell(进程重启后的认领)。

Cleanup 负责删除容器(关闭 shell 之后调用);调用方必须在会话 Close 时执行它。

type TerminalRuntimeOpener added in v0.2.0

type TerminalRuntimeOpener interface {
	StartTerminalRuntime(ctx context.Context, userID, projectID, templateID, sessionID int64, opts containerruntime.TerminalOptions) (*TerminalRuntimeHandle, error)
	AttachTerminalRuntime(ctx context.Context, instance *types.ContainerInstance, opts containerruntime.TerminalOptions) (*TerminalRuntimeHandle, error)
	DropTerminalRuntime(ctx context.Context, runtimeName, runtimeID string)
	// ContainerTemplateName 返回模板的展示名与名称,供新建会话生成默认展示名。
	// 模板不可读时返回空串,调用方回退到模板 ID。
	ContainerTemplateName(ctx context.Context, templateID int64) (displayName, name string)
}

TerminalRuntimeOpener 抽象「创建终端容器 / 认领已有容器 + 打开交互式 shell」的能力。 *ContainerCreateWorker 实现它;单测可注入 fake PTY。

sessionID 是终端会话主键(= AppSession.ID):容器以 owner_type=app_session、 owner_id=sessionID 归属该会话。instance 是认领时使用的 ContainerInstance 记录, RuntimeName / RuntimeID 由它提供。

type TerminalSessionKey added in v0.2.0

type TerminalSessionKey struct {
	UserID     int64
	ProjectID  int64
	TemplateID int64
	// AgentSessionID 是创建该终端会话的 Agent 会话 ID(agent_sessions.id);
	// 0 表示用户从 UI 手动创建。
	AgentSessionID int64
	// ID 是终端会话主键(= AppSession.ID)。0 表示尚未定位到具体会话(创建请求);
	// 落库前的新会话使用进程内负数占位 ID(见 newTerminalSessionPlaceholderID)。
	ID int64
}

TerminalSessionKey 定位一个终端会话。

会话的对外标识是 AppSession.ID;这里保留 (userID, projectID, templateID, agentSessionID) 是为了:

  • Agent 侧按 (templateID, agentSessionID) 查找 / 复用会话;
  • UI 手动创建时按模板新建会话;
  • 由 key 派生出 SessionKey(滚动缓冲文件名)。

func NewAgentKey added in v0.2.0

func NewAgentKey(userID, projectID, templateID, agentSessionID int64) TerminalSessionKey

NewAgentKey 返回「某个 Agent 会话在某个模板上的终端」的 key。

同一 (templateID, agentSessionID) 只会对应一个终端会话(见 registry 的 resolveRecordKey),因此 Agent 侧不需要关心终端会话 ID。

func NewUIKey added in v0.2.0

func NewUIKey(userID, projectID, templateID int64) TerminalSessionKey

NewUIKey 返回「用户从 UI 在某个模板上新建会话」的 key(尚未分配终端会话 ID)。

func (TerminalSessionKey) ReplaceID added in v0.2.0

ReplaceID 返回把终端会话主键替换为 id 的 key 副本。

func (TerminalSessionKey) SessionID added in v0.2.0

func (k TerminalSessionKey) SessionID() string

SessionID 返回稳定的会话 ID(= SessionKey,仅供日志 / 内部使用)。

func (TerminalSessionKey) SessionKey added in v0.2.0

func (k TerminalSessionKey) SessionKey() string

SessionKey 返回稳定的会话标识。

只作为唯一键与滚动缓冲文件名,对外(接口 / 前端)一律使用 ID。 ID == 0 表示「尚未分配」(创建请求),此时用 "new" 占位。

func (TerminalSessionKey) UIKey added in v0.2.0

UIKey 返回「去掉终端会话 ID」后的 key:用于从 ID 反向定位 (user/template/agent session)。

type TerminalSessionRegistry added in v0.2.0

type TerminalSessionRegistry struct {
	// contains filtered or unexported fields
}

TerminalSessionRegistry 维护终端会话 ID → PTY 的映射。

func NewTerminalSessionRegistry added in v0.2.0

func NewTerminalSessionRegistry(worker *ContainerCreateWorker, bus event.Bus, store TerminalSessionStore, instances TerminalInstanceStore, cfg *config.Config) *TerminalSessionRegistry

NewTerminalSessionRegistry 构造会话注册表。

worker 复用 ContainerCreateWorker 的容器组装与创建链路;bus 可为 nil(例如单测), 此时不推送前端事件;store 记录会话(= AppSession)并供进程重启后 认领;instances 用于按会话定位 / 删除 ContainerInstance;cfg 决定回收策略 / 配额 / 滚动缓冲目录。

func (*TerminalSessionRegistry) Close added in v0.2.3

func (r *TerminalSessionRegistry) Close(ctx context.Context, terminalID int64)

Close 实现 hostshell.ContainerShellService。

func (*TerminalSessionRegistry) CloseSession added in v0.2.0

func (r *TerminalSessionRegistry) CloseSession(key TerminalSessionKey) bool

CloseSession 主动结束会话(删除容器),并删除持久层记录。

只按终端会话主键寻址:key.ID 必须 > 0。

func (*TerminalSessionRegistry) CloseTerminal added in v0.2.3

func (r *TerminalSessionRegistry) CloseTerminal(ctx context.Context, terminalID int64)

CloseTerminal 按终端会话主键关闭会话并删除容器。

与 ClosePersistentShell 对应:Agent 请求结束时调用。

func (*TerminalSessionRegistry) CreateForTemplate added in v0.2.0

func (r *TerminalSessionRegistry) CreateForTemplate(ctx context.Context, userID, projectID, templateID int64, rows, cols uint16) (*ManagedTerminalSession, *types.AppSession, error)

CreateForTemplate 按容器模板新建一条「UI 手动创建」的终端会话并立即启动。

一个模板可以有多条这样的会话(每次点「新建」都新建一条),彼此独立。 持久会话(只能由空闲 TTL 或显式关闭回收);展示名由 persistRecord 按模板生成。

func (*TerminalSessionRegistry) Ensure added in v0.2.3

func (r *TerminalSessionRegistry) Ensure(ctx context.Context, userID, projectID, templateID, agentSessionID int64) (int64, error)

Ensure 实现 hostshell.ContainerShellService。

func (*TerminalSessionRegistry) EnsureAgentTerminal added in v0.2.3

func (r *TerminalSessionRegistry) EnsureAgentTerminal(ctx context.Context, userID, projectID, templateID, agentSessionID int64) (int64, error)

EnsureAgentTerminal 按 (userID, projectID, templateID, agentSessionID) 创建或复用 Agent 会话的终端容器,返回终端会话主键。

与 GetPersistentShell 对应:供 hostshell.ContainerShell 在第一次执行命令时调用, 之后同一 Agent 会话的多次调用复用同一个容器与 PTY。

会话一律标记为持久(persistent=true):容器 shell 的生命周期等于一次 Agent 请求, 由调用方在请求结束时通过 Close / CloseShell 回收(见 providers/custom.go 的 OnFinish)。 若按一次性会话创建,命令一结束 execLoop 就会 scheduleReap 掉容器与会话记录, 下一次 Exec 只能拿到 ErrTerminalSessionNotFound。

func (*TerminalSessionRegistry) EnsurePersistent added in v0.2.0

EnsurePersistent 创建(或复用)会话,并把会话标记为持久会话(见 types.AppSession.Persistent)。

WebSocket 接入(ContainerTemplateTerminal)走这个入口:无论会话是否新建、是否复用, 只要前端接入了,此后就只能由空闲 TTL 或显式 DELETE 回收。

func (*TerminalSessionRegistry) EnsurePersistentSized added in v0.2.0

func (r *TerminalSessionRegistry) EnsurePersistentSized(ctx context.Context, key TerminalSessionKey, rows, cols uint16) (*ManagedTerminalSession, bool, error)

EnsurePersistentSized 与 EnsurePersistent 相同,但会带上前端 xterm 的行列: 新建的会话直接以这个尺寸创建 PTY;已存活的会话保持原 PTY,接入方再调用 Resize 同步。

func (*TerminalSessionRegistry) Exec added in v0.2.3

func (r *TerminalSessionRegistry) Exec(ctx context.Context, terminalID int64, command string, timeoutSeconds int) (runtimecontext.ContainerTerminalExecResult, error)

Exec 实现 hostshell.ContainerShellService。

func (*TerminalSessionRegistry) ExecInTerminal added in v0.2.3

func (r *TerminalSessionRegistry) ExecInTerminal(ctx context.Context, terminalID int64, command string, timeoutSeconds int) (runtimecontext.ContainerTerminalExecResult, error)

ExecInTerminal 按终端会话主键执行命令并等待结束。

与 PersistentShell.Exec 对应:会话存活期间 cd / export / 已安装的包在多次调用之间保留。

func (*TerminalSessionRegistry) Execute added in v0.2.0

Execute 把命令写入会话的串行队列。

定位规则(见 ensure):

  • key.ID > 0:直接投递到该终端会话;
  • 否则按 (templateID, agentSessionID) 查找 Agent 会话的终端(agentSessionID=0 时新建);
  • 会话不存在且 cmd.CreateIfMissing 时按 cmd.Persistent 创建。

Wait=false 时只投递并立即返回;Wait=true 时等待命令结束(靠 OSC 标记判定), 超时返回 TimedOut=true 与已产生的输出。

func (*TerminalSessionRegistry) Lookup added in v0.2.0

Lookup 返回存活会话(不创建)。

定位顺序:

  • key.ID != 0:按终端会话主键查找;
  • key.AgentSessionID > 0:按 (userID, projectID, templateID, agentSessionID) 查找 (Agent 侧只关心「这个 Agent 会话在该模板上的终端」,不关心会话 ID);
  • 否则无法定位:会话以主键为唯一标识。

func (*TerminalSessionRegistry) LookupByID added in v0.2.0

LookupByID 按终端会话主键返回存活会话(不创建)。

新会话在落库前使用负数占位 ID,因此这里只拒绝 0。

func (*TerminalSessionRegistry) MarkPersistent added in v0.2.0

func (r *TerminalSessionRegistry) MarkPersistent(ctx context.Context, key TerminalSessionKey)

MarkPersistent 把会话标记为持久,并同步到持久层。

只会 false → true:已经持久的会话不会被改回一次性。

func (*TerminalSessionRegistry) ReviveByID added in v0.2.0

func (r *TerminalSessionRegistry) ReviveByID(ctx context.Context, id int64, rows, cols uint16) (*ManagedTerminalSession, error)

ReviveByID 按终端会话主键「重建」一个本进程里还不存在的会话。 典型场景:进程重启后会话(AppSession)与容器都还在,但 shell 随进程结束。 这里走与创建相同的 ensure 路径:能认领原容器就重新 exec 一个 shell(adoptSession), 容器已不存在则新建;历史输出由落盘的滚动缓冲回放。

rows/cols 是前端 xterm 当前尺寸:会话已存活时直接 Resize 到该尺寸; 需要重新 exec shell 时用它建 PTY。传 0 时保持原尺寸 / 使用默认 24x80。

返回 ErrTerminalSessionNotFound 表示记录不存在,由调用方报 404。 id 只拒绝 0(未分配):落库前的新会话使用负数占位 ID,它们同样可以被定位。

func (*TerminalSessionRegistry) RunInTerminal added in v0.2.0

RunInTerminal 实现 runtimecontext.ContainerTerminalRunner,供 Agent 工具注入。

会话定位:按 (userID, projectID, templateID, agentSessionID) 查找该 Agent 会话在该模板上的 终端会话;不存在时新建(同一 agentSessionID + templateID 唯一),因此同一个 Agent 会话 多次调用 terminal_exec 会复用同一个容器与 PTY。

语义:

  • 创建新会话时,按 in.Persistent 决定它是一次性还是持久会话;
  • 命令结束(含超时 / 失败)后总是 Detach:一次性会话因此立即回收容器, 持久会话则保留,等待空闲 TTL 或用户显式关闭。

func (*TerminalSessionRegistry) SessionRecord added in v0.2.0

func (r *TerminalSessionRegistry) SessionRecord(ctx context.Context, id int64) (*types.AppSession, error)

SessionRecord 按终端会话主键返回持久层记录(不存在时返回 nil)。

供 handler 在内存注册表里找不到会话时做归属校验 / 判断会话是否仍然存在。

func (*TerminalSessionRegistry) StartMaintenance added in v0.2.0

func (r *TerminalSessionRegistry) StartMaintenance(ctx context.Context)

StartMaintenance 启动后台维护:空闲会话回收 + 跨进程残留对账。 传入的 ctx 取消时退出。

func (*TerminalSessionRegistry) Status added in v0.2.0

Status 返回会话状态;不存在时 Exists=false。

type TerminalSessionStatus added in v0.2.0

type TerminalSessionStatus struct {
	// SessionID 是终端会话主键(= types.AppSession.ID)的字符串形式,
	// 也是 WS / exec / status / close 接口里使用的 {id}。
	SessionID   string `json:"session_id"`
	Exists      bool   `json:"exists"`
	Alive       bool   `json:"alive"`
	Subscribers int    `json:"subscribers"`
	Seq         int64  `json:"seq"`

	// 以下字段只在「按用户列出会话」时填充,供左侧栏列表 join 容器模板展示。
	UserID     int64 `json:"user_id,omitempty,string"`
	ProjectID  int64 `json:"project_id,omitempty,string"`
	TemplateID int64 `json:"template_id,omitempty,string"`
	// AgentSessionID 是创建该终端会话的 Agent 会话 ID;0 表示 UI 手动创建。
	AgentSessionID int64 `json:"agent_session_id,omitempty,string"`
	// Name 是会话展示名(UI 创建时写入;Agent 创建时取模板展示名)。
	Name string `json:"name,omitempty"`
	// Persistent 为 true 表示会话只能由空闲 TTL 或显式关闭回收。
	Persistent bool `json:"persistent"`
	// Busy 表示当前有命令在执行(此时空闲 TTL 不会回收容器)。
	Busy bool `json:"busy"`
	// RuntimeID / RuntimeName 是底层容器标识(docker id / k8s workload),便于排查。
	RuntimeID   string `json:"runtime_id,omitempty"`
	RuntimeName string `json:"runtime_name,omitempty"`
	// CreatedAt 是会话在内存注册表里的创建时间;LastActive 是最近一次操作时间。
	CreatedAt  time.Time `json:"created_at,omitempty"`
	LastActive time.Time `json:"last_active,omitempty"`
}

TerminalSessionStatus 是会话的只读状态。

type TerminalSessionStore added in v0.2.0

type TerminalSessionStore interface {
	// Get 按会话 key 读取记录;不存在返回 (nil, nil)。
	Get(ctx context.Context, key TerminalSessionKey) (*types.AppSession, error)
	// GetByID 按会话主键读取记录;不存在返回 (nil, nil)。
	GetByID(ctx context.Context, id int64) (*types.AppSession, error)
	// FindAgentSession 按 (userID, projectID, templateID, agentSessionID) 查找 Agent 会话对应的终端会话;
	// agentSessionID <= 0(UI 手动创建)时永远返回 (nil, nil)。
	FindAgentSession(ctx context.Context, userID, projectID, templateID, agentSessionID int64) (*types.AppSession, error)
	// Create 新增一条会话记录,并回填 rec.ID。
	//
	// name 只在创建时写入:之后 Update 不会再改它(DB 是 name 的唯一真相,
	// 改名必须走独立接口)。
	Create(ctx context.Context, rec *types.AppSession) error
	// Update 按主键更新已存在记录的运行时字段(status / persistent / last_access_at 等),
	// 不会修改 name。
	Update(ctx context.Context, rec *types.AppSession) error
	// Touch 刷新 last_access_at。
	Touch(ctx context.Context, key TerminalSessionKey, at time.Time) error
	// MarkPersistent 把会话标记为持久(幂等,只会 false → true)。
	MarkPersistent(ctx context.Context, key TerminalSessionKey) error
	// Delete 按会话 key 删除记录。
	Delete(ctx context.Context, key TerminalSessionKey) error
	// DeleteByID 按会话主键删除记录。
	DeleteByID(ctx context.Context, id int64) error
	// List 返回全部记录(用于启动/定期对账)。
	List(ctx context.Context) ([]*types.AppSession, error)
	// ListByUser 返回某用户的全部会话记录,供「终端会话列表」使用。
	ListByUser(ctx context.Context, userID int64) ([]*types.AppSession, error)
}

TerminalSessionStore 是终端会话持久层的最小契约。

终端会话与「应用会话」是同一个实体(types.AppSession,表 go_container_app_session),这里只暴露注册表需要的能力:定位会话、落库 持久标记、刷新活跃时间、删除会话。注册表不依赖完整 repository 层, 单测可以用内存 fake 或直接传 nil。

会话的对外标识是它的主键 ID(= AppSession.ID),因此 Get / Delete / Touch / MarkPersistent 既可以按 ID,也可以按 (userID, projectID, templateID, agentSessionID) 定位。

type TerminalSubscriber added in v0.2.0

type TerminalSubscriber struct {
	ID   int64
	Data chan []byte
	// Events 承载 JSON 控制事件(exec start/end、exit 等),由 handler 以文本帧发送。
	Events chan []byte
	// contains filtered or unexported fields
}

TerminalSubscriber 是一个终端输出订阅者(浏览器 WebSocket)。

func (*TerminalSubscriber) Done added in v0.2.0

func (s *TerminalSubscriber) Done() <-chan struct{}

Done 在订阅者被关闭时关闭。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL