router

package
v0.0.1-alpha.13 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2026 License: MIT Imports: 81 Imported by: 0

Documentation

Overview

Package router wires together all service handlers into a single HTTP server. It owns the middleware chain and the service dispatch logic.

Index

Constants

This section is empty.

Variables

View Source
var ServiceGoalTiers = map[string]EmulationTier{

	"dynamodb":       TierFull,
	"secretsmanager": TierFull,

	"iam":           TierPartial,
	"eventbridge":   TierPartial,
	"stepfunctions": TierPartial,
}

ServiceGoalTiers maps each service to its aspirational emulation tier — the tier we intend to reach eventually. When ServiceTiers[svc] != ServiceGoalTiers[svc] the service is considered "work in progress" and the UI shows a WIP indicator.

Services not listed here have an implicit goal of their current tier (i.e. no further improvement is planned or the service is already at its goal).

View Source
var ServiceTiers = map[string]EmulationTier{

	"s3":     TierFull,
	"sqs":    TierFull,
	"sns":    TierFull,
	"lambda": TierFull,

	"dynamodb":        TierPartial,
	"dynamodbstreams": TierPartial,
	"ses":             TierPartial,
	"secretsmanager":  TierPartial,
	"kinesis":         TierPartial,
	"pipes":           TierPartial,
	"logs":            TierPartial,
	"sts":             TierPartial,
	"kms":             TierPartial,
	"ssm":             TierPartial,
	"ec2":             TierPartial,
	"ecs":             TierPartial,
	"eks":             TierPartial,
	"rds":             TierPartial,
	"cloudformation":  TierPartial,
	"apigateway":      TierPartial,
	"cognito":         TierPartial,

	"iam":           TierInert,
	"eventbridge":   TierInert,
	"stepfunctions": TierInert,
	"appsync":       TierInert,
	"cloudfront":    TierInert,

	"waf":    TierStub,
	"shield": TierStub,

	"cloudwatch":  TierInert,
	"acm":         TierInert,
	"opensearch":  TierInert,
	"appconfig":   TierInert,
	"glue":        TierInert,
	"firehose":    TierInert,
	"athena":      TierInert,
	"bedrock":     TierStub,
	"appregistry": TierInert,
	"elasticache": TierPartial,
	"msk":         TierPartial,
	"route53":     TierInert,
	"elbv2":       TierInert,
	"autoscaling": TierInert,
	"cloudtrail":  TierInert,
	"backup":      TierInert,
	"transfer":    TierInert,
}

ServiceTiers maps the canonical service name (as returned by Service.Name()) to its current emulation tier. Update this whenever a service graduates from stub → partial → full.

Functions

func New

func New(cfg *config.Config, store state.Store, logger *zap.Logger, clk clock.Clock, hookRunner ...*inithooks.Runner) (handler http.Handler, preShutdown func(), cleanup func(context.Context), waitReady func())

New builds and returns the root HTTP handler for the emulator, plus a cleanup function that should be called during graceful shutdown with the remaining shutdown context. It stops background service resources (e.g. the Lambda Runtime API server) and closes any other open handles (e.g. the SMTP listener).

The returned preShutdown function must be called BEFORE http.Server.Shutdown to unblock long-lived handlers (e.g. the SSE /_events endpoint).

func ProcessStartTime

func ProcessStartTime() time.Time

ProcessStartTime returns the OS process start time that anchors all phase measurements. Exported so cmd/overcast can anchor its phase timer to the same reference point as the router profiler, producing honest totals.

func RecordExternalPhase

func RecordExternalPhase(name string, start, end time.Time)

RecordExternalPhase appends a startup phase from outside the router package (e.g. cmd/overcast config load, store init). These are merged into the sealed timeline when router.New completes. Always records regardless of OVERCAST_PROFILE_STARTUP.

Types

type ContainerReconciler

type ContainerReconciler interface {
	// ReconcileContainers is called once after Docker becomes available.
	// containers lists every managed container for this service, running or stopped.
	ReconcileContainers(ctx context.Context, containers []docker.ContainerSummary)
}

ContainerReconciler is optionally implemented by services that manage Docker containers. When Docker becomes available at startup, the router calls ReconcileContainers with the current state of all managed containers for that service. Services should use this to sync their stored state (e.g. mark instances as "stopped" if their container exited while overcast was down).

ReconcileContainers must be idempotent — it will only be called once per Docker availability event, but it must produce correct results regardless of the order or timing of the call relative to CreateDBInstance etc.

type EmulationTier

type EmulationTier = string

EmulationTier describes how completely a service is emulated.

  • "full" — P1+P2 operations implemented; real SDK clients can use it.
  • "partial" — P1 operations implemented; basic workflows work.
  • "inert" — Full CRUD works, resources exist, but no side-effects or enforcement.
  • "stub" — Registered; all endpoints return 501 Not Implemented.
  • "unsupported" — Not registered in Overcast; no backend handler exists.
const (
	TierFull        EmulationTier = "full"
	TierPartial     EmulationTier = "partial"
	TierInert       EmulationTier = "inert"
	TierStub        EmulationTier = "stub"
	TierUnsupported EmulationTier = "unsupported"
)

type NetworkReconciler

type NetworkReconciler interface {
	// ReconcileNetworks is called once after Docker becomes available.
	// networks lists every managed network for this service.
	ReconcileNetworks(ctx context.Context, networks []docker.NetworkSummary)
}

