mirror of
https://github.com/caddyserver/caddy.git
synced 2025-03-26 23:11:05 +03:00
core: add type registry
Facilitates validation of type adherence to namespace requirements
This commit is contained in:
parent
b16aba5c27
commit
5e24e84288
17 changed files with 180 additions and 0 deletions
4
admin.go
4
admin.go
|
@ -34,6 +34,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -55,6 +56,9 @@ func init() {
|
||||||
if env, exists := os.LookupEnv("CADDY_ADMIN"); exists {
|
if env, exists := os.LookupEnv("CADDY_ADMIN"); exists {
|
||||||
DefaultAdminListen = env
|
DefaultAdminListen = env
|
||||||
}
|
}
|
||||||
|
RegisterType("caddy.config_loaders", []reflect.Type{
|
||||||
|
reflect.TypeOf((*ConfigLoader)(nil)).Elem(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminConfig configures Caddy's API endpoint, which is used
|
// AdminConfig configures Caddy's API endpoint, which is used
|
||||||
|
|
14
caddy.go
14
caddy.go
|
@ -27,6 +27,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -41,6 +42,15 @@ import (
|
||||||
"github.com/caddyserver/caddy/v2/notify"
|
"github.com/caddyserver/caddy/v2/notify"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterType("", []reflect.Type{
|
||||||
|
reflect.TypeOf((*App)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
RegisterType("caddy.storage", []reflect.Type{
|
||||||
|
reflect.TypeOf((*StorageConverter)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Config is the top (or beginning) of the Caddy configuration structure.
|
// Config is the top (or beginning) of the Caddy configuration structure.
|
||||||
// Caddy config is expressed natively as a JSON document. If you prefer
|
// Caddy config is expressed natively as a JSON document. If you prefer
|
||||||
// not to work with JSON directly, there are [many config adapters](/docs/config-adapters)
|
// not to work with JSON directly, there are [many config adapters](/docs/config-adapters)
|
||||||
|
@ -72,11 +82,15 @@ type Config struct {
|
||||||
// module is `caddy.storage.file_system` (the local file system),
|
// module is `caddy.storage.file_system` (the local file system),
|
||||||
// and the default path
|
// and the default path
|
||||||
// [depends on the OS and environment](/docs/conventions#data-directory).
|
// [depends on the OS and environment](/docs/conventions#data-directory).
|
||||||
|
// A storage `module` should implement the following interfaces:
|
||||||
|
// - [StorageConverter](https://pkg.go.dev/github.com/caddyserver/caddy/v2#StorageConverter)
|
||||||
StorageRaw json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`
|
StorageRaw json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`
|
||||||
|
|
||||||
// AppsRaw are the apps that Caddy will load and run. The
|
// AppsRaw are the apps that Caddy will load and run. The
|
||||||
// app module name is the key, and the app's config is the
|
// app module name is the key, and the app's config is the
|
||||||
// associated value.
|
// associated value.
|
||||||
|
// An `app` should implement the following interfaces:
|
||||||
|
// - [caddy.App](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#App)
|
||||||
AppsRaw ModuleMap `json:"apps,omitempty" caddy:"namespace="`
|
AppsRaw ModuleMap `json:"apps,omitempty" caddy:"namespace="`
|
||||||
|
|
||||||
apps map[string]App
|
apps map[string]App
|
||||||
|
|
22
caddytest/integration/types_test.go
Normal file
22
caddytest/integration/types_test.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/v2"
|
||||||
|
_ "github.com/caddyserver/caddy/v2/modules/standard"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validates Caddy's the registered internal types implement the necessary interfaces of their
|
||||||
|
// namespaces
|
||||||
|
func TestTypes(t *testing.T) {
|
||||||
|
var i int
|
||||||
|
for _, v := range caddy.Modules() {
|
||||||
|
mod, _ := caddy.GetModule(v)
|
||||||
|
if ok, err := caddy.ConformsToNamespace(mod.New(), mod.ID.Namespace()); !ok {
|
||||||
|
t.Errorf("%s", err)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
t.Logf("Passed through %d modules", i)
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -37,6 +38,12 @@ import (
|
||||||
"github.com/caddyserver/caddy/v2/internal"
|
"github.com/caddyserver/caddy/v2/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterType("caddy.listeners", []reflect.Type{
|
||||||
|
reflect.TypeOf((*ListenerWrapper)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// NetworkAddress represents one or more network addresses.
|
// NetworkAddress represents one or more network addresses.
|
||||||
// It contains the individual components for a parsed network
|
// It contains the individual components for a parsed network
|
||||||
// address of the form accepted by ParseNetworkAddress().
|
// address of the form accepted by ParseNetworkAddress().
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -33,6 +34,12 @@ func init() {
|
||||||
RegisterModule(StdoutWriter{})
|
RegisterModule(StdoutWriter{})
|
||||||
RegisterModule(StderrWriter{})
|
RegisterModule(StderrWriter{})
|
||||||
RegisterModule(DiscardWriter{})
|
RegisterModule(DiscardWriter{})
|
||||||
|
RegisterType("caddy.logging.encoders", []reflect.Type{
|
||||||
|
reflect.TypeOf((*zapcore.Encoder)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
RegisterType("caddy.logging.writers", []reflect.Type{
|
||||||
|
reflect.TypeOf((*WriterOpener)(nil)).Elem(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging facilitates logging within Caddy. The default log is
|
// Logging facilitates logging within Caddy. The default log is
|
||||||
|
@ -265,6 +272,8 @@ type BaseLog struct {
|
||||||
WriterRaw json.RawMessage `json:"writer,omitempty" caddy:"namespace=caddy.logging.writers inline_key=output"`
|
WriterRaw json.RawMessage `json:"writer,omitempty" caddy:"namespace=caddy.logging.writers inline_key=output"`
|
||||||
|
|
||||||
// The encoder is how the log entries are formatted or encoded.
|
// The encoder is how the log entries are formatted or encoded.
|
||||||
|
// An `encoder` should implement the following interfaces:
|
||||||
|
// - [zapcore.Encoder](https://pkg.go.dev/go.uber.org/zap/zapcore#Encoder)
|
||||||
EncoderRaw json.RawMessage `json:"encoder,omitempty" caddy:"namespace=caddy.logging.encoders inline_key=format"`
|
EncoderRaw json.RawMessage `json:"encoder,omitempty" caddy:"namespace=caddy.logging.encoders inline_key=format"`
|
||||||
|
|
||||||
// Level is the minimum level to emit, and is inclusive.
|
// Level is the minimum level to emit, and is inclusive.
|
||||||
|
|
|
@ -21,8 +21,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
weakrand "math/rand"
|
weakrand "math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
|
|
||||||
|
@ -31,6 +33,15 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
caddy.RegisterModule(HTTPBasicAuth{})
|
caddy.RegisterModule(HTTPBasicAuth{})
|
||||||
|
|
||||||
|
caddy.RegisterType("http.authentication.hashes", []reflect.Type{
|
||||||
|
reflect.TypeOf((*Comparer)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
caddy.RegisterType("http.authentication.providers", []reflect.Type{
|
||||||
|
reflect.TypeOf((*Authenticator)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
|
||||||
|
weakrand.Seed(time.Now().UnixNano())
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBasicAuth facilitates HTTP basic authentication.
|
// HTTPBasicAuth facilitates HTTP basic authentication.
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -37,6 +38,9 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
caddy.RegisterModule(Encode{})
|
caddy.RegisterModule(Encode{})
|
||||||
|
caddy.RegisterType("http.encoders", []reflect.Type{
|
||||||
|
reflect.TypeOf((*Encoding)(nil)).Elem(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode is a middleware which can encode responses.
|
// Encode is a middleware which can encode responses.
|
||||||
|
|
|
@ -26,9 +26,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
@ -38,6 +40,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
weakrand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
caddy.RegisterType("http.precompressed", []reflect.Type{
|
||||||
|
reflect.TypeOf((*encode.Precompressed)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
|
||||||
caddy.RegisterModule(FileServer{})
|
caddy.RegisterModule(FileServer{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,8 @@ type (
|
||||||
// where each of the array elements is a matcher set, i.e. an
|
// where each of the array elements is a matcher set, i.e. an
|
||||||
// object keyed by matcher name.
|
// object keyed by matcher name.
|
||||||
MatchNot struct {
|
MatchNot struct {
|
||||||
|
// A `matcher` should implement the following interfaces:
|
||||||
|
// - [caddyhttp.RequestMatcher](https://pkg.go.dev/github.com/caddyserver/caddy/v2/modules/caddyhttp?tab=doc#RequestMatcher)
|
||||||
MatcherSetsRaw []caddy.ModuleMap `json:"-" caddy:"namespace=http.matchers"`
|
MatcherSetsRaw []caddy.ModuleMap `json:"-" caddy:"namespace=http.matchers"`
|
||||||
MatcherSets []MatcherSet `json:"-"`
|
MatcherSets []MatcherSet `json:"-"`
|
||||||
}
|
}
|
||||||
|
@ -212,6 +214,9 @@ func init() {
|
||||||
caddy.RegisterModule(MatchHeaderRE{})
|
caddy.RegisterModule(MatchHeaderRE{})
|
||||||
caddy.RegisterModule(new(MatchProtocol))
|
caddy.RegisterModule(new(MatchProtocol))
|
||||||
caddy.RegisterModule(MatchNot{})
|
caddy.RegisterModule(MatchNot{})
|
||||||
|
caddy.RegisterType("http.matchers", []reflect.Type{
|
||||||
|
reflect.TypeOf((*RequestMatcher)(nil)).Elem(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaddyModule returns the Caddy module information.
|
// CaddyModule returns the Caddy module information.
|
||||||
|
|
|
@ -1145,3 +1145,9 @@ func BenchmarkHostMatcherWithPlaceholder(b *testing.B) {
|
||||||
match.Match(req)
|
match.Match(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConformsToNamespace(t *testing.T) {
|
||||||
|
if ok, err := caddy.ConformsToNamespace(new(StaticResponse), "http.matchers"); !ok || err != nil {
|
||||||
|
t.Errorf("%s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -45,6 +46,19 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
caddy.RegisterModule(Handler{})
|
caddy.RegisterModule(Handler{})
|
||||||
|
|
||||||
|
caddy.RegisterType("http.reverse_proxy.circuit_breakers", []reflect.Type{
|
||||||
|
reflect.TypeOf((*CircuitBreaker)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
caddy.RegisterType("http.reverse_proxy.selection_policies", []reflect.Type{
|
||||||
|
reflect.TypeOf((*Selector)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
caddy.RegisterType("http.reverse_proxy.transport", []reflect.Type{
|
||||||
|
reflect.TypeOf((*http.RoundTripper)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
caddy.RegisterType("http.reverse_proxy.upstreams", []reflect.Type{
|
||||||
|
reflect.TypeOf((*UpstreamSource)(nil)).Elem(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler implements a highly configurable and production-ready reverse proxy.
|
// Handler implements a highly configurable and production-ready reverse proxy.
|
||||||
|
|
|
@ -18,10 +18,17 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
caddy.RegisterType("http.handlers", []reflect.Type{
|
||||||
|
reflect.TypeOf((*MiddlewareHandler)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Route consists of a set of rules for matching HTTP requests,
|
// Route consists of a set of rules for matching HTTP requests,
|
||||||
// a list of handlers to execute, and optional flow control
|
// a list of handlers to execute, and optional flow control
|
||||||
// parameters which customize the handling of HTTP requests
|
// parameters which customize the handling of HTTP requests
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -30,6 +31,18 @@ import (
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
caddy.RegisterType("dns.provider", []reflect.Type{
|
||||||
|
reflect.TypeOf((*acmez.Solver)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
caddy.RegisterType("tls.get_certificate", []reflect.Type{
|
||||||
|
reflect.TypeOf((*certmagic.Manager)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
caddy.RegisterType("tls.issuance", []reflect.Type{
|
||||||
|
reflect.TypeOf((*certmagic.Issuer)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// AutomationConfig governs the automated management of TLS certificates.
|
// AutomationConfig governs the automated management of TLS certificates.
|
||||||
type AutomationConfig struct {
|
type AutomationConfig struct {
|
||||||
// The list of automation policies. The first policy matching
|
// The list of automation policies. The first policy matching
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mholt/acmez"
|
"github.com/mholt/acmez"
|
||||||
|
@ -33,6 +34,9 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
caddy.RegisterModule(LeafCertClientAuth{})
|
caddy.RegisterModule(LeafCertClientAuth{})
|
||||||
|
caddy.RegisterType("tls.handshake_match", []reflect.Type{
|
||||||
|
reflect.TypeOf((*ConnectionMatcher)(nil)).Elem(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectionPolicies govern the establishment of TLS connections. It is
|
// ConnectionPolicies govern the establishment of TLS connections. It is
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"reflect"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -28,6 +29,12 @@ import (
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
caddy.RegisterType("tls.stek", []reflect.Type{
|
||||||
|
reflect.TypeOf((*STEKProvider)(nil)).Elem(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// SessionTicketService configures and manages TLS session tickets.
|
// SessionTicketService configures and manages TLS session tickets.
|
||||||
type SessionTicketService struct {
|
type SessionTicketService struct {
|
||||||
// KeySource is the method by which Caddy produces or obtains
|
// KeySource is the method by which Caddy produces or obtains
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -35,6 +36,10 @@ import (
|
||||||
func init() {
|
func init() {
|
||||||
caddy.RegisterModule(TLS{})
|
caddy.RegisterModule(TLS{})
|
||||||
caddy.RegisterModule(AutomateLoader{})
|
caddy.RegisterModule(AutomateLoader{})
|
||||||
|
|
||||||
|
caddy.RegisterType("tls.certificates", []reflect.Type{
|
||||||
|
reflect.TypeOf((*CertificateLoader)(nil)).Elem(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -652,6 +657,11 @@ func (AutomateLoader) CaddyModule() caddy.ModuleInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadCertificates is a stub so AutomateLoader can implement CertificateLoader
|
||||||
|
func (AutomateLoader) LoadCertificates() ([]Certificate, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CertCacheOptions configures the certificate cache.
|
// CertCacheOptions configures the certificate cache.
|
||||||
type CertCacheOptions struct {
|
type CertCacheOptions struct {
|
||||||
// Maximum number of certificates to allow in the
|
// Maximum number of certificates to allow in the
|
||||||
|
|
35
types.go
Normal file
35
types.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var namespaceTypes map[string][]reflect.Type = make(map[string][]reflect.Type)
|
||||||
|
|
||||||
|
func RegisterType(namespace string, types []reflect.Type) {
|
||||||
|
if _, ok := namespaceTypes[namespace]; ok {
|
||||||
|
panic("namespace is already registered")
|
||||||
|
}
|
||||||
|
namespaceTypes[namespace] = types
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespaceTypes returns a copy of Caddy's namespace->type registry
|
||||||
|
func NamespaceTypes() map[string][]reflect.Type {
|
||||||
|
copy := make(map[string][]reflect.Type)
|
||||||
|
for namespace, typeSlice := range namespaceTypes {
|
||||||
|
copy[namespace] = typeSlice
|
||||||
|
}
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConformsToNamespace validates the given module implements all the mandatory types of a given namespace
|
||||||
|
func ConformsToNamespace(mod Module, namespace string) (bool, error) {
|
||||||
|
modType := reflect.TypeOf(mod)
|
||||||
|
for _, t := range namespaceTypes[namespace] {
|
||||||
|
if !modType.Implements(t) {
|
||||||
|
return false, fmt.Errorf("%s does not implement %s", modType, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
Loading…
Reference in a new issue