server

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package server is peng's transport-agnostic request mux.

Handlers receive a Request and return a Response. The mux maps (method, path) tuples to handlers and exposes a single Mux.Dispatch entry point that every transport adapter (IPC, HTTP, MCP) calls into. See docs/server-design-WIP.md for the why.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ChannelStream

type ChannelStream struct {
	Ch      <-chan any
	OnClose func()
	// contains filtered or unexported fields
}

ChannelStream adapts a channel of frames to the Stream interface. Closing the underlying channel (or canceling the context) ends the stream; transports always call Close, so it's safe to wire a cleanup goroutine there.

func (*ChannelStream) Close

func (s *ChannelStream) Close() error

Close runs the OnClose hook exactly once.

func (*ChannelStream) Next

func (s *ChannelStream) Next(ctx context.Context) (any, bool, error)

Next blocks until a frame arrives, the channel closes (done=true), or the context is canceled.

type Handler

type Handler func(req *Request) Response

Handler is the signature every peng operation implements. Handlers are pure functions of their Request; they don't know which transport invoked them.

type MCPMeta

type MCPMeta struct {
	Name    string // tool name as exposed to MCP clients
	Confirm bool   // require confirm:true argument before invocation
}

MCPMeta marks a route for inclusion in the MCP tool list.

type Mux

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

Mux maps (method, path) tuples to handlers. Routes are matched in registration order, so register specific routes ("/migrations/up") before parameterized ones ("/migrations/{version}").

func NewMux

func NewMux() *Mux

NewMux returns an empty mux.

func (*Mux) Dispatch

func (m *Mux) Dispatch(ctx context.Context, method, path string,
	query url.Values, headers map[string]string, body json.RawMessage) Response

Dispatch is the single entry point every transport calls. It runs the matched handler synchronously and returns its Response. Transports handle concurrency (one goroutine per request) and stream pumping around this call.

func (*Mux) Handle

func (m *Mux) Handle(method, pattern string, h Handler, opts ...RouteOption)

Handle registers a route. The pattern uses "{name}" segments for path captures; everything else is matched literally. Method is matched case-sensitively (use upper-case verbs).

func (*Mux) Routes

func (m *Mux) Routes() []*Route

Routes returns the registered routes. Slice is shared; do not mutate.

type Request

type Request struct {
	Ctx     context.Context
	Method  string
	Path    string
	Params  map[string]string
	Query   url.Values
	Headers map[string]string
	Body    json.RawMessage
}

Request is the transport-agnostic input to every handler.

Body is left as raw JSON so each handler decodes into its own argument type — keeps the mux free of generics. Params holds path-pattern captures (e.g. for "/migrations/{version}", Params["version"] is the matched segment). Headers carries only transport-relevant entries (Authorization, Idempotency-Key) — bulk request metadata stays out.

type Response

type Response struct {
	Status  int
	Headers map[string]string
	Body    any
	Stream  Stream
}

Response is the transport-agnostic output of every handler.

Exactly one of Body or Stream should be set. Status without either signals a no-body response (typically 204). Headers are optional; transports may ignore them (MCP, for instance, has no header concept).

func JSON

func JSON(status int, body any) Response

JSON returns a Response with status, JSON body, and standard headers implicitly set by transports.

func NoContent

func NoContent() Response

NoContent returns a 204 with no body.

func Problem

func Problem(status int, title, detail string) Response

Problem returns an RFC 7807 problem+json error response. Handlers can return this directly when a request is invalid or fails.

func Streaming

func Streaming(s Stream) Response

Streaming returns a Response that pumps frames from the given stream.

type Route

type Route struct {
	Method  string
	Pattern string
	Handler Handler
	MCP     *MCPMeta
	Stream  bool
	Summary string
	OpID    string // matches operationId in docs/openapi-WIP.yaml
	// contains filtered or unexported fields
}

Route is the registered handler entry. Exported so transport adapters can iterate routes (e.g. the MCP adapter builds its tool list this way).

type RouteOption

type RouteOption func(*Route)

RouteOption configures a route at registration time.

func WithMCP

func WithMCP(name string, confirm bool) RouteOption

WithMCP exposes the route as an MCP tool.

func WithOpID

func WithOpID(id string) RouteOption

WithOpID ties the route to an OpenAPI operationId so other tooling (MCP schema lookup, doc generation) can correlate.

func WithStreaming

func WithStreaming() RouteOption

WithStreaming marks the route as producing a Stream response. Transports without a streaming model (MCP) refuse to register it.

func WithSummary

func WithSummary(s string) RouteOption

WithSummary attaches a short description (used by MCP tool descriptions and HTTP discovery endpoints).

type Stream

type Stream interface {
	Next(ctx context.Context) (frame any, done bool, err error)
	Close() error
}

Stream is a unidirectional producer of JSON-encodable frames. The transport drives [Next] until done is true or ctx is canceled. HTTP formats each frame as an SSE event; IPC wraps each as a "chunk" envelope on the same channel as request/response; MCP refuses to register streaming routes.

Directories

Path Synopsis
Package handlers wires up route registrations for the peng server.
Package handlers wires up route registrations for the peng server.

Jump to

Keyboard shortcuts

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