package api import ( "context" "errors" hub "git.ipao.vip/rogee/creator-hub/internal/environment" ) // 账号即环境:账号创建即绑定运行环境。 // 规则:alias = 账号文本 ID、唯一网关自动取、出口直连、seed 由账号 ID 派生。 // soleGateway 返回平台唯一网关;零配置绑定要求恰有一个网关: // 缺失返回 ErrNotFound,多个返回 ErrConflict(无法自动选择)。 func soleGateway(ctx context.Context, store HubStore) (hub.Gateway, error) { gateways, err := store.ListGateways(ctx) if err != nil { return hub.Gateway{}, err } if len(gateways) == 0 { return hub.Gateway{}, hub.ErrNotFound } if len(gateways) > 1 { return hub.Gateway{}, hub.ErrConflict } return gateways[0], nil } // ensureAccountEnvironment 幂等补建账号环境:已绑定(任意出口)原样返回; // 未绑定时以 alias=账号 ID、派生 seed、指定指纹、直连出口创建。 func ensureAccountEnvironment(ctx context.Context, store HubStore, accountID string, fingerprint hub.Fingerprint) (hub.EnvironmentContext, bool, error) { environment, err := store.GetEnvironmentContextForAccount(ctx, accountID) if err == nil { return environment, false, nil } if !errors.Is(err, hub.ErrNotFound) { return hub.EnvironmentContext{}, false, err } gateway, err := soleGateway(ctx, store) if err != nil { return hub.EnvironmentContext{}, false, err } // seed 由 CreateBoundEnv 从账号 bigint id + 1000 派生(数字主键)。 return store.CreateBoundEnv(ctx, hub.Env{ Alias: accountID, Name: accountID, Gateway: gateway.Name, Fingerprint: fingerprint, }, accountID, "") } // startAccountEnvironment 启动账号环境并记录审计对;环境缺失时幂等补建(创建即绑定的自愈路径)。 func startAccountEnvironment(ctx context.Context, store HubStore, accountID string) error { environment, err := store.GetEnvironmentContextForAccount(ctx, accountID) if errors.Is(err, hub.ErrNotFound) { // start 自愈补建时创建表单不可得,零值指纹 = 派生 seed + 浏览器默认参数。 environment, _, err = ensureAccountEnvironment(ctx, store, accountID, hub.Fingerprint{}) } if err != nil { return err } action := actionForEnvironment("start", environment) if err := store.AppendEnvironmentAction(ctx, "environment_action_requested", action); err != nil { return err } finish := func(outcome, reason string, current hub.EnvironmentContext) error { action.Outcome, action.ReasonCode = outcome, reason action.BindingVersion, action.NetworkExitID = current.BindingVersion, current.Exit.ID return store.AppendEnvironmentAction(ctx, "environment_action_finished", action) } return startBrowserRuntime(ctx, store, defaultNetworkExitProbe(), environment, finish) }