package protocol import ( "context" "time" "github.com/pkg/errors" ) type Registry struct { protocols map[Identifier]ProtocolFactory } func (r *Registry) Register(identifier Identifier, factory ProtocolFactory) { r.protocols[identifier] = factory } func (r *Registry) Get(identifier Identifier, funcs ...ProtocolOptionFunc) (Protocol, error) { factory, exists := r.protocols[identifier] if !exists { return nil, errors.WithStack(ErrNotFound) } protocolOpts := NewProtocolOptions(funcs...) proto, err := factory(protocolOpts) if err != nil { return nil, errors.WithStack(err) } return proto, nil } func (r *Registry) Availables(ctx context.Context, addr string, timeout time.Duration, funcs ...ProtocolOptionFunc) ([]Protocol, error) { availables := make([]Protocol, 0) protocolOpts := NewProtocolOptions(funcs...) for _, factory := range r.protocols { proto, err := factory(protocolOpts) if err != nil { return nil, errors.WithStack(err) } timeoutCtx, cancel := context.WithTimeout(ctx, timeout) available, err := proto.Available(timeoutCtx, addr) if err != nil { cancel() return nil, errors.WithStack(err) } cancel() if !available { continue } availables = append(availables, proto) } return availables, nil } func NewRegistry() *Registry { return &Registry{ protocols: make(map[Identifier]ProtocolFactory), } } var defaultRegistry = NewRegistry() func DefaultRegistry() *Registry { return defaultRegistry } func Register(identifier Identifier, factory ProtocolFactory) { defaultRegistry.Register(identifier, factory) } func Availables(ctx context.Context, addr string, timeout time.Duration) ([]Protocol, error) { return defaultRegistry.Availables(ctx, addr, timeout) }