165 lines
5.5 KiB
Go
165 lines
5.5 KiB
Go
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]) + `"`
|
|
}
|