Help us shape the future of Go! Take the 2026 Go Developer Survey

server

package
v0.7.0 Latest Latest
Warning

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

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

Documentation

Overview

Package server serves the runner protocol to one app: runner.sock, and mysql.sock through mysqlproxy when the app declares sqldb. It checks everything the app sends against the protocol and the app's permission list: the protocol version, secret names, file names, mail and its recipients, calls to other apps and the size of spans. Only what passes reaches the providers, which keep the files, send the mail, hold the secrets and take the spans on the target the app runs on. A provider gives the app an error of the error catalogue with CodedError, which the app reads as the framework's own coded errors.

aicoded dev, aicoded l7-runner and the platform's runner serve apps through it. Apps never import it; they reach their runner through the building blocks.

Index

Constants

View Source
const (
	EnvDev        = "dev"
	EnvPreview    = "preview"
	EnvProduction = "production"
)

The environments an app may run in.

View Source
const MaxFileSize = 1 << 30

MaxFileSize bounds one file in a store, in bytes.

View Source
const MinCSRFKey = 32

MinCSRFKey is the shortest key Options.CSRFKey may be, in bytes.

Variables

This section is empty.

Functions

func CodedError

func CodedError(c connect.Code, code, msg, fix string) error

CodedError returns the error a provider gives the app for a problem of the error catalogue: a *connect.Error of c whose message is the code, such as E-MAIL-008, msg, the one-line fix and the code's docs link, as the framework's own coded errors print them.

Types

type Calls

type Calls interface {
	// Call checks req, a call made by the app of caller, and forwards it with traceparent.
	Call(ctx context.Context, caller manifest.Manifest, req *runnerv1.CallRequest, traceparent string) (*runnerv1.CallResponse, error)
}

Calls carries the calls of an app to other apps.

type FileInfo

type FileInfo struct {
	// Name is the last element of the file's name.
	Name    string
	Size    int64
	Dir     bool
	ModTime time.Time
}

FileInfo describes a file or a folder in a store.

type Files

type Files interface {
	// Stat describes the file or folder name.
	Stat(ctx context.Context, store, name string) (FileInfo, error)
	// ReadDir lists the folder name, in any order.
	ReadDir(ctx context.Context, store, name string) ([]FileInfo, error)
	// Read opens the file name, which Stat found to be a file.
	Read(ctx context.Context, store, name string) (io.ReadCloser, error)
	// Write replaces the file name with what data yields, at most MaxFileSize bytes, whole or not
	// at all: when data or ctx fails, the store stays as it was.
	Write(ctx context.Context, store, name string, data io.Reader) (FileInfo, error)
	// Mkdir makes the folder name and its missing parents. A folder that exists is no error.
	Mkdir(ctx context.Context, store, name string) error
	// Remove removes the file or the empty folder name.
	Remove(ctx context.Context, store, name string) error
	// Rename renames oldName to newName and replaces a file at newName. The server never asks it
	// to replace a folder.
	Rename(ctx context.Context, store, oldName, newName string) error
}

Files keeps an app's file stores. The server calls it only for a store the app declares, with a name that fs.ValidPath accepts, of at most 1024 bytes, whose elements are at most 255 bytes, hold no control character and do not start with ".aicoded-tmp-", a prefix Files may use for files of its own. A name that Write, Mkdir, Remove or Rename changes is never ".".

Its errors wrap fs.ErrNotExist, fs.ErrExist, fs.ErrPermission or a syscall.Errno, from which the server makes the app's error: a code and a message that names the file as the app named it. Any other error reaches the app as an internal error.

type Mail

type Mail interface {
	// Send sends msg from the address from, the app's email.from, once for each idempotency key
	// it remembers, and returns the message's id; a repeated key it remembers returns the first
	// message's id.
	Send(ctx context.Context, from string, msg *runnerv1.SendRequest) (string, error)
	// List returns a page of the messages in folder, newest first, and how many it holds.
	List(ctx context.Context, folder string, offset, limit int) ([]*runnerv1.MessageSummary, int, error)
	// Get returns the message id.
	Get(ctx context.Context, id string) (*runnerv1.GetResponse, error)
	// Delete deletes the message id.
	Delete(ctx context.Context, id string) error
	// Move moves the message id to folder.
	Move(ctx context.Context, id, folder string) error
}

Mail sends an app's mail and serves its mailbox. The server checks every message against the mail rules and the app's email section first, and every folder, page and message id the app names. A target that keeps no mailbox answers List, Get, Delete and Move with a *connect.Error, E-MAIL-008 with the code Unimplemented.

type Minter

type Minter interface {
	// Public returns the key that verifies the tokens it signs.
	Public() ed25519.PublicKey
	// MintCall returns the token of a call from the app caller to the app callee: on behalf of
	// the viewer v, or of the calling app itself when v is nil.
	MintCall(v *viewer.Claims, caller, callee string, now time.Time) (string, error)
}

Minter signs the tokens the runner hands apps.

type Options

