aboutsummaryrefslogtreecommitdiff
path: root/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'server.go')
-rw-r--r--server.go97
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)
+}