package listener import ( "context" "errors" "fmt" "io/ioutil" "net" "net/http" "os" ) type Listener struct { ctx context.Context cancel context.CancelFunc httpSrv *http.Server exportChan chan string errorChan chan error listener net.Listener handler *http.ServeMux } func New(sockPath string) (*Listener, error) { if err := os.Remove(sockPath); err != nil && !errors.Is(err, os.ErrNotExist) { return nil, fmt.Errorf("failed to cleanup previously existing socket: %w", err) } sock, err := net.Listen("unix", sockPath) if err != nil { return nil, fmt.Errorf("failed to create unix socket: %w", err) } if err := os.Chmod(sockPath, 0o777); err != nil { return nil, fmt.Errorf("failed to set permissions to unix socket: %w", err) } m := http.NewServeMux() return &Listener{ handler: m, httpSrv: &http.Server{ Handler: m, }, listener: sock, exportChan: make(chan string, 10), errorChan: make(chan error, 10), }, nil } func (l *Listener) initMux() { l.handler.HandleFunc("/", l.sendMessageHandler) } func (l *Listener) Run(ctx context.Context) { l.ctx, l.cancel = context.WithCancel(ctx) l.initMux() if err := l.httpSrv.Serve(l.listener); err != nil { l.errorChan <- fmt.Errorf("failed to serve HTTP server: %w", err) } } func (l *Listener) sendMessage(message string) { l.exportChan <- message } func (l *Listener) sendMessageHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { w.WriteHeader(http.StatusMethodNotAllowed) return } // TODO: use max length instead of writing everything bod, err := ioutil.ReadAll(r.Body) if err != nil { l.errorChan <- fmt.Errorf("failed to read body: %w", err) w.WriteHeader(http.StatusBadRequest) return } l.sendMessage(string(bod)) w.WriteHeader(http.StatusOK) } func (l *Listener) ExportChan() <-chan string { return l.exportChan } func (l *Listener) ErrorChan() <-chan error { return l.errorChan }