diff options
Diffstat (limited to 'server.go')
| -rw-r--r-- | server.go | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/server.go b/server.go new file mode 100644 index 0000000..2675521 --- /dev/null +++ b/server.go @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: 2025 M. Shulhan <ms@kilabit.info> +// SPDX-License-Identifier: GPL-3.0-only + +package lilin + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + libhttp "git.sr.ht/~shulhan/pakakeh.go/lib/http" +) + +const ( + pathAPIServicesSummary = `/lilin/api/services/summary` +) + +const responseTemplateJSON = `{"code":%d,"name":%q,"message":%q}` + +// Server define the HTTP server for APIs and serving web user interface. +type Server struct { + httpd *http.Server + worker *worker + + Options ServerOptions +} + +func NewServer(opts ServerOptions) (srv *Server, err error) { + var logp = `NewServer` + + srv = &Server{ + Options: opts, + worker: newWorker(), + } + + err = srv.Options.init() + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + var mux = http.NewServeMux() + mux.HandleFunc(`GET `+pathAPIServicesSummary, srv.handleServicesSummary) + + srv.httpd = &http.Server{ + Addr: srv.Options.Address, + Handler: mux, + ReadTimeout: 5 * time.Second, + WriteTimeout: 5 * time.Second, + } + return srv, nil +} + +// ListenAndServe start handling request on incoming connections. +func (srv *Server) ListenAndServe() (err error) { + err = srv.httpd.ListenAndServe() + if err != nil { + return fmt.Errorf(`ListenAndServe: %w`, err) + } + return nil +} + +// Shutdown gracefully shuts down the server without interrupting any active +// connections, similar to [http.Server.Shutdown] +func (srv *Server) Shutdown(ctx context.Context) (err error) { + err = srv.httpd.Shutdown(ctx) + if err != nil { + return fmt.Errorf(`Shutdown: %w`, err) + } + return nil +} + +func (srv *Server) handleServicesSummary(resw http.ResponseWriter, req *http.Request) { + var summary = srv.worker.summary() + var resp = libhttp.EndpointResponse{ + Data: summary, + } + var respBody []byte + var err error + + respBody, err = json.Marshal(resp) + if err != nil { + goto fail + } + + resw.WriteHeader(http.StatusOK) + resw.Write(respBody) + return +fail: + resw.WriteHeader(http.StatusInternalServerError) + respBody = []byte(fmt.Sprintf(responseTemplateJSON, + http.StatusInternalServerError, + `ERR_INTERNAL`, + err.Error())) + resw.Write(respBody) +} |
