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 hook interface { Open(env env.Env) (interface{}, error) } type H interface { hook String() string } type Sender interface { Send(rq, wq queue.Q) error } type Recver interface { Recv(rq, wq queue.Q) error } 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 Open(h H, env env.Env) (Func, Func, error) { var send, recv Func w := h.(*wrapper) it, err := h.Open(env) if err != nil { return nil, nil, err } if sender, ok := it.(Sender); ok { send = sender.Send } if recver, ok := it.(Recver); ok { recv = recver.Recv } if w.reverse { send, recv = recv, send } return send, recv, nil } 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 }