Documentation
¶
Overview ¶
Package store 是 SQLite 持久层(modernc.org/sqlite,纯 Go 零 CGO)。 schema 内嵌,启动时按 PRAGMA user_version 自动逐级迁移。
Index ¶
- Variables
- type AppDomainRecordRow
- type AuditEvent
- type AuthUser
- type CommandRow
- type DeviceMetaInput
- type DeviceRow
- type EventRow
- type PluginEdgeRevisionRow
- type PluginInstallationRow
- type PluginInstanceRow
- type PluginObservationRow
- type ScheduledJobRow
- type SessionRow
- type StateRow
- type Stats
- type Store
- func (s *Store) AddEvent(deviceID, typ, payload string, ts int64) (int64, error)
- func (s *Store) AddEventTenant(tenantID int64, deviceID, typ, payload string, ts int64) (int64, error)
- func (s *Store) CancelScheduledJob(tenantID int64, instanceID, scheduleID string) error
- func (s *Store) ClaimScheduledJobRun(tenantID int64, instanceID, scheduleID string, nextRunAt, lastRunAt int64, ...) error
- func (s *Store) Close() error
- func (s *Store) CountEnabledAdmins(tenantID int64) (int64, error)
- func (s *Store) CountPluginInstances(tenantID int64) (int, error)
- func (s *Store) CountUsers() (int64, error)
- func (s *Store) CreateCommand(deviceID, cmd, args string) (int64, error)
- func (s *Store) CreateCommandTenant(deviceID, cmd, args string, tenantID int64) (int64, error)
- func (s *Store) CreateInitialAdmin(username, name, passwordHash string) (AuthUser, bool, error)
- func (s *Store) CreatePluginInstance(row PluginInstanceRow) (uint64, error)
- func (s *Store) CreateSession(id string, userID, expiresAt int64) error
- func (s *Store) CreateTenant(slug, name string) (int64, error)
- func (s *Store) CreateTenantToken(tenantID int64, name, hash, prefix, scopesJSON string, expiresAt *int64) (TokenRow, error)
- func (s *Store) CreateUser(tenantID int64, username, name, role, passwordHash string) (AuthUser, error)
- func (s *Store) DeletePluginInstance(tenantID int64, edgeID, instanceID string, purge bool) (uint64, error)
- func (s *Store) DeleteSession(id string) error
- func (s *Store) DeleteSessionsByUser(userID int64) (int64, error)
- func (s *Store) EnsureDefaultTenant() (int64, error)
- func (s *Store) FailedCommandsWindow(tenantID *int64, since, until int64, limit int) ([]CommandRow, int, error)
- func (s *Store) GetAppDomainRecord(tenantID int64, instanceID, recordType, recordID string) (AppDomainRecordRow, error)
- func (s *Store) GetPluginEdgeRevision(tenantID int64, edgeID string) (PluginEdgeRevisionRow, error)
- func (s *Store) GetPluginInstance(tenantID int64, edgeID, instanceID string) (PluginInstanceRow, bool, error)
- func (s *Store) GetStates() (map[string]StateRow, error)
- func (s *Store) GetTenantByID(id int64) (TenantRow, error)
- func (s *Store) GetTenantBySlug(slug string) (TenantRow, error)
- func (s *Store) GetTenantPolicy(tenantID int64) (TenantPolicyRow, error)
- func (s *Store) GetTenantToken(id, tenantID int64) (TokenRow, error)
- func (s *Store) GetTenantTokenByHash(hash string) (TokenRow, error)
- func (s *Store) GetUserByID(id int64) (AuthUser, error)
- func (s *Store) GetUserByUsername(username string) (AuthUser, error)
- func (s *Store) InsertAuditEvent(ev AuditEvent) error
- func (s *Store) ListAppDomainRecords(tenantID int64, instanceID string, limit int) ([]AppDomainRecordRow, error)
- func (s *Store) ListAppDomainRecordsFiltered(tenantID int64, instanceID, recordType string, limit, offset int) ([]AppDomainRecordRow, error)
- func (s *Store) ListAuditEvents(tenantID int64, since int64, action string, limit int) ([]AuditEvent, error)
- func (s *Store) ListCommands(deviceID, status string, limit int) ([]CommandRow, error)
- func (s *Store) ListCommandsTenant(tenantID int64, deviceID, status string, limit int) ([]CommandRow, error)
- func (s *Store) ListDevices() ([]DeviceRow, error)
- func (s *Store) ListDevicesTenant(tenantID int64) ([]DeviceRow, error)
- func (s *Store) ListEvents(deviceID string, since int64, limit int) ([]EventRow, error)
- func (s *Store) ListEventsTenant(tenantID int64, deviceID string, since int64, limit int) ([]EventRow, error)
- func (s *Store) ListPluginInstallationsTenant(tenantID int64) ([]PluginInstallationRow, error)
- func (s *Store) ListPluginInstancesAll() ([]PluginInstanceRow, error)
- func (s *Store) ListPluginInstancesTenant(tenantID int64) ([]PluginInstanceRow, error)
- func (s *Store) ListPluginObservationsTenant(tenantID int64) ([]PluginObservationRow, error)
- func (s *Store) ListScheduledJobs(tenantID int64, instanceID string) ([]ScheduledJobRow, error)
- func (s *Store) ListScheduledJobsDue(now int64) ([]ScheduledJobRow, error)
- func (s *Store) ListTenantTokens(tenantID int64) ([]TokenRow, error)
- func (s *Store) ListUsersTenant(tenantID int64) ([]AuthUser, error)
- func (s *Store) PluginDesiredRevision(tenantID int64, edgeID string) (uint64, error)
- func (s *Store) PruneCommands(before int64) (int64, error)
- func (s *Store) PruneEvents(before int64) (int64, error)
- func (s *Store) PrunePluginObservations(tenantID int64, before int64) (int64, error)
- func (s *Store) PruneSessions(before int64) (int64, error)
- func (s *Store) RevokeTenantToken(id, tenantID int64) (bool, error)
- func (s *Store) SetDeviceDescriptor(deviceID, descriptorJSON string) error
- func (s *Store) SetPluginEdgeApplied(tenantID int64, edgeID, bootID string, seq, appliedRevision uint64, at int64) error
- func (s *Store) SetPluginEdgeReport(tenantID int64, edgeID, bootID string, seq uint64, at int64) error
- func (s *Store) SetState(deviceID, stateJSON string, online bool, updatedAt int64) error
- func (s *Store) SetTenantPolicy(tenantID int64, p TenantPolicyRow) error
- func (s *Store) Stats() (Stats, error)
- func (s *Store) StatsTenant(tenantID int64) (Stats, error)
- func (s *Store) TenantIDBySlug(slug string) (int64, error)
- func (s *Store) TimeoutStaleCommandIDs(ttl time.Duration) ([]int64, error)
- func (s *Store) TimeoutStaleCommands(ttl time.Duration) (int64, error)
- func (s *Store) TouchSession(id string, lastSeen int64) error
- func (s *Store) TouchTenantToken(id, at int64) error
- func (s *Store) UpdateCommandStatus(id int64, status, result string) error
- func (s *Store) UpdateCommandStatusScoped(id int64, deviceID string, tenantID int64, status, result string) (bool, error)
- func (s *Store) UpdatePluginInstance(row PluginInstanceRow) (uint64, error)
- func (s *Store) UpdateUser(tenantID, id int64, patch UserPatch) (AuthUser, error)
- func (s *Store) UpsertAppDomainRecord(tenantID int64, instanceID, recordType, recordID, dataJSON, version string, ...) error
- func (s *Store) UpsertDevice(id, edgeID, adapter, name, port string) error
- func (s *Store) UpsertDeviceTenant(id, edgeID, adapter, name, port string, tenantID int64) error
- func (s *Store) UpsertDevicesTenant(edgeID string, metas []DeviceMetaInput, tenantID int64) error
- func (s *Store) UpsertPluginInstallations(tenantID int64, edgeID string, rows []api.PluginInstallationStatusData) error
- func (s *Store) UpsertPluginObservations(tenantID int64, edgeID string, rows []api.PluginObservedInstanceData, ...) error
- func (s *Store) UpsertScheduledJob(row ScheduledJobRow) (ScheduledJobRow, error)
- func (s *Store) UserBySession(id string, at int64) (AuthUser, error)
- func (s *Store) Version() int
- type TenantPolicyRow
- type TenantRow
- type TokenRow
- type UserPatch
- type UserRow
Constants ¶
This section is empty.
Variables ¶
var ( // ErrPluginInstanceNotFound 表示 (tenant, edge, instance) 期望态行不存在 → api.PluginErrNotFound。 ErrPluginInstanceNotFound = errors.New("store: plugin instance not found") // ErrPluginInstanceConflict 表示 Create 目标实例已存在 → api.PluginErrConflict。 ErrPluginInstanceConflict = errors.New("store: plugin instance already exists") // ErrPluginQuotaExceeded 表示租户 plugin instance 配额已满:写在事务内被原子拒绝, // revision 未推进、无任何半状态 → api.PluginErrQuota(tenant-security-policy.md §4.1、§6.2)。 ErrPluginQuotaExceeded = errors.New("store: plugin instance quota exceeded") // ErrPluginIdentityIncomplete 表示 edge_id / instance_id / plugin_id / boot_id 缺失,fail-closed。 ErrPluginIdentityIncomplete = errors.New("store: plugin identity incomplete") // ErrPluginConfigInvalid 表示 config_json / secret_refs 不是契约要求的 JSON 形状 // → api.PluginErrInvalidConfig。 ErrPluginConfigInvalid = errors.New("store: plugin config or secret refs invalid") // ErrPluginImmutableField 表示试图改写不可变字段(实例的 plugin_id 归属); // 换插件是新实例语义,必须走 Create,不得由 Update 静默改写。 ErrPluginImmutableField = errors.New("store: plugin instance immutable field changed") )
插件控制面稳定 sentinel 错误:调用方用 errors.Is 判断并映射到 api.PluginErr* 稳定码, 不要依赖错误文本。
var ( // ErrUsernameTaken 表示 username 已存在(租户内唯一,handler 回 409)。 ErrUsernameTaken = errors.New("store: username already taken") // ErrLastAdmin 表示目标用户是最后一个可用 admin,禁止禁用/降级(handler 回 409)。 ErrLastAdmin = errors.New("store: cannot disable or demote the last admin") // ErrInvalidRole 表示角色不在 admin|operator|viewer 内。 ErrInvalidRole = errors.New("store: invalid role") )
用户/令牌管理的哨兵错误(docs/api.md §3.2/§3.3 语义)。
var ErrDeviceDescriptorEmpty = errors.New("store: device descriptor is empty")
ErrDeviceDescriptorEmpty 表示 Descriptor JSON 为空,拒绝覆盖最后已知描述。
var ErrDeviceDescriptorTooLarge = errors.New("store: device descriptor exceeds size limit")
ErrDeviceDescriptorTooLarge 表示 Descriptor JSON 超过持久化上限。
var ErrDeviceNotFound = errors.New("store: device not found")
ErrDeviceNotFound 表示设备不存在,Descriptor 等设备级写入必须 fail-closed。
var ErrDeviceTenantMismatch = errors.New("store: device identity bound to another tenant")
ErrDeviceTenantMismatch 表示设备身份已绑定其他租户,写入必须 fail-closed。
var ErrEdgeTenantMismatch = errors.New("store: edge identity bound to another tenant")
ErrEdgeTenantMismatch 表示 edge 身份已绑定其他租户,写入必须 fail-closed。
Functions ¶
This section is empty.
Types ¶
type AppDomainRecordRow ¶ added in v0.2.3
type AppDomainRecordRow struct {
TenantID int64
InstanceID string
RecordType string
RecordID string
DataJSON string
Version string
UpdatedAt int64
}
AppDomainRecordRow 是 app_domain_records 一行(Application Plugin 的领域记录)。
type AuditEvent ¶
type AuditEvent struct {
ID int64
TenantID int64
ActorType string
ActorID int64
ActorName string
Action string
TargetType string
TargetID string
Outcome string
RequestID string
RemoteIP string
MetadataJSON string
CreatedAt int64
}
AuditEvent 是 audit_events 表一行。append-only:本包只暴露 INSERT 与 tenant-scoped 查询, 不暴露任何 update/delete API(安全红线由代码结构锁定)。
type CommandRow ¶
type CommandRow struct {
ID int64
DeviceID string
Cmd string
Args string
Status string
CreatedAt int64
AckedAt sql.NullInt64
Result string
}
CommandRow 是 commands 一行。
type DeviceMetaInput ¶
DeviceMetaInput 是批量设备注册的输入(ID 为完整 "<edge>/<dev>" 键)。
type DeviceRow ¶
type DeviceRow struct {
ID string
EdgeID string
Adapter string
Name string
Port string
FirstSeen int64
LastSeen int64
DescriptorJSON string
TenantID int64
TenantSlug string
}
DeviceRow 是 devices 表一行。
type PluginEdgeRevisionRow ¶
type PluginEdgeRevisionRow struct {
TenantID int64
EdgeID string
DesiredRevision uint64
AppliedRevision uint64
BootID string
LastSequence uint64
LastReportAt int64
LastAckAt int64
}
PluginEdgeRevisionRow 是 plugin_edge_revisions 一行:每 (tenant, edge) 的同步游标。
type PluginInstallationRow ¶
type PluginInstallationRow struct {
api.PluginInstallationStatusData
TenantID int64
EdgeID string
ReportedAt int64
}
PluginInstallationRow 是 plugin_installations 投影一行:Edge 上报的已安装插件公开事实。 内嵌 api.PluginInstallationStatusData。本表只存公开 manifest 字段, 永不含本地路径、启动参数、环境变量或 secret 值(§7、tenant-security-policy.md §2.4)。
type PluginInstanceRow ¶
type PluginInstanceRow struct {
TenantID int64
EdgeID string
InstanceID string
PluginID string
Version string
Enabled bool
Isolation string
ConfigJSON string
SecretRefs string
Revision uint64
CreatedAt int64
UpdatedAt int64
}
PluginInstanceRow 是 plugin_desired_instances 一行(Server 权威期望态)。 ConfigJSON 是 map[string]string 的 JSON,值只含非敏感标量或 secret:// handle; SecretRefs 是 JSON []string,只含 handle 名称。Revision 是该行最后一次写入时所属 (tenant_id, edge_id) 的 desired revision(写入时由 store 赋值,调用方传入值被忽略)。
type PluginObservationRow ¶
type PluginObservationRow struct {
api.PluginObservedInstanceData
TenantID int64
EdgeID string
ReportedAt int64
}
PluginObservationRow 是 plugin_observations 投影一行:Edge 上报的实例实际态 + 归属坐标。 内嵌 api.PluginObservedInstanceData(instance/plugin/version/host_online/state/health/ detail/restart_count/last_healthy/message_rate),读侧可直接复用 DTO 组装 api.PluginInstanceObservedView。boot/sequence/applied_revision 不在此重复存储—— 它们是 per-edge 事实,唯一来源是 plugin_edge_revisions(GetPluginEdgeRevision)。
type ScheduledJobRow ¶ added in v0.2.8
type ScheduledJobRow struct {
TenantID int64
InstanceID string
ScheduleID string
Cron string
Timezone string
PayloadJSON string
MissedPolicy string // skip | run_once
NextRunAt int64 // 计划触发时刻(unix 秒)
LastRunAt int64
LastDispatch string
State string // active | cancelled
Revision int64
CreatedAt int64
UpdatedAt int64
}
ScheduledJobRow 是 scheduled_jobs 一行(Durable Scheduler 的持久态)。
type SessionRow ¶
SessionRow 是 sessions 表一行。
type Stats ¶
type Stats struct {
Devices int64 `json:"devices"`
Events int64 `json:"events"`
Commands int64 `json:"commands"`
OldestEvent int64 `json:"oldest_event"`
SchemaVer int `json:"schema_version"`
}
Stats 是存储侧计数(系统页展示用)。
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store 持有数据库连接。所有方法并发安全(database/sql 连接池)。
func (*Store) AddEventTenant ¶
func (s *Store) AddEventTenant(tenantID int64, deviceID, typ, payload string, ts int64) (int64, error)
AddEventTenant 只在设备确属指定租户时写事件(fail-closed,不回退 default)。
func (*Store) CancelScheduledJob ¶ added in v0.2.8
CancelScheduledJob 撤销一条定时任务(cancel_job 效果落点)。幂等:不存在或 已取消均不报错(删除语义的收敛写)。
func (*Store) ClaimScheduledJobRun ¶ added in v0.2.8
func (s *Store) ClaimScheduledJobRun(tenantID int64, instanceID, scheduleID string, nextRunAt, lastRunAt int64, dispatchKey string) error
ClaimScheduledJobRun 领取一次运行:先持久化推进 next_run_at / last_run_at / last_dispatch,再由调用方派发(claim-then-dispatch)。崩溃发生在 claim 之后、 派发之前 → 该次运行静默跳过(at-most-once,符合平台「不回放过期副作用」 哲学);崩溃不可能造成重复派发(next_run_at 已推进,同 run 不会被再次选中)。 dispatchKey 为空表示本次不派发(skip 策略只推进)。
func (*Store) CountEnabledAdmins ¶
CountEnabledAdmins 返回租户内启用中的 admin 数(保护与测试用)。
func (*Store) CountPluginInstances ¶
CountPluginInstances 返回本租户期望态实例数(配额准入与 UI 计数共用同一口径: 只数 Server 权威 desired,不数 Edge 上报投影)。
func (*Store) CountUsers ¶
CountUsers 返回用户总数(判定账号模式/首装状态)。
func (*Store) CreateCommand ¶
CreateCommand 建命令行(pending),返回命令 ID;tenant_id 由 devices 表继承,设备缺失时回落 default。
func (*Store) CreateCommandTenant ¶
CreateCommandTenant 在指定租户下为已存在设备建命令行;设备不存在或跨租户返回 sql.ErrNoRows。
func (*Store) CreateInitialAdmin ¶
CreateInitialAdmin 原子首装:确保 default 租户存在,且仅当用户数为 0 时创建首个 admin。 created=false 表示已有用户(调用方回 409)。事务保证并发首装只会成功一次。
func (*Store) CreatePluginInstance ¶
func (s *Store) CreatePluginInstance(row PluginInstanceRow) (uint64, error)
CreatePluginInstance 新建期望态实例并在同一事务内原子推进 (tenant,edge) desired revision, 返回新 revision。row.Revision / CreatedAt / UpdatedAt 由 store 赋值(CreatedAt<=0 用 now())。
拒绝路径(全部整体回滚,revision 不消费、无半状态):
- 身份段缺失 → ErrPluginIdentityIncomplete
- config/secret_refs 形状非法 → ErrPluginConfigInvalid
- edge 已绑定其他租户 → ErrEdgeTenantMismatch
- 配额已满 → ErrPluginQuotaExceeded(计数与写入同事务,杜绝「先 COUNT 后 INSERT」竞态)
- 实例已存在 → ErrPluginInstanceConflict
func (*Store) CreateSession ¶
CreateSession 落一条服务端会话(登录成功调用;每次登录都新 ID,天然防会话固定)。
func (*Store) CreateTenant ¶
CreateTenant 创建新租户(P2 测试/后续租户管理使用),返回其 id。
func (*Store) CreateTenantToken ¶
func (s *Store) CreateTenantToken(tenantID int64, name, hash, prefix, scopesJSON string, expiresAt *int64) (TokenRow, error)
CreateTenantToken 落一条租户服务令牌(只存 hash/prefix/scopes)。
func (*Store) CreateUser ¶
func (s *Store) CreateUser(tenantID int64, username, name, role, passwordHash string) (AuthUser, error)
CreateUser 在租户内创建用户;username 冲突返回 ErrUsernameTaken。
func (*Store) DeletePluginInstance ¶
func (s *Store) DeletePluginInstance(tenantID int64, edgeID, instanceID string, purge bool) (uint64, error)
DeletePluginInstance 删除期望态实例并原子推进 revision(Edge 需靠新 revision 收敛「实例已移除」), 返回新 revision。不存在 → ErrPluginInstanceNotFound(不消费 revision)。
purge=false(默认):只删期望态,保留 observed 投影、该实例的领域记录与定时任务,以及插件安装事实。 purge=true:在同一写事务中额外删除该实例的 plugin_observations、app_domain_records 和 scheduled_jobs(API 语义「显式清除该实例私有数据」)。 两种情况都**绝不**删除 audit_events(契约:删除期望态不删审计),也不删 plugin_installations ——安装物是 per-plugin 事实,可能被同 edge 的其他实例共享。
func (*Store) DeleteSession ¶
DeleteSession 删除会话(登出;幂等,不存在也返回 nil)。
func (*Store) DeleteSessionsByUser ¶
DeleteSessionsByUser 撤销用户全部会话,返回删除行数(幂等)。
func (*Store) EnsureDefaultTenant ¶
EnsureDefaultTenant 幂等创建 default 租户(首装自动创建),返回其 id。
func (*Store) FailedCommandsWindow ¶ added in v0.2.13
func (s *Store) FailedCommandsWindow(tenantID *int64, since, until int64, limit int) ([]CommandRow, int, error)
FailedCommandsWindow 返回闭区间 [since, until] 内 failed/timeout 命令及完整计数。 失败时间取 acked_at(包括服务端写入的 timeout 时刻),缺失则回退 created_at。 tenantID 非 nil 时始终限定该租户(包括无效的 0);只有 nil 表示明确的无鉴权全局视图。 列表按失败时间、ID 降序且有界;窗口计数先于 LIMIT,二者来自同一 SQL 读快照。
func (*Store) GetAppDomainRecord ¶ added in v0.2.3
func (s *Store) GetAppDomainRecord(tenantID int64, instanceID, recordType, recordID string) (AppDomainRecordRow, error)
GetAppDomainRecord 取单条领域记录;不存在返回 sql.ErrNoRows。
func (*Store) GetPluginEdgeRevision ¶
func (s *Store) GetPluginEdgeRevision(tenantID int64, edgeID string) (PluginEdgeRevisionRow, error)
GetPluginEdgeRevision 读 (tenant, edge) 同步游标。从未同步过返回全零行(TenantID/EdgeID 已填) 且 error 为 nil,调用方无需处理 sql.ErrNoRows。
func (*Store) GetPluginInstance ¶
func (s *Store) GetPluginInstance(tenantID int64, edgeID, instanceID string) (PluginInstanceRow, bool, error)
GetPluginInstance 读单个期望态实例;不存在返回 (zero, false, nil)。
func (*Store) GetTenantByID ¶
GetTenantByID 按 id 读租户;不存在返回 sql.ErrNoRows。
func (*Store) GetTenantBySlug ¶
GetTenantBySlug 按 slug 读租户;不存在返回 sql.ErrNoRows。
func (*Store) GetTenantPolicy ¶
func (s *Store) GetTenantPolicy(tenantID int64) (TenantPolicyRow, error)
GetTenantPolicy 读本租户策略行。无策略行时返回全 0 行(= 全部继承默认)且 error 为 nil, 调用方无需处理 sql.ErrNoRows;用 Resolve() 取得可执行策略。
func (*Store) GetTenantToken ¶
GetTenantToken 按 id+租户读令牌(handler 校验归属用)。
func (*Store) GetTenantTokenByHash ¶
GetTenantTokenByHash 按 hash 读令牌(鉴权路径);不存在返回 sql.ErrNoRows。
func (*Store) GetUserByID ¶
GetUserByID 按 id 读用户(含租户 slug);不存在返回 sql.ErrNoRows。
func (*Store) GetUserByUsername ¶
GetUserByUsername 按用户名读用户(含租户 slug);不存在返回 sql.ErrNoRows。
func (*Store) InsertAuditEvent ¶
func (s *Store) InsertAuditEvent(ev AuditEvent) error
InsertAuditEvent 追加一条审计事件。写失败由调用方消化(audit 失败不得改变业务结果)。
func (*Store) ListAppDomainRecords ¶ added in v0.2.3
func (s *Store) ListAppDomainRecords(tenantID int64, instanceID string, limit int) ([]AppDomainRecordRow, error)
ListAppDomainRecords 按实例列领域记录(按更新时间倒序,limit<=0 默认 100,上限 1000)。
func (*Store) ListAppDomainRecordsFiltered ¶ added in v0.2.7
func (s *Store) ListAppDomainRecordsFiltered(tenantID int64, instanceID, recordType string, limit, offset int) ([]AppDomainRecordRow, error)
ListAppDomainRecordsFiltered 按实例列领域记录,支持 record_type 过滤与 limit/offset 分页(按更新时间倒序)。recordType 为空 = 不过滤;limit<=0 默认 100、上限 1000;offset<0 归零。offset 分页在本表规模(单实例数百条) 下语义足够,不引入游标。
func (*Store) ListAuditEvents ¶
func (s *Store) ListAuditEvents(tenantID int64, since int64, action string, limit int) ([]AuditEvent, error)
ListAuditEvents 查询本租户审计事件:since>0 只取 created_at>=since;action 非空精确过滤; limit 经 clampLimit 归一(<=0 或 >1000 → 100)。恒按 tenant_id 过滤,跨租户不可见。
func (*Store) ListCommands ¶
func (s *Store) ListCommands(deviceID, status string, limit int) ([]CommandRow, error)
ListCommands 查询命令。deviceID/status 为空表示不过滤。
func (*Store) ListCommandsTenant ¶
func (s *Store) ListCommandsTenant(tenantID int64, deviceID, status string, limit int) ([]CommandRow, error)
ListCommandsTenant 查询指定租户的命令(账号模式)。
func (*Store) ListDevices ¶
ListDevices 返回全部注册设备(无账号开发模式沿用)。
func (*Store) ListDevicesTenant ¶
ListDevicesTenant 返回指定租户的设备(账号模式)。
func (*Store) ListEvents ¶
ListEvents 查询事件历史。deviceID 为空查全部;since>0 只取 ts>=since;limit<=0 默认 100(上限 1000)。
func (*Store) ListEventsTenant ¶
func (s *Store) ListEventsTenant(tenantID int64, deviceID string, since int64, limit int) ([]EventRow, error)
ListEventsTenant 查询指定租户的事件历史(账号模式)。
func (*Store) ListPluginInstallationsTenant ¶
func (s *Store) ListPluginInstallationsTenant(tenantID int64) ([]PluginInstallationRow, error)
ListPluginInstallationsTenant 返回本租户全部安装物投影,按 (edge_id, plugin_id) 有序。
func (*Store) ListPluginInstancesAll ¶ added in v0.2.3
func (s *Store) ListPluginInstancesAll() ([]PluginInstanceRow, error)
ListPluginInstancesAll 返回全部租户的全部期望态实例(Server 侧 AppHost reconcile 用; 按 tenant/edge/instance 有序)。Edge 侧读面禁止使用本方法(Edge 必须走租户过滤版本)。
func (*Store) ListPluginInstancesTenant ¶
func (s *Store) ListPluginInstancesTenant(tenantID int64) ([]PluginInstanceRow, error)
ListPluginInstancesTenant 返回本租户全部期望态实例,按 (edge_id, instance_id) 有序。 恒带 tenant predicate;tenantID<=0 解析为 default 租户,绝不当作「不过滤」。
func (*Store) ListPluginObservationsTenant ¶
func (s *Store) ListPluginObservationsTenant(tenantID int64) ([]PluginObservationRow, error)
ListPluginObservationsTenant 返回本租户全部 observed 投影,按 (edge_id, instance_id) 有序。 恒带 tenant predicate;tenantID<=0 解析为 default 租户,绝不当作「不过滤」。
func (*Store) ListScheduledJobs ¶ added in v0.2.8
func (s *Store) ListScheduledJobs(tenantID int64, instanceID string) ([]ScheduledJobRow, error)
ListScheduledJobs 按实例列定时任务(D1 jobs 读面;含 cancelled,state 自述)。
func (*Store) ListScheduledJobsDue ¶ added in v0.2.8
func (s *Store) ListScheduledJobsDue(now int64) ([]ScheduledJobRow, error)
ListScheduledJobsDue 列出到期任务(state=active AND next_run_at<=now), 按计划时刻升序(错过最久的先被处理)。
func (*Store) ListTenantTokens ¶
ListTenantTokens 返回租户全部令牌元数据(无明文)。
func (*Store) ListUsersTenant ¶
ListUsersTenant 返回指定租户的全部用户(不含密码哈希之外的敏感信息;handler 只透出视图)。
func (*Store) PluginDesiredRevision ¶
PluginDesiredRevision 返回 (tenant, edge) 当前 desired revision;从未写过返回 0。
func (*Store) PruneCommands ¶
PruneCommands 删除 ts < before 的终态命令(保留期清理),返回删除行数。 仅清理已结算状态,避免误删仍在等待回执的命令行。
func (*Store) PruneEvents ¶
PruneEvents 删除 ts < before 的事件(保留期清理),返回删除行数。
func (*Store) PrunePluginObservations ¶
PrunePluginObservations 删除本租户 reported_at < before 的 observed 投影行,返回删除行数。 这是 §3.1「plugin observed projection 默认 30 天」的执行面,供 Server sweeper 按租户分批调用: 恒带 tenant predicate(清理 A 绝不读取/删除 B),且**只清投影**——desired 期望态与 audit 审计都不随 observed 清理(§5「删除期望态不删审计」、§3.1「desired 不随 observed 清理」)。 本方法是 §3 契约之外的补充(契约未列保留期执行面),Captain 可选择接线或忽略。
func (*Store) PruneSessions ¶
PruneSessions 删除过期会话,返回删除行数(保留期维护复用)。
func (*Store) RevokeTenantToken ¶
RevokeTenantToken 吊销租户内令牌(幂等语义由 handler 决定 404/204),返回是否命中。
func (*Store) SetDeviceDescriptor ¶ added in v0.2.20
SetDeviceDescriptor 保存设备最后已知 Descriptor JSON。调用方负责 schema 校验; 本方法只拒绝空值和超限数据,并确保目标设备存在。
func (*Store) SetPluginEdgeApplied ¶
func (s *Store) SetPluginEdgeApplied(tenantID int64, edgeID, bootID string, seq, appliedRevision uint64, at int64) error
SetPluginEdgeApplied 在 Edge ack=applied 后推进 applied_revision 并记 last_ack_at。 除 boot/sequence 规则外再加两条单调守卫(不满足即幂等忽略,不写任何列):
- applied_revision 不得回退(Server 侧记录只增,避免 UI/下发出现回归);
- applied_revision 不得超过本 (tenant,edge) 的 desired_revision(Edge 不能声称应用了 Server 从未下发过的 revision,control-plane-sync.md §2 不变量 2、3)。
func (*Store) SetPluginEdgeReport ¶
func (s *Store) SetPluginEdgeReport(tenantID int64, edgeID, bootID string, seq uint64, at int64) error
SetPluginEdgeReport 记录 Edge 一次 plugin_status 上报(boot 身份 + sequence + 时间), 不改 applied_revision。重复/倒序/旧 boot 迟到消息按契约幂等忽略(返回 nil,不写任何列)。
func (*Store) SetTenantPolicy ¶
func (s *Store) SetTenantPolicy(tenantID int64, p TenantPolicyRow) error
SetTenantPolicy 写(upsert)本租户策略行。0 字段存 NULL(继承默认)。 先用 tenantpolicy 的冻结校验规则验解析结果(单一校验来源,不与 store 各写一份范围), 非法值 → tenantpolicy.ErrInvalidPolicy 包装错误,且**不写入任何列**; DB CHECK 是第二道防线(手工 SQL 也绕不过)。row.TenantID 被忽略,归属恒取 tenantID 参数。
func (*Store) StatsTenant ¶
StatsTenant 返回指定租户的行数统计与最早事件时间(账号模式)。
func (*Store) TenantIDBySlug ¶
TenantIDBySlug 按租户 slug 读 id;不存在返回 sql.ErrNoRows。
func (*Store) TimeoutStaleCommandIDs ¶ added in v0.2.18
TimeoutStaleCommandIDs 与 TimeoutStaleCommands 同语义,但在同一个 IMMEDIATE 写事务内返回真正从 pending/sent 推进到 timeout 的命令 ID。 调用方据此向 Application Host 通知终态;已终态行不会重复返回。
func (*Store) TimeoutStaleCommands ¶
TimeoutStaleCommands 把超过 ttl 仍 pending/sent 的命令标记 timeout,返回受影响行。
func (*Store) TouchSession ¶
TouchSession 刷新会话最近活跃时间(节流调用,避免每请求一次写)。
func (*Store) TouchTenantToken ¶
TouchTenantToken 节流刷新 last_used_at(避免每请求一次写库)。
func (*Store) UpdateCommandStatus ¶
UpdateCommandStatus 更新命令状态与回执(default 兼容包装)。
func (*Store) UpdateCommandStatusScoped ¶
func (s *Store) UpdateCommandStatusScoped(id int64, deviceID string, tenantID int64, status, result string) (bool, error)
UpdateCommandStatusScoped 只允许更新同租户、同设备的命令行,返回是否命中(防止跨租户 ack)。
func (*Store) UpdatePluginInstance ¶
func (s *Store) UpdatePluginInstance(row PluginInstanceRow) (uint64, error)
UpdatePluginInstance 更新既有实例并原子推进 revision,返回新 revision。 不可变字段:tenant_id(结构性不可改)、created_at(不改写历史)、plugin_id(换插件属新实例, 传空表示保留,传不同值 → ErrPluginImmutableField)。不存在 → ErrPluginInstanceNotFound。 更新不占配额(没有新增实例),因此不做配额准入。
func (*Store) UpdateUser ¶
UpdateUser 修改用户字段并在同一事务内做「最后一个可用 admin」保护。 禁用或重置密码会撤销该用户全部会话。目标用户不存在或跨租户返回 sql.ErrNoRows。
func (*Store) UpsertAppDomainRecord ¶ added in v0.2.3
func (s *Store) UpsertAppDomainRecord(tenantID int64, instanceID, recordType, recordID, dataJSON, version string, updatedAt int64) error
UpsertAppDomainRecord 写入/覆盖一条应用领域记录(create_domain_record 效果落点)。 tenantID 由调用方(Server,来自实例行)传入;记录键为 (tenant, instance, record_type, record_id),同一键重复上报即覆盖—— 与 Application Protocol 的 UpsertDomainRecord 语义一致。
func (*Store) UpsertDevice ¶
UpsertDevice 注册/刷新设备元信息(default 兼容包装,无账号开发模式沿用)。
func (*Store) UpsertDeviceTenant ¶
UpsertDeviceTenant 注册/刷新设备元信息并绑定租户(账号模式使用)。
func (*Store) UpsertDevicesTenant ¶
func (s *Store) UpsertDevicesTenant(edgeID string, metas []DeviceMetaInput, tenantID int64) error
UpsertDevicesTenant 在单个 IMMEDIATE 写事务里绑定 edge 及其全部设备到租户。 任一设备或 edge 已绑定其他租户时整体回滚并返回对应 sentinel error(fail-closed, 不留半绑定行),避免跨租户同名注册污染。
func (*Store) UpsertPluginInstallations ¶
func (s *Store) UpsertPluginInstallations(tenantID int64, edgeID string, rows []api.PluginInstallationStatusData) error
UpsertPluginInstallations 写入某 (tenant, edge) 的已安装插件全量快照(语义同上)。 时间戳取 now()(契约未传 reportedAt);per-edge 的 last_report_at 由 SetPluginEdgeReport 记录。
func (*Store) UpsertPluginObservations ¶
func (s *Store) UpsertPluginObservations(tenantID int64, edgeID string, rows []api.PluginObservedInstanceData, reportedAt int64) error
UpsertPluginObservations 写入某 (tenant, edge) 的 observed 实例全量快照。 reportedAt<=0 时用 now()。rows 为该 edge 的完整快照:nil/空表示该 edge 当前无实例运行, 会清空该 (tenant,edge) 的投影(不影响其他 edge / 其他租户)。 edge 已绑定其他租户 → ErrEdgeTenantMismatch 且整批不写入(暗卷:伪造上报不污染任一租户投影)。
func (*Store) UpsertScheduledJob ¶ added in v0.2.8
func (s *Store) UpsertScheduledJob(row ScheduledJobRow) (ScheduledJobRow, error)
UpsertScheduledJob 写入/更新一条声明式定时任务(schedule_job 效果落点)。 同 (tenant, instance, schedule_id) 重声明 = 更新(cron/payload/策略/next_run_at 重算);state 一律回到 active(cancel 后重声明 = 重新生效,与 UpsertDomainRecord 的「最终态收敛」同一哲学)。revision 递增。
func (*Store) UserBySession ¶
UserBySession 按会话 ID 读有效用户;过期/不存在/用户被禁用一律返回 sql.ErrNoRows。
type TenantPolicyRow ¶
type TenantPolicyRow struct {
TenantID int64
// 保留期(天)
RetentionEventsDays int
RetentionCommandsDays int
RetentionAuditDays int
RetentionRevokedTokensDays int
RetentionPluginObservedDays int
// 配额(硬上限)
QuotaDevices int
QuotaEdges int
QuotaBrowserWS int
QuotaTokens int
QuotaUsers int
QuotaEventsPerMinute int
QuotaPluginInstances int
UpdatedAt int64
}
TenantPolicyRow 是 tenant_policies 一行。所有天数/上限字段 0 表示继承默认(存 NULL)。 字段集与 tenantpolicy.RetentionDays / tenantpolicy.Quotas 一一对应。
func (TenantPolicyRow) Resolve ¶
func (r TenantPolicyRow) Resolve() tenantpolicy.Policy
Resolve 把行解析成 tenantpolicy.Policy:0/NULL 字段填入 tenantpolicy.Defaults()。 解析结果恒为可直接执行的正数上限与天数(永不返回 0,因此 0 不可能被当成「无限」)。
type TokenRow ¶
type TokenRow struct {
ID int64
TenantID int64
Name string
Prefix string
Hash string
Scopes string // JSON 数组
ExpiresAt sql.NullInt64
LastUsedAt sql.NullInt64
RevokedAt sql.NullInt64
CreatedAt int64
}
TokenRow 是 tenant_tokens 表一行。明文只在创建响应返回,本结构不含明文。