chore: establish local platform baseline
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package media
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"data-terminal-cloud/internal/audit"
|
||||
"data-terminal-cloud/internal/database"
|
||||
"data-terminal-cloud/internal/deviceauth"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
// AcknowledgeLocalDelete records only deletion of the device-side encrypted copy.
|
||||
// The verified cloud object and its media_segment lifecycle remain unchanged.
|
||||
func (s *Service) AcknowledgeLocalDelete(ctx context.Context, identity deviceauth.Identity, segmentPublicID, status, errorCode, requestID string) (Segment, error) {
|
||||
status = strings.ToUpper(strings.TrimSpace(status))
|
||||
errorCode = strings.ToUpper(strings.TrimSpace(errorCode))
|
||||
if status != "DELETED" && status != "FAILED" {
|
||||
return Segment{}, ErrInvalidDeclaration
|
||||
}
|
||||
if status == "DELETED" && errorCode != "" {
|
||||
return Segment{}, ErrInvalidDeclaration
|
||||
}
|
||||
if status == "FAILED" && (errorCode == "" || len(errorCode) > 80) {
|
||||
return Segment{}, ErrInvalidDeclaration
|
||||
}
|
||||
|
||||
var result Segment
|
||||
err := database.Transact(ctx, s.pool, func(tx pgx.Tx) error {
|
||||
var cloudStatus, storedStatus string
|
||||
var deleteAfter *time.Time
|
||||
err := tx.QueryRow(ctx, `
|
||||
SELECT status,COALESCE(local_delete_status,''),local_delete_after
|
||||
FROM media_segment
|
||||
WHERE public_id=$1::uuid AND tenant_id=$2::uuid AND device_id=$3::uuid
|
||||
FOR UPDATE`, segmentPublicID, identity.TenantID, identity.ID,
|
||||
).Scan(&cloudStatus, &storedStatus, &deleteAfter)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cloudStatus != "VERIFIED" || deleteAfter == nil {
|
||||
return ErrConflict
|
||||
}
|
||||
if storedStatus == "DELETED" {
|
||||
return scanDeviceSegment(ctx, tx, identity, segmentPublicID, &result)
|
||||
}
|
||||
if status == "DELETED" && time.Now().UTC().Before(*deleteAfter) {
|
||||
return ErrLocalDeleteTooEarly
|
||||
}
|
||||
if _, err := tx.Exec(ctx, `
|
||||
UPDATE media_segment
|
||||
SET local_delete_status=$4,local_delete_reported_at=now(),local_delete_error_code=NULLIF($5,''),updated_at=now()
|
||||
WHERE public_id=$1::uuid AND tenant_id=$2::uuid AND device_id=$3::uuid`,
|
||||
segmentPublicID, identity.TenantID, identity.ID, status, errorCode,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
auditResult := "success"
|
||||
if status == "FAILED" {
|
||||
auditResult = "failure"
|
||||
}
|
||||
if err := s.audit.Record(ctx, tx, audit.Event{
|
||||
TenantID: &identity.TenantID, ActorType: "device", ActorPublicID: &identity.PublicID,
|
||||
Action: "media.local_delete.ack", ResourceType: "media_segment", ResourceID: &segmentPublicID,
|
||||
RequestID: requestID, Result: auditResult, Detail: map[string]any{"status": status, "error_code": errorCode},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return scanDeviceSegment(ctx, tx, identity, segmentPublicID, &result)
|
||||
})
|
||||
return result, err
|
||||
}
|
||||
|
||||
func scanDeviceSegment(ctx context.Context, tx pgx.Tx, identity deviceauth.Identity, segmentPublicID string, result *Segment) error {
|
||||
return tx.QueryRow(ctx, `
|
||||
SELECT public_id::text,track,sequence_no,codec,content_type,duration_ms,expected_size,expected_digest,status,
|
||||
COALESCE(last_error_code,''),verified_at,local_delete_after,COALESCE(local_delete_status,''),
|
||||
local_delete_reported_at,COALESCE(local_delete_error_code,'')
|
||||
FROM media_segment WHERE public_id=$1::uuid AND tenant_id=$2::uuid AND device_id=$3::uuid`,
|
||||
segmentPublicID, identity.TenantID, identity.ID,
|
||||
).Scan(&result.ID, &result.Track, &result.SequenceNo, &result.Codec, &result.ContentType, &result.DurationMS,
|
||||
&result.ExpectedSize, &result.ExpectedDigest, &result.Status, &result.LastErrorCode, &result.VerifiedAt,
|
||||
&result.LocalDeleteAfter, &result.LocalDeleteStatus, &result.LocalDeleteReportedAt, &result.LocalDeleteErrorCode)
|
||||
}
|
||||
Reference in New Issue
Block a user