handler index
This commit is contained in:
parent
600cde5279
commit
10bd39d915
|
@ -1 +1,48 @@
|
||||||
package handler
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Index(w http.ResponseWriter) {
|
||||||
|
Message(w, http.StatusOK, "yogai index")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Message(w http.ResponseWriter, status int, message string, details ...any) {
|
||||||
|
w.WriteHeader(status)
|
||||||
|
response := struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Details []any `json:"details,omitempty"`
|
||||||
|
}{
|
||||||
|
Message: message,
|
||||||
|
Details: details,
|
||||||
|
}
|
||||||
|
body, marshalErr := json.Marshal(response)
|
||||||
|
if marshalErr != nil {
|
||||||
|
fmt.Fprintf(w, fmt.Sprintf(`{"message": %q, "details":%q}`, message, marshalErr.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(w http.ResponseWriter, status int, message string, err error, details ...any) {
|
||||||
|
w.WriteHeader(status)
|
||||||
|
response := struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details []any `json:"details,omitempty"`
|
||||||
|
}{
|
||||||
|
Message: message,
|
||||||
|
Error: err.Error(),
|
||||||
|
Details: details,
|
||||||
|
}
|
||||||
|
body, marshalErr := json.Marshal(response)
|
||||||
|
if marshalErr != nil {
|
||||||
|
fmt.Fprintf(w, fmt.Sprintf(`{"message": %q, "error": %q, "details":%q}`, message, err.Error(), marshalErr.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, string(body))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"golang.org/x/exp/slog"
|
||||||
|
"miniflux.app/logger"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
apis map[string]http.Handler
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(logger *slog.Logger) *Server {
|
||||||
|
return &Server{
|
||||||
|
apis: map[string]http.Handler{},
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
originalPath := r.URL.Path
|
||||||
|
rec := httptest.NewRecorder() // records the response to be able to mix writing headers and content
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
// route to api
|
||||||
|
head, tail := ShiftPath(r.URL.Path)
|
||||||
|
if len(head) == 0 {
|
||||||
|
Index(rec)
|
||||||
|
returnResponse(w, rec)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
api, ok := s.apis[head]
|
||||||
|
if !ok {
|
||||||
|
Error(rec, http.StatusNotFound, "Not found", fmt.Errorf("%s is not a valid path", r.URL.Path))
|
||||||
|
} else {
|
||||||
|
r.URL.Path = tail
|
||||||
|
api.ServeHTTP(rec, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
returnResponse(w, rec)
|
||||||
|
logger.Info("request served", "path", originalPath, "status", rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func returnResponse(w http.ResponseWriter, rec *httptest.ResponseRecorder) {
|
||||||
|
w.WriteHeader(rec.Code)
|
||||||
|
for k, v := range rec.Header() {
|
||||||
|
w.Header()[k] = v
|
||||||
|
}
|
||||||
|
w.Write(rec.Body.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShiftPath splits off the first component of p, which will be cleaned of
|
||||||
|
// relative components before processing. head will never contain a slash and
|
||||||
|
// tail will always be a rooted path without trailing slash.
|
||||||
|
// See https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/
|
||||||
|
func ShiftPath(p string) (string, string) {
|
||||||
|
p = path.Clean("/" + p)
|
||||||
|
|
||||||
|
// restore iri prefixes that might be mangled by path.Clean
|
||||||
|
for k, v := range map[string]string{
|
||||||
|
"http:/": "http://",
|
||||||
|
"https:/": "https://",
|
||||||
|
} {
|
||||||
|
p = strings.Replace(p, k, v, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := strings.Index(p[1:], "/") + 1
|
||||||
|
if i <= 0 {
|
||||||
|
return p[1:], "/"
|
||||||
|
}
|
||||||
|
return p[1:i], p[i:]
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
package handler
|
|
15
service.go
15
service.go
|
@ -3,18 +3,23 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"ewintr.nl/yogai/fetcher"
|
"ewintr.nl/yogai/fetcher"
|
||||||
|
"ewintr.nl/yogai/handler"
|
||||||
"ewintr.nl/yogai/storage"
|
"ewintr.nl/yogai/storage"
|
||||||
|
"fmt"
|
||||||
"golang.org/x/exp/slog"
|
"golang.org/x/exp/slog"
|
||||||
"google.golang.org/api/option"
|
"google.golang.org/api/option"
|
||||||
"google.golang.org/api/youtube/v3"
|
"google.golang.org/api/youtube/v3"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
logger := slog.New(slog.NewTextHandler(os.Stderr))
|
logger := slog.New(slog.NewTextHandler(os.Stderr))
|
||||||
|
|
||||||
postgres, err := storage.NewPostgres(storage.PostgresInfo{
|
postgres, err := storage.NewPostgres(storage.PostgresInfo{
|
||||||
Host: getParam("POSTGRES_HOST", "localhost"),
|
Host: getParam("POSTGRES_HOST", "localhost"),
|
||||||
Port: getParam("POSTGRES_PORT", "5432"),
|
Port: getParam("POSTGRES_PORT", "5432"),
|
||||||
|
@ -50,7 +55,15 @@ func main() {
|
||||||
|
|
||||||
fetcher := fetcher.NewFetch(videoRepo, mflx, fetchInterval, yt, openAIClient, logger)
|
fetcher := fetcher.NewFetch(videoRepo, mflx, fetchInterval, yt, openAIClient, logger)
|
||||||
go fetcher.Run()
|
go fetcher.Run()
|
||||||
logger.Info("service started")
|
logger.Info("fetch service started")
|
||||||
|
|
||||||
|
port, err := strconv.Atoi(getParam("API_PORT", "8080"))
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("invalid port", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
go http.ListenAndServe(fmt.Sprintf(":%d", port), handler.NewServer(logger))
|
||||||
|
logger.Info("http server started")
|
||||||
|
|
||||||
done := make(chan os.Signal)
|
done := make(chan os.Signal)
|
||||||
signal.Notify(done, os.Interrupt)
|
signal.Notify(done, os.Interrupt)
|
||||||
|
|
Loading…
Reference in New Issue