feat(sense): implement Control API v1 [T-011]
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"yovision/sense/internal/device"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrETagMismatch = errors.New("device ETag mismatch")
|
||||
ErrIdempotencyConflict = errors.New("idempotency key body conflict")
|
||||
ErrDuplicateSerialNumber = errors.New("duplicate device serial number")
|
||||
)
|
||||
|
||||
type ControlProjectionVersions struct {
|
||||
QuotaSourceVersion *int64 `json:"quota_source_version"`
|
||||
AreaPolicySourceVersion *int64 `json:"area_policy_source_version"`
|
||||
SyncedAt *time.Time `json:"synced_at"`
|
||||
}
|
||||
|
||||
// ControlDevice is deliberately safe to serialize. It contains configured
|
||||
// booleans, never endpoint, credential or profile-token values.
|
||||
type ControlDevice struct {
|
||||
ID string `json:"id"`
|
||||
TenantID string `json:"tenant_id"`
|
||||
SiteID string `json:"site_id"`
|
||||
SerialNumber string `json:"serial_number"`
|
||||
Name string `json:"name"`
|
||||
Modality device.Modality `json:"modality"`
|
||||
Capabilities []device.Capability `json:"capabilities"`
|
||||
AreaID string `json:"area_id"`
|
||||
DesiredState device.DesiredState `json:"desired_state"`
|
||||
ActualState device.ActualState `json:"actual_state"`
|
||||
AdapterStatus string `json:"adapter_status"`
|
||||
EndpointConfigured bool `json:"endpoint_configured"`
|
||||
CredentialConfigured bool `json:"credential_configured"`
|
||||
Generation int64 `json:"generation"`
|
||||
ObservedGeneration int64 `json:"observed_generation"`
|
||||
Converged bool `json:"converged"`
|
||||
FailureCount int `json:"failure_count"`
|
||||
NextAttemptAt *time.Time `json:"next_attempt_at,omitempty"`
|
||||
LastErrorCode *string `json:"last_error_code,omitempty"`
|
||||
ProjectionVersions ControlProjectionVersions `json:"projection_versions"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
ResourceVersion int64 `json:"-"`
|
||||
}
|
||||
|
||||
type ControlSiteQuota struct {
|
||||
Status string
|
||||
UsedVideoChannels int
|
||||
MaxVideoChannels *int
|
||||
AvailableVideoChannels *int
|
||||
OverLimit bool
|
||||
SourceVersion *int64
|
||||
SyncedAt *time.Time
|
||||
}
|
||||
|
||||
type ControlListFilter struct {
|
||||
Limit int
|
||||
AfterCreated *time.Time
|
||||
AfterDeviceID string
|
||||
Modality *device.Modality
|
||||
Capability *device.Capability
|
||||
DesiredState *device.DesiredState
|
||||
ActualState *device.ActualState
|
||||
}
|
||||
|
||||
type ControlDevicePage struct {
|
||||
Items []ControlDevice
|
||||
HasMore bool
|
||||
Quota ControlSiteQuota
|
||||
}
|
||||
|
||||
type IdempotencyScope struct {
|
||||
PrincipalID string
|
||||
TenantID string
|
||||
SiteID string
|
||||
Operation string
|
||||
Key string
|
||||
RequestHash [sha256.Size]byte
|
||||
TraceID string
|
||||
}
|
||||
|
||||
type ControlCreateRequest struct {
|
||||
Scope IdempotencyScope
|
||||
Device device.Device
|
||||
}
|
||||
|
||||
type ControlCreateResult struct {
|
||||
Device ControlDevice
|
||||
AcceptedAt time.Time
|
||||
TraceID string
|
||||
ETag string
|
||||
Location string
|
||||
Replay bool
|
||||
}
|
||||
|
||||
type ControlPatch struct {
|
||||
Name *string
|
||||
AreaID *string
|
||||
EndpointRef *string
|
||||
CredentialRef *string
|
||||
ProfileToken *string
|
||||
}
|
||||
|
||||
type ControlMutationResult struct {
|
||||
Device ControlDevice
|
||||
AcceptedAt time.Time
|
||||
TraceID string
|
||||
ETag string
|
||||
}
|
||||
|
||||
type ControlBatchItem struct {
|
||||
DeviceID string
|
||||
ETag string
|
||||
DesiredState device.DesiredState
|
||||
}
|
||||
|
||||
type ControlBatchRequest struct {
|
||||
Scope IdempotencyScope
|
||||
Reason string
|
||||
Items []ControlBatchItem
|
||||
}
|
||||
|
||||
type ControlBatchItemResult struct {
|
||||
DeviceID string `json:"device_id"`
|
||||
Status string `json:"status"`
|
||||
ErrorCode *string `json:"error_code"`
|
||||
Message *string `json:"message"`
|
||||
Generation *int64 `json:"generation"`
|
||||
}
|
||||
|
||||
type ControlBatchOperation struct {
|
||||
ID string `json:"id"`
|
||||
TenantID string `json:"-"`
|
||||
SiteID string `json:"-"`
|
||||
Status string `json:"status"`
|
||||
SubmittedAt time.Time `json:"submitted_at"`
|
||||
CompletedAt *time.Time `json:"completed_at"`
|
||||
Results []ControlBatchItemResult `json:"results"`
|
||||
TraceID string `json:"trace_id"`
|
||||
Replay bool `json:"-"`
|
||||
}
|
||||
|
||||
type ControlRepository interface {
|
||||
ListControlDevices(context.Context, string, string, ControlListFilter) (ControlDevicePage, error)
|
||||
CreateControlDevice(context.Context, ControlCreateRequest) (ControlCreateResult, error)
|
||||
GetControlDevice(context.Context, string, string, string) (ControlDevice, error)
|
||||
PatchControlDevice(context.Context, string, string, string, string, ControlPatch) (ControlMutationResult, error)
|
||||
SetControlDesiredState(context.Context, string, string, string, string, device.DesiredState) (ControlMutationResult, error)
|
||||
BatchSetControlDesiredState(context.Context, ControlBatchRequest) (ControlBatchOperation, error)
|
||||
GetControlOperation(context.Context, string, string) (ControlBatchOperation, error)
|
||||
}
|
||||
|
||||
func DeviceETag(deviceID string, resourceVersion int64) string {
|
||||
digest := sha256.Sum256([]byte(deviceID + "\x00" + strconv.FormatInt(resourceVersion, 10)))
|
||||
return `"` + base64.RawURLEncoding.EncodeToString(digest[:18]) + `"`
|
||||
}
|
||||
Reference in New Issue
Block a user