cmd/taisce/ingest.go
cmd/taisce · 378 lines · 17 declarations · source
This file carries the package documentation, rendered on the package page.
Declarations
const envAPI, envToken
const (
envAPI = "TAISCE_API"
envToken = "TAISCE_TOKEN"
)
type manifest
type manifest struct {
Version int `json:"version"`
Document string `json:"document"`
Digest string `json:"digest"`
Bytes int `json:"bytes"`
Role string `json:"role"`
DataSubjectID string `json:"data_subject_id,omitempty"`
OccurredAt *time.Time `json:"occurred_at,omitempty"`
SegmentBytes int `json:"segment_bytes"`
Segments []segmentReceipt `json:"segments"`
// Refused says why the document stopped, if it did; a manifest with it set lists the segments
// that were received before the refusal, and a rerun sends them all again as replays.
Refused string `json:"refused,omitempty"`
}
manifest is what the command writes for one document. Version names the shape so a reader of a manifest written by an older binary knows what it is reading.
type segmentReceipt
type segmentReceipt struct {
Ordinal int `json:"ordinal"`
ByteStart int `json:"byte_start"`
ByteEnd int `json:"byte_end"`
IdempotencyKey string `json:"idempotency_key"`
ObservationID string `json:"observation_id"`
LogOffset int64 `json:"log_offset"`
}
type ingestOptions
type ingestOptions struct {
api string
role string
dataSubjectID string
occurredAt string
segmentBytes int
maxFileBytes int
manifestDir string
capacityWait time.Duration
wait time.Duration
}
ingestOptions are the flags, parsed once and passed rather than read from globals.
func ingestCommand
func ingestCommand(ctx context.Context, args []string, out io.Writer) error
func ingestOne
func ingestOne(ctx context.Context, client *apiClient, path string, o ingestOptions, defaultTime *time.Time) (manifest, error)
ingestOne reads, cuts and sends one document, and returns the manifest so far with the error that stopped it, if one did. A refusal by the package leaves an empty segment list; a refusal by the API leaves the receipts received before it.
func writeManifest
func writeManifest(dir string, m manifest) error
type observeBody
type observeBody struct {
IdempotencyKey string `json:"idempotency_key"`
DataSubjectID string `json:"data_subject_id,omitempty"`
OccurredAt *time.Time `json:"occurred_at,omitempty"`
Messages []observeMessage `json:"messages"`
}
The wire shapes this command uses, written here rather than imported from the API package: a client that shares the server's types cannot notice the server changing them.
type observeMessage
type observeMessage struct {
GroupOrdinal int `json:"group_ordinal"`
Role string `json:"role"`
Content string `json:"content"`
}
type observeReceipt
type observeReceipt struct {
ID string `json:"id"`
Scope string `json:"scope"`
LogOffset int64 `json:"log_offset"`
}
type apiError
type apiError struct {
Code string `json:"code"`
Message string `json:"message"`
}
type apiClient
type apiClient struct {
base string
token string
http *http.Client
}
method apiClient.observe
func (c *apiClient) observe(ctx context.Context, body observeBody, capacityWait time.Duration) (observeReceipt, error)
observe sends one segment. A full backlog (429) is waited out with bounded backoff up to capacityWait, because a bulk import is exactly the caller that should retry with the same key; a conflict (409) is a document that changed under a key it had already used, which cannot happen with keys derived from the digest and is refused rather than papered over.
method apiClient.awaitFormation
func (c *apiClient) awaitFormation(ctx context.Context, offset int64, wait time.Duration) (*int64, int, error)
awaitFormation polls freshness until the formed watermark reaches the offset or the wait ends, and returns the watermark and the parked count as they stood.
method apiClient.post
func (c *apiClient) post(ctx context.Context, path string, body any) (int, []byte, error)
method apiClient.get
func (c *apiClient) get(ctx context.Context, path string) (int, []byte, error)
method apiClient.do
func (c *apiClient) do(req *http.Request) (int, []byte, error)