watchdaemon

package
v0.114.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Overview

Package watchdaemon hosts DataTug's independently composable Watch roles.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidateEndpoint

func ValidateEndpoint(endpoint string) error

ValidateEndpoint permits TLS, or explicit loopback HTTP for local operation. Credentials, fragments and query strings never belong in manifest endpoints.

Types

type Authenticator

type Authenticator struct {
	// contains filtered or unexported fields
}

func NewAuthenticator

func NewAuthenticator(credentials []Credential) (*Authenticator, error)

func (*Authenticator) Authenticate

func (a *Authenticator) Authenticate(r *http.Request, kind string) (Credential, bool)

type Client

type Client struct {
	Endpoint, Token string
	HTTP            *http.Client
}

func (Client) Claim

func (c Client) Claim(ctx context.Context) (*watch.Claim, error)

func (Client) Complete

func (c Client) Complete(ctx context.Context, result watch.Completion) error

func (Client) Heartbeat

func (c Client) Heartbeat(ctx context.Context, id string, fence int64) error

func (Client) Register

func (c Client) Register(ctx context.Context) error

type Config

type Config struct {
	Namespace      string            `json:"namespace"`
	Listen         string            `json:"listen,omitempty"`
	TLSCertFile    string            `json:"tlsCertFile,omitempty"`
	TLSKeyFile     string            `json:"tlsKeyFile,omitempty"`
	Credentials    []Credential      `json:"credentials"`
	AllowedOrigins []string          `json:"allowedOrigins,omitempty"`
	PublicUIURL    string            `json:"publicUIURL,omitempty"`
	ProjectUIURLs  map[string]string `json:"projectUIURLs,omitempty"`
	Limits         Limits            `json:"limits,omitempty"`
	Storage        struct {
		DALGOConnectionEnv string `json:"dalgoConnectionEnv"`
	} `json:"storage"`
	Runner struct {
		TokenEnv            string             `json:"tokenEnv"`
		CoordinatorEndpoint string             `json:"coordinatorEndpoint"`
		ProjectDir          string             `json:"projectDir"`
		Environment         string             `json:"environment"`
		Principal           string             `json:"principal"`
		EvidenceDir         string             `json:"evidenceDir"`
		AllowOpaqueSQL      bool               `json:"allowOpaqueSQL,omitempty"`
		Telegram            *TelegramBotConfig `json:"telegram,omitempty"`
	} `json:"runner"`
	Notifications struct {
		EmailSink string      `json:"emailSink,omitempty"`
		SMTP      *SMTPConfig `json:"smtp,omitempty"`
		SMSSink   string      `json:"smsSink,omitempty"`
		Twilio    bool        `json:"twilio,omitempty"`
	} `json:"notifications"`
}

Config belongs to the daemon deployment. Projects carry only coordination endpoint and namespace; credentials and storage are never read from a project.

func LoadConfig

func LoadConfig(path string) (Config, error)

type CoordinatorStore

type CoordinatorStore interface {
	Health(context.Context) error
	ListDefinitions(context.Context, watch.Actor) ([]watch.Definition, error)
	GetDefinition(context.Context, watch.Actor, string) (watch.Definition, error)
	PutDefinition(context.Context, watch.Actor, watch.Definition, string, int64) (watch.Definition, error)
	DeleteDefinition(context.Context, watch.Actor, string, string, int64) error
	SetLifecycle(context.Context, watch.Actor, string, string, string, int64) (watch.Definition, error)
	ResetBaseline(context.Context, watch.Actor, string, string, int64) (watch.Definition, error)
	Subscribe(context.Context, watch.Actor, watch.Subscription) error
	GetSubscription(context.Context, watch.Actor, string) (watch.Subscription, error)
	ListRuns(context.Context, watch.Actor, string) ([]watch.Run, error)
	ListDeliveries(context.Context, watch.Actor, string) ([]watch.Delivery, error)
	RetryNotification(context.Context, watch.Actor, string) error
	RegisterRunner(context.Context, watch.RunnerIdentity) error
	ClaimDue(context.Context, watch.RunnerIdentity) (*watch.Claim, error)
	Heartbeat(context.Context, watch.RunnerIdentity, string, int64) error
	FinishRun(context.Context, watch.RunnerIdentity, watch.Completion) (watch.Run, error)
	Inbox(context.Context, watch.Actor) ([]watch.Notification, error)
	MarkRead(context.Context, watch.Actor, string) error
	Status(context.Context, watch.Actor) (watch.Status, error)
	Reconcile(context.Context) error
	ClaimNotifications(context.Context) (*watch.Delivery, error)
	FinishNotification(context.Context, string, int64, string) error
}

CoordinatorStore owns all transactional state; transports never implement scheduling, state transitions, visibility or lease decisions themselves.

type Credential

