server

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const ShutdownBudget = 3 * time.Second

ShutdownBudget is how long graceful shutdown may take. main.go uses it for its shutdown context, and sseWriteDeadline is defined strictly under it, so the two cannot drift apart into a shutdown that always force-closes.

Variables

This section is empty.

Functions

func HostValidationMiddleware

func HostValidationMiddleware(next http.Handler, port int) http.Handler

func SeqPath added in v1.2.0

func SeqPath(store *versions.Store) string

SeqPath is where the live-sync sequence high-water mark lives, beside the backups in a private 0700 directory the server refuses to serve.

func ValidateHost

func ValidateHost(r *http.Request, port int) bool

func ValidatePath

func ValidatePath(relPath string, homeDir string) (string, error)

Types

type Hooks added in v1.3.0

type Hooks struct {
	// Confirm replaces the native read-permission dialog. Nil uses the real one.
	//
	// allowTrust reports whether the dialog may offer to trust the folder
	// durably. The app decides it from its refusal rules BEFORE the dialog is
	// drawn, so a folder that could never be trusted is never offered; the
	// button used to be drawn always and the refusal arrived afterwards as a
	// notification, which asked the user for a choice that could not be honored.
	Confirm func(title, message string, allowTrust bool) (platform.ConfirmChoice, error)

	// TrustedCovers reports whether absPath sits inside a DECLARED trusted
	// folder. It is the config fact, not this site's runtime roots: a file can
	// belong to a trusted folder this site holds no root for, and answering from
	// the roots is exactly what made a folder declared below an already-open
	// site grant nothing at all. It must not touch the filesystem; see
	// shouldAutoRegister for why the ordering there is load-bearing.
	TrustedCovers func(absPath string) bool

	// TrustedLive is the same question with the identity pin applied: is absPath
	// inside a trusted folder that is still the folder that was trusted? A folder
	// deleted and recreated still covers lexically but is no longer live, and the
	// two must not be confused. TrustedCovers is the gate on whether to TRY
	// auto-registering, and answers from memory; this one is the standing
	// capability, and stats. Only handleTrustRequest asks it, on the file its own
	// token was minted for, so the stat reveals nothing a caller did not know.
	TrustedLive func(absPath string) bool

	// Route registers absPath through the app and reports where it serves, so
	// this site can redirect when the registration landed on another origin.
	// Trusted-folder auto-registration is its only caller, and the app refuses
	// anything that does not anchor at a live trusted folder.
	Route func(absPath string) (url string, ok bool)

	// MayTrustFolder gates Confirm's allowTrust for a candidate folder.
	MayTrustFolder func(dir string) bool

	// TrustFolder is the durable half of the read prompt's "Trust this folder"
	// choice. The folder there is one the PAGE steered, by choosing which
	// out-of-scope assets to request, so the app applies its stricter refusal
	// rule behind this.
	TrustFolder func(dir string) error

	// TrustRequest is the one door for "trust this file's folder". Both routes
	// into it name a FILE the server already vouches for, never a folder: the
	// banner's nonce resolves to the descriptor that was served, and the JSON
	// route's token to a registration. openedByUser is false when the file was
	// reached by a link, and the dialog says so on its first line.
	TrustRequest func(requestingFile string, openedByUser bool) (url string, ok bool)
}

Hooks are the decisions a site's server cannot make for itself. Each one needs the declared trusted-folder list, the app's site registry, or a native dialog, and the server imports none of those.

Wiring them as one struct at construction makes the whole app-to-server contract a single declaration that can be read from either end. As five separate setters mutating a live server, it could only be reconstructed by grepping, and two of them had to take the broker's lock because they could be called at any moment.

A nil field disables that route, which is what a standalone server (every server test) wants.

type LiveSync added in v1.2.0

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

LiveSync bundles the process-wide live-sync machinery: the pub/sub hub, the file watcher, and the coordinator that keeps their membership in step. One LiveSync is shared by every per-tree site. It keys all state by absolute file path, and absolute paths are unique across the single home directory, so sharing one instance never collides between sites.

func NewLiveSync added in v1.2.0

func NewLiveSync(seqPath string, logger *logging.Logger) *LiveSync

NewLiveSync builds the shared live-sync runtime. seqPath is the persisted sequence high-water mark, which lives beside the backups in a private 0700 directory the server refuses to serve.

func (*LiveSync) DropSubscribers added in v1.3.0

func (ls *LiveSync) DropSubscribers(path string)

DropSubscribers closes every SSE stream for path, across every site. Used by revocation: a live stream resolved its *session.File once and would otherwise loop forever after the registration died. Each stopped stream unwinds through its handler's deferred coordinator remove, which drops the watcher reference and hub membership idempotently — teardown by eviction, not a second bookkeeping path.

func (*LiveSync) Shutdown added in v1.2.0

func (ls *LiveSync) Shutdown()

Shutdown stops the watcher and closes every SSE stream across all sites. Call it once at process exit, before shutting down the per-site HTTP servers, so graceful shutdown does not wait on open SSE connections.

type Server

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

func New

func New(ln net.Listener, sessions *session.Manager, logger *logging.Logger, store *versions.Store) *Server

New builds a server that owns its own live-sync runtime and tears it down on Shutdown/Close. Used by tests and any single-server caller.

func NewWithLiveSync added in v1.2.0

func NewWithLiveSync(ln net.Listener, sessions *session.Manager, logger *logging.Logger, store *versions.Store, ls *LiveSync) *Server

NewWithLiveSync builds a server that shares an injected live-sync runtime with its sibling sites. The runtime is owned by the process, not by any one server, so Shutdown/Close leave it running; the process shuts it down once.

func (*Server) Close

func (s *Server) Close() error

func (*Server) SetHooks added in v1.3.0

func (s *Server) SetHooks(h Hooks)

SetHooks wires the app behind this server. Call once, before Start.

func (*Server) SetInternalDir added in v1.2.0

func (s *Server) SetInternalDir(dir string)

SetInternalDir marks a directory the server must never serve, whatever the read roots say. htmlclay's own config tree holds its log and settings, and a grant that happens to cover that directory must not turn into a read path. Denying on the serve path is structural; a grant-time guard can only ever cover the grants it happens to see.

func (*Server) SetSiteLabel added in v1.2.0

func (s *Server) SetSiteLabel(label string)

SetSiteLabel names this site in the permission dialog so the user knows which page is asking. Optional; the broker falls back to a generic label.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown releases parked permission requests and closes every SSE stream before handing off to http.Server.Shutdown. Both otherwise hold graceful shutdown open until its timeout and are then force-closed. A server that shares an injected live-sync runtime leaves it running (the process shuts the shared runtime down once, before the per-site HTTP servers).

func (*Server) Start

func (s *Server) Start() error

Jump to

Keyboard shortcuts

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