package server import ( "context" "fmt" "net" "net/http" "strings" "time" ) const ( EndpointAddChain = "/add-chain" EndpointGetStatus = "/get-status" DefaultAddress = "localhost:2009" DefaultConfigFile = "/home/rgdd/.config/silent-ct/config.json" // FIXME ) type Nodes []Node type Node struct { Name string `json:"name"` Secret string `json:"secret"` Domains []string `json:"issues"` } type Config struct { Address string // hostname[:port] or unix:///path/to/file.sock Nodes Nodes // Which nodes are trusted to issue what certificates } type Server struct { Config http.Server unixSocket bool // true if listening with a unix socket eventCh chan MessageNodeSubmission errorCh chan error } func New(cfg Config) (Server, error) { mux := http.NewServeMux() srv := Server{Config: cfg, Server: http.Server{Handler: mux}} mux.HandleFunc(EndpointAddChain, func(w http.ResponseWriter, r *http.Request) { srv.addChain(w, r) }) mux.HandleFunc(EndpointGetStatus, func(w http.ResponseWriter, r *http.Request) { srv.getStatus(w, r) }) if len(srv.Address) == 0 { srv.Config.Address = DefaultAddress } if strings.HasPrefix(srv.Config.Address, "unix://") { srv.Config.Address = srv.Config.Address[7:] srv.unixSocket = true } return srv, nil } func (srv *Server) Run(ctx context.Context, submitCh chan MessageNodeSubmission, errorCh chan error) error { srv.eventCh = submitCh srv.errorCh = errorCh network := "unix" if !srv.unixSocket { network = "tcp" } listener, err := net.Listen(network, srv.Address) if err != nil { return fmt.Errorf("listen: %v", err) } defer listener.Close() exitErr := make(chan error, 1) defer close(exitErr) go func() { exitErr <- srv.Serve(listener) }() select { case err := <-exitErr: if err != nil && err != http.ErrServerClosed { return fmt.Errorf("serve: %v", err) } case <-ctx.Done(): tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(tctx); err != nil { return fmt.Errorf("shutdown: %v", err) } } return nil } func (srv *Server) getStatus(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Only HTTP GET method is allowed", http.StatusMethodNotAllowed) return } fmt.Fprintf(w, "OK\n") } func (srv *Server) addChain(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Only HTTP POST method is allowed", http.StatusMethodNotAllowed) return } fmt.Fprintf(w, "TODO: HTTP POST /add-chain\n") }