type Credential struct {
	TelegramBotID string   `json:"telegramBotId,omitempty"`
	TokenEnv      string   `json:"tokenEnv"`
	Kind          string   `json:"kind"` // user or runner
	ID            string   `json:"id"`
	AccountID     string   `json:"accountId,omitempty"`
	Namespace     string   `json:"namespace"`
	Project       string   `json:"project"`
	Environment   string   `json:"environment"`
	SharedEditor  bool     `json:"sharedEditor,omitempty"`
	Capabilities  []string `json:"capabilities,omitempty"`
	Email         string   `json:"email,omitempty"`
	Tier          string   `json:"tier,omitempty"`
	Phone         string   `json:"phone,omitempty"`
}

Credential is deployment-owned authority. Tokens are resolved from the environment at startup, never accepted from a project or a request body.

type EmailMessage

type EmailMessage struct {
	ID      string `json:"id"`
	To      string `json:"to"`
	Subject string `json:"subject"`
	Body    string `json:"body"`
}

EmailMessage contains only notification metadata, never query rows or inputs.

type EmailSender

type EmailSender interface {
	Send(context.Context, EmailMessage) error
}

type Executor

type Executor interface {
	Execute(context.Context, watch.Claim) (watch.Completion, error)
}

type ExecutorFunc

type ExecutorFunc func(context.Context, watch.Claim) (watch.Completion, error)

func (ExecutorFunc) Execute

type FileEmailSink

type FileEmailSink struct {
	Path string
	// contains filtered or unexported fields
}

FileEmailSink is a persistent development mailbox. Stable message IDs make retries idempotent, including after a daemon restart. Use one coordinator.

func (*FileEmailSink) Send

func (s *FileEmailSink) Send(ctx context.Context, message EmailMessage) error

type FileSMSSink

type FileSMSSink struct{ Sink *FileEmailSink }

FileSMSSink shares the crash-safe, ID-deduplicated development mailbox kernel. Its To field ends in @sms.test and preserves the verified E.164 recipient.

func (FileSMSSink) Send

func (s FileSMSSink) Send(ctx context.Context, m SMSMessage) error

type Limits

type Limits struct {
	EmailPerDay        int `json:"emailPerDay,omitempty"`
	EmailPerMinute     int `json:"emailPerMinute,omitempty"`
	SMSPerDay          int `json:"smsPerDay,omitempty"`
	SMSPerMinute       int `json:"smsPerMinute,omitempty"`
	TelegramPerDay     int `json:"telegramPerDay,omitempty"`
	TelegramPerMinute  int `json:"telegramPerMinute,omitempty"`
	WatchesPerUser     int `json:"watchesPerUser,omitempty"`
	MinIntervalSeconds int `json:"minIntervalSeconds,omitempty"`
}

func (Limits) Resolve

func (l Limits) Resolve() (Limits, error)

type Runner

type Runner struct {
	Telegram *TelegramBotConfig

	Client                      Client
	Executor                    Executor
	PollInterval, RenewInterval time.Duration
	RegistrationInterval        time.Duration
	// contains filtered or unexported fields
}

func (Runner) Run

func (r Runner) Run(ctx context.Context) error

Run uses the same HTTP registration/claim/renew/complete protocol locally and remotely. A runner needs no inbound listener or source credentials on server.

type SMSMessage

type SMSMessage struct{ ID, To, Body string }

type SMSSender

type SMSSender interface {
	Send(context.Context, SMSMessage) error
}

type SMTPConfig

type SMTPConfig struct {
	Address     string `json:"address"`
	From        string `json:"from"`
	UsernameEnv string `json:"usernameEnv,omitempty"`
	PasswordEnv string `json:"passwordEnv,omitempty"`
	// AllowLoopbackPlaintext is only for a local development SMTP receiver.
	AllowLoopbackPlaintext bool `json:"allowLoopbackPlaintext,omitempty"`
}

type SMTPSender

type SMTPSender struct{ Config SMTPConfig }

func (SMTPSender) Send

func (s SMTPSender) Send(ctx context.Context, m EmailMessage) error

type Server

type Server struct {
	Store          CoordinatorStore
	Auth           *Authenticator
	AllowedOrigins []string
	Email          EmailSender
	SMS            SMSSender
	PublicUIURL    string
	ProjectUIURLs  map[string]string
	Limits         Limits
}

func (*Server) RunCoordinator

func (s *Server) RunCoordinator(ctx context.Context, interval time.Duration) error

RunCoordinator reconciles due schedules separately from assignment and drains the durable delivery outbox. A failed delivery never changes evaluation truth.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

type TelegramBotConfig

type TelegramBotConfig struct {
	BotID     string `json:"botID"`
	SecretEnv string `json:"secretEnv,omitempty"`
	TokenEnv  string `json:"tokenEnv,omitempty"`
}

TelegramBotConfig is runner-only deployment configuration. Neither token nor secret is sent to the coordinator or saved in a project.

type TwilioSMSSender

type TwilioSMSSender struct {
	Credentials twiliosms.Credentials
	Transport   http.RoundTripper
}

TwilioSMSSender reuses the ecosystem's shared SMS provider kernel. Credentials remain deployment-owned. Provider errors are deliberately reduced to a code.

func (TwilioSMSSender) Send

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL