package main import ( "bytes" "context" "encoding/json" "fmt" "io" "log" "net" "net/http" "os/signal" "syscall" ) func main() { ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT) defer can() cfg, err := newConfig() if err != nil { panic(err) } if err := run(ctx, cfg); err != nil && ctx.Err() == nil { panic(err) } } func run(ctx context.Context, cfg Config) error { select { case <-ctx.Done(): return ctx.Err() case err := <-listenAndServe(ctx, cfg): return err } } func listenAndServe(ctx context.Context, cfg Config) chan error { s := http.Server{ Addr: fmt.Sprintf(":%d", cfg.Port), Handler: http.HandlerFunc(newHandler(cfg)), BaseContext: func(net.Listener) context.Context { return ctx }, } errc := make(chan error) go func() { defer close(errc) errc <- s.ListenAndServe() }() return errc } func newHandler(cfg Config) http.HandlerFunc { mux := http.NewServeMux() mux.Handle("POST /api/v1/events/slack", http.HandlerFunc(newHandlerPostAPIV1EventsSlack(cfg))) return func(w http.ResponseWriter, r *http.Request) { b, _ := io.ReadAll(r.Body) r.Body = io.NopCloser(bytes.NewReader(b)) log.Printf("%s %s | %s", r.Method, r.URL, b) mux.ServeHTTP(w, r) } } func newHandlerPostAPIV1EventsSlack(cfg Config) http.HandlerFunc { if cfg.InitializeSlack { return handlerPostAPIV1EventsSlackInitialize } return _newHandlerPostAPIV1EventsSlack(cfg) } func handlerPostAPIV1EventsSlackInitialize(w http.ResponseWriter, r *http.Request) { b, _ := io.ReadAll(r.Body) var challenge struct { Token string Challenge string Type string } if err := json.Unmarshal(b, &challenge); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } json.NewEncoder(w).Encode(map[string]any{"challenge": challenge.Challenge}) } func _newHandlerPostAPIV1EventsSlack(cfg Config) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { b, _ := io.ReadAll(r.Body) r.Body = io.NopCloser(bytes.NewReader(b)) var token struct { Token string } if err := json.Unmarshal(b, &token); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } else if token.Token != cfg.SlackToken { http.Error(w, "invalid .token", http.StatusForbidden) return } http.Error(w, "not impl", http.StatusNotImplemented) } }