type Options struct {
	// Dir is the folder where the server makes runner.sock, and mysql.sock when the app declares
	// sqldb. The app makes app.sock there.
	Dir string
	// Manifest is the app's permission list.
	Manifest manifest.Manifest
	// Env is the environment the app runs in: EnvDev, EnvPreview or EnvProduction.
	Env string
	// Version is the version of the release that Hello reports.
	Version string
	// ViewerKeys verify the viewer tokens the app accepts. There must be at least one.
	ViewerKeys []ed25519.PublicKey
	// CSRFKey signs the app's form tokens: an app accepts the tokens of another instance of it
	// with the same key. It must be at least MinCSRFKey bytes.
	CSRFKey []byte
	// ShareAppSocket makes runner.sock and mysql.sock usable by every user, and has Hello tell
	// the app to do the same with app.sock: for an app that runs as another user. Dir then
	// decides who reaches them.
	ShareAppSocket bool
	// Adopted marks an app that is already running and said Hello to an earlier server. Ready is
	// closed at New; nothing else changes.
	Adopted bool
	// Database is where the proxy on mysql.sock logs in, until SetDatabase changes it. It is set
	// exactly when the app declares sqldb.
	Database *mysqlproxy.Upstream
	// OnDatabaseError, if set, gets each reason the proxy could not open the app's database.
	// It may be called from several goroutines at once.
	OnDatabaseError func(error)
	// OnReady, if set, is called at each Ready the app sends.
	OnReady func()
	// Providers do the work of the building blocks.
	Providers Providers
}

Options configure New.

type Providers

type Providers struct {
	// Files keeps the file stores. It must be set when the app declares one.
	Files Files
	// Mail sends the app's mail and serves its mailbox. It must be set when the app declares email.
	Mail Mail
	// Secrets holds the values of the app's secrets and settings. It must be set when the app
	// declares either.
	Secrets Secrets
	// Telemetry takes the app's spans. With nil, they are dropped.
	Telemetry Telemetry
	// Calls carries the app's calls to other apps, as Router does. With nil, every call fails
	// with E-RPC-011.
	Calls Calls
}

Providers do the work of the building blocks on the target the app runs on. The server calls them only with what passed its checks.

A *connect.Error a provider returns reaches the app as it is, so its code and message must be meant for the app. Any other error reaches the app as an internal error, without its text, except the file errors that Files describes.

type Router

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

Router carries calls between the apps that one runner serves. It checks every call against the permission lists of both apps and hands the called app a fresh token for the viewer, or for the calling app when there is no viewer.

func NewRouter

func NewRouter(minter Minter) *Router

NewRouter returns a router that verifies the viewer tokens apps forward and signs call tokens with minter.

func (*Router) Add

func (r *Router) Add(m manifest.Manifest, appSocket string)

Add lets the other apps call the app of m, which listens on appSocket. It closes the connections to the instance of the app it replaces.

func (*Router) Call

func (r *Router) Call(ctx context.Context, caller manifest.Manifest, req *runnerv1.CallRequest, traceparent string) (*runnerv1.CallResponse, error)

Call checks req, a call made by the app of caller, and forwards it to the called app with traceparent. A refusal is a connect error marked as the runner's, whose message is the text of a coded error. An error of the called app passes on only with a code a function may return, and never with the runner's mark.

func (*Router) Remove

func (r *Router) Remove(app string)

Remove takes app out of the router: calls to it fail with E-RPC-011.

type Secrets

type Secrets interface {
	// Secret returns the value of the secret name, which the app declares.
	Secret(ctx context.Context, name string) (string, error)
	// Settings returns the values of the settings. Hello hands the app those it declares. It may
	// be called from several goroutines at once, and the server never changes the map.
	Settings() map[string]string
}

Secrets holds the values of an app's secrets and settings.

type Server

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

Server serves the runner protocol to one app. It knows the app by the socket it listens on, never by anything in a request, and logs nothing, so that an app cannot write to its log.

func New

func New(ctx context.Context, opts Options) (*Server, error)

New starts serving the runner protocol on runner.sock in opts.Dir, and the app's database on mysql.sock there when the app declares sqldb. It refuses options that do not fit the app.

func (*Server) Close

func (s *Server) Close() error

Close stops serving, which removes runner.sock and mysql.sock.

func (*Server) Ready

func (s *Server) Ready() <-chan struct{}

Ready is closed once the app reports that it accepts requests, or at New for an adopted app.

func (*Server) SetDatabase

func (s *Server) SetDatabase(up mysqlproxy.Upstream) error

SetDatabase makes the proxy on mysql.sock log in as up from the next connection the app opens on: sessions already open keep their login. It refuses a server that serves no database.

type Telemetry

type Telemetry interface {
	// Export takes spans, and dropped, the number of spans the app or the server dropped since
	// the previous export.
	Export(ctx context.Context, spans []*runnerv1.Span, dropped uint64)
}

Telemetry takes an app's spans. Each span's trace id is empty or 16 bytes, and its span and parent ids empty or 8 bytes. Its name and error are at most 4 KiB, and it has at most 64 attributes, with keys of at most 256 bytes and values of at most 4 KiB. One export holds at most 1024 spans.

Jump to

Keyboard shortcuts

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