package hook import ( "fmt" "log" "sort" "strings" "tunnel/pkg/server/env" "tunnel/pkg/server/opts" "tunnel/pkg/server/queue" ) type hookInitFunc func(opts.Opts, env.Env) (hook, error) var hooks = map[string]hookInitFunc{} type Pipe struct { priv interface{} Send Func Recv Func } type hook interface { Open(env env.Env) (interface{}, error) } type H interface { Open(env env.Env) (*Pipe, error) String() string } type Sender interface { Send(rq, wq queue.Q) error } type Recver interface { Recv(rq, wq queue.Q) error } type Closer interface { Close() } type Func func(rq, wq queue.Q) error func (f Func) Send(rq, wq queue.Q) error { return f(rq, wq) } func (f Func) Open(env env.Env) (interface{}, error) { return f, nil } type wrapper struct { hook name string reverse bool } func (w *wrapper) String() string { return fmt.Sprintf("hook:%s", w.name) } func (w *wrapper) Open(env env.Env) (*Pipe, error) { it, err := w.hook.Open(env) if err != nil { return nil, err } pipe := &Pipe{priv: it} if s, ok := it.(Sender); ok { pipe.Send = s.Send } if r, ok := it.(Recver); ok { pipe.Recv = r.Recv } if w.reverse { pipe.Send, pipe.Recv = pipe.Recv, pipe.Send } return pipe, nil } func (p *Pipe) Close() { if c, ok := p.priv.(Closer); ok { c.Close() } } func New(desc string, env env.Env) (H, error) { name, opts := opts.Parse(desc) reverse := false if strings.HasPrefix(name, "-") { name = name[1:] reverse = true } if f, ok := hooks[name]; !ok { return nil, fmt.Errorf("unknown hook '%s'", name) } else if h, err := f(opts, env); err != nil { return nil, err } else { w := &wrapper{ hook: h, name: name, reverse: reverse, } return w, nil } } func getHookVar(env env.Env, s string) string { if v := env.Eval("@{tunnel.@{tunnel}." + s + "}"); v != "" { return v } return env.Get(s) } func register(name string, f hookInitFunc) { if _, ok := hooks[name]; ok { log.Panicf("duplicate hook name '%s'", name) } hooks[name] = f } func registerFunc(name string, p Func) { register(name, func(opts.Opts, env.Env) (hook, error) { return p, nil }) } func GetList() []string { var list []string for k := range hooks { list = append(list, k) } sort.Strings(list) return list }