Files

62 lines
1.8 KiB
Go

package contract
import (
"bytes"
"fmt"
"path"
"strings"
"sync"
"git.ipao.vip/rogee/go-sip/contracts"
"github.com/santhosh-tekuri/jsonschema/v6"
)
var compiledSchemas sync.Map
type bundleLoader struct{ version string }
func (l bundleLoader) base() string {
return "https://go-sip.local/contracts/" + l.version + "/"
}
// Load never accesses the network or resolves references against another bundle.
func (l bundleLoader) Load(address string) (any, error) {
if !strings.HasPrefix(address, l.base()) {
return nil, fmt.Errorf("schema reference outside pinned bundle: %s", address)
}
name := strings.TrimPrefix(address, l.base())
if name == "" || path.Base(name) != name || !strings.HasSuffix(name, ".schema.json") {
return nil, fmt.Errorf("invalid schema resource name %q", name)
}
raw, err := contracts.Files.ReadFile("upstream/" + l.version + "/" + name)
if err != nil {
return nil, fmt.Errorf("read pinned schema %s: %w", name, err)
}
return jsonschema.UnmarshalJSON(bytes.NewReader(raw))
}
func schemaFromBundle(version, name string) (*jsonschema.Schema, error) {
key := version + "/" + name
if cached, ok := compiledSchemas.Load(key); ok {
return cached.(*jsonschema.Schema), nil
}
loader := bundleLoader{version: version}
resource := loader.base() + name
doc, err := loader.Load(resource)
if err != nil {
return nil, err
}
compiler := jsonschema.NewCompiler()
compiler.UseLoader(loader)
compiler.AssertFormat()
if err := compiler.AddResource(resource, doc); err != nil {
return nil, fmt.Errorf("register %s: %w", name, err)
}
schema, err := compiler.Compile(resource)
if err != nil {
return nil, fmt.Errorf("compile %s: %w", name, err)
}
actual, _ := compiledSchemas.LoadOrStore(key, schema)
return actual.(*jsonschema.Schema), nil
}