NetworkReconciler is optionally implemented by services that manage Docker networks. When Docker becomes available at startup, the router calls ReconcileNetworks with the current state of all managed networks for that service. Services should use this to sync their stored state (e.g. recreate missing VPC networks, update Docker network IDs in the store).

ReconcileNetworks must be idempotent.

type PathPrefixService

type PathPrefixService interface {
	// PathPrefixes returns the URL path prefixes this service owns.
	PathPrefixes() []string
}

PathPrefixService is optionally implemented by services that own specific URL path prefixes distinct from S3's /{bucket}/* wildcard. When a service is disabled, the router registers a 503 ServiceDisabled catch-all handler at each declared prefix so callers receive a clear error instead of a stray 404 or a spurious S3 response. The format (JSON or XML) is determined by the Content-Type of the incoming request at dispatch time.

Prefix examples: "/2015-03-31" for Lambda, "/clusters" for EKS. Each prefix must start with "/" and must NOT end with "/".

type ProtocolService

type ProtocolService interface {
	Service

	// Operations returns the typed operations this service implements.
	// Operation names are AWS operation names ("SendMessage", "GetItem").
	Operations() []op.Operation

	// SupportedProtocols returns the wire codecs this service accepts.
	// Used by the dispatcher to return 415 if a request arrives in a codec
	// the service doesn't speak.
	SupportedProtocols() []codec.Codec
}

ProtocolService is optionally implemented by services that opt into the Smithy-aligned typed dispatcher (see docs/plans/smithy.md §4.4). The service supplies a typed operation registry and the set of wire protocols it accepts; the protocol-detection middleware (gated by OVERCAST_PROTOCOL_DISPATCH) puts the resolved codec and operation name in the request context, and the service's Dispatch consults that context to route to the typed operation.

Services that implement only Service (not this interface) keep working exactly as today — the middleware is a passthrough for them.

type QueryActionOwner

type QueryActionOwner interface {
	OwnsAction(action string) bool
}

QueryActionOwner is an optional interface for QueryDispatcher services that want to declare which Action values they handle. The router uses OwnsAction in the SECOND pass, after all QueryVersionOwner dispatchers have declined. Dispatchers that implement neither interface are tried as a final fallback.

type QueryDispatcher

type QueryDispatcher interface {
	DispatchQuery(w http.ResponseWriter, r *http.Request)
}

QueryDispatcher is implemented by services that use the AWS Query protocol: form-encoded POST body with an Action field, XML responses. SNS uses this protocol. The router calls r.ParseForm() before invoking DispatchQuery so handlers can read fields with r.FormValue().

type QueryVersionOwner

type QueryVersionOwner interface {
	OwnsVersion(version string) bool
}

QueryVersionOwner is an optional interface for QueryDispatcher services that identify themselves by the AWS API Version parameter (e.g. "2010-05-15") rather than by individual action names. The router checks OwnsVersion in the FIRST pass, before QueryActionOwner, because the version string is a stricter discriminator — it prevents action-name collisions between services (e.g. both SES and CloudFormation implement "GetTemplate").

type Readier

type Readier interface {
	WaitReady()
}

Readier is optionally implemented by services that perform background initialisation (e.g. Docker probing). WaitReady blocks until the service is fully ready to handle requests. The router collects all Readier services and returns a combined wait function for use in tests.

type Service

type Service interface {
	// Name returns the lowercase service name, e.g. "s3", "sqs".
	// Used to check against cfg.Services to decide whether to enable it.
	Name() string

	// RegisterRoutes mounts the service's HTTP handlers onto the given router.
	// The router is already chi.Router — use chi's routing DSL.
	RegisterRoutes(r chi.Router)
}

Service is the interface every AWS service emulator must implement. Adding a new service means:

  1. Create internal/services/<name>/ package.
  2. Implement this interface.
  3. Register it in New() below.

Nothing else needs to change — the router is open for extension, closed for modification. (Open/Closed Principle, same as in any language.)

type StartupPhase

type StartupPhase struct {
	Name       string  `json:"name"`
	StartMs    float64 `json:"start_ms"`    // ms since OS process start
	DurationMs float64 `json:"duration_ms"` // ms this phase took
}

StartupPhase records a single timed phase during server initialization. Exposed via /_metrics to power the startup timeline visualisation in the web UI. StartMs is milliseconds since the OS process started (same reference as startup_duration_ms).

func GetStartupPhases

func GetStartupPhases() []StartupPhase

GetStartupPhases returns the sealed startup phase timeline. Returns nil until router.New has returned — phases are sealed then.

type Stopper

type Stopper interface {
	Stop(ctx context.Context)
}

Stopper is optionally implemented by services that hold background resources (goroutines, open connections, child processes) that must be released before the process exits. The router calls Stop on every Stopper after the HTTP server has drained, passing the remaining shutdown context.

type TargetDispatcher

type TargetDispatcher interface {
	// TargetPrefix returns the X-Amz-Target prefix for this service,
	// e.g. "AmazonSQS.", "DynamoDB_20120810.".
	TargetPrefix() string

	// Dispatch handles the request after the router has matched the target prefix.
	Dispatch(w http.ResponseWriter, r *http.Request)
}

TargetDispatcher is optionally implemented by services that use the X-Amz-Target header for dispatch on POST /. Because SQS, DynamoDB, and SNS all share the root POST / endpoint, the router needs to inspect the target header to route to the correct service. Services that implement this interface do NOT register POST / in RegisterRoutes — the router handles it.

Jump to

Keyboard shortcuts

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