feat(19.7-02): pier MCP module tracer with in-process dispatch and sessions
- modules/pier: Host contract, mcp.* config, catalog compiled from pact.HasMCP (prefixing, route binding, guard resolution, schema reflection, annotations), per-request identity through the published verifier and resolvers, built-in backend guard provider, in-process dispatch with the bouncer marker, per-identity SDK server with the per-request re-filter, stateful session router with rehydration over a memory store, audit lines - modules/surf/pier_on.go: the summercms_mcp hook adapting the router to pier.Host; the untagged hello binary carries no SDK - go.mod: go-sdk v1.8.0 and jsonschema-go v0.4.3 (decision note committed before this change) - TestPierTracerSmoke: SDK client lists and calls acme_echo end to end through surf's compiled guard chain; README and root table row
This commit is contained in:
68
modules/surf/pier_on.go
Normal file
68
modules/surf/pier_on.go
Normal file
@@ -0,0 +1,68 @@
|
||||
//go:build summercms_mcp
|
||||
|
||||
package surf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/pact"
|
||||
"git.golem15.com/golem15/summercms/modules/party"
|
||||
"git.golem15.com/golem15/summercms/modules/pier"
|
||||
)
|
||||
|
||||
// Binaries built with the summercms_mcp tag (MCPBuildTag) link the MCP
|
||||
// module: this file sets the mount hook BuildRouter calls when mcp.enabled
|
||||
// is true, with an adapter that gives pier the route table, the compiled
|
||||
// handler lookup and the two mount kinds without pier importing surf.
|
||||
func init() {
|
||||
mountPier = func(r *Router, app *backpack.App, plugins []party.Plugin) error {
|
||||
return pier.Mount(pierHost{r: r}, app, plugins)
|
||||
}
|
||||
}
|
||||
|
||||
// pierHost adapts a Router to pier.Host.
|
||||
type pierHost struct {
|
||||
r *Router
|
||||
}
|
||||
|
||||
func (h pierHost) Routes() []pier.RouteInfo {
|
||||
routes := h.r.Routes()
|
||||
out := make([]pier.RouteInfo, len(routes))
|
||||
for i, ri := range routes {
|
||||
out[i] = pier.RouteInfo{Method: ri.Method, Pattern: ri.Pattern, PluginID: ri.PluginID, Middleware: ri.Middleware}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (h pierHost) Handler(method, pattern string) (http.Handler, bool) {
|
||||
return h.r.Handler(method, pattern)
|
||||
}
|
||||
|
||||
func (h pierHost) MountStream(method, path string, handler http.Handler, middleware ...string) error {
|
||||
h.r.BindPlugin(pier.PluginID)
|
||||
return h.r.MountStream(method, path, handler, middleware...)
|
||||
}
|
||||
|
||||
// MountJSON registers a plain GET route (no middleware) under the pier
|
||||
// pseudo-plugin; only GET is supported.
|
||||
func (h pierHost) MountJSON(method, path string, handler http.Handler) error {
|
||||
if strings.ToUpper(strings.TrimSpace(method)) != http.MethodGet {
|
||||
return fmt.Errorf("surf: pier may mount JSON routes with GET only, got %q", method)
|
||||
}
|
||||
if owner, ok := h.Owner(http.MethodGet, path); ok {
|
||||
return fmt.Errorf("surf: route GET %s (plugin %q) collides with a route the MCP module mounts", path, owner)
|
||||
}
|
||||
h.r.BindPlugin(pier.PluginID)
|
||||
h.r.GroupRaw("", nil, func(g pact.Router) {
|
||||
g.Get(path, handler.ServeHTTP)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h pierHost) Owner(method, path string) (string, bool) {
|
||||
owner, ok := h.r.seen[strings.ToUpper(strings.TrimSpace(method))+" "+path]
|
||||
return owner, ok
|
||||
}
|
||||
Reference in New Issue
Block a user