package module import ( "tunnel/pkg/server/queue" "tunnel/pkg/server/opts" "tunnel/pkg/server/env" "fmt" "log" ) type moduleInitFunc func (opts.Opts, env.Env) (module, error) var modules = map[string]moduleInitFunc{} type module interface { Open(env env.Env) (Pipe, Pipe) } type M interface { module String() string } type Pipe func (rq, wq queue.Q) error func (p Pipe) Open(env env.Env) (Pipe, Pipe) { return p, nil } type reverse struct { M } func Reverse(m M) M { return &reverse{m} } func (r *reverse) Open(env env.Env) (Pipe, Pipe) { p1, p2 := r.M.Open(env) return p2, p1 } type named struct { name string module } func (m *named) String() string { return fmt.Sprintf("module:%s", m.name) } func register(name string, f moduleInitFunc) { if _, ok := modules[name]; ok { log.Panicf("duplicate module name '%s'", name) } modules[name] = f } func registerPipe(name string, p Pipe) { register(name, func (opts.Opts, env.Env) (module, error) { return p, nil }) } func New(desc string, env env.Env) (M, error) { name, opts := opts.Parse(desc) if f, ok := modules[name]; !ok { return nil, fmt.Errorf("unknown module '%s'", name) } else if m, err := f(opts, env); err != nil { return nil, err } else { return &named{name: name, module: m}, nil } }