package tubson import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "os" "os/signal" "strings" "syscall" ) type Http_method uint8; const ( GET Http_method = iota POST PATCH PUT DELETE ) func (method Http_method) to_string() string { switch method { case GET: return http.MethodGet case POST: return http.MethodPost case PATCH: return http.MethodPatch case PUT: return http.MethodPut case DELETE: return http.MethodDelete } return "" } type Http_status_code int; const ( OK Http_status_code = http.StatusOK INTERNAL_SERVER_ERROR Http_status_code = http.StatusInternalServerError BAD_REQUEST Http_status_code = http.StatusBadRequest ) type Empty_request_body struct {} /* T Representing any request body struct S Representing any response body struct */ func New_endpoint[T any, S any](method Http_method, route string, endpoint string, handle_func func(body T, raw_request *http.Request) (S, Http_status_code)) { http.HandleFunc(method.to_string() + " /" + route + endpoint, func(response http.ResponseWriter, request *http.Request) { request_body_bytes, err := io.ReadAll(request.Body) if err != nil { response.WriteHeader(int(INTERNAL_SERVER_ERROR)) log.Panicln(err) return } var decode_result T if len(request_body_bytes) != 0 { decoder := json.NewDecoder(strings.NewReader(string(request_body_bytes))) decoder.DisallowUnknownFields() err = decoder.Decode(&decode_result) if err != nil { response.WriteHeader(int(BAD_REQUEST)) response.Write([]byte(err.Error())) log.Println(err) return } } body, status_code := handle_func(decode_result, request) encode_result, err := json.Marshal(body) if err != nil { response.WriteHeader(int(INTERNAL_SERVER_ERROR)) log.Panicln(err) return } response.WriteHeader(int(status_code)) response.Write(encode_result) }) } func Start_server(http_server *http.Server, cleanup func()) { go func() { log.Fatal(http_server.ListenAndServe()) }() fmt.Println("Timefu.li server started! Listening in on ", http_server.Addr) sigs := make(chan os.Signal, 1) signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) <-sigs fmt.Println("Exit called, attempting to stop server!") ctx := context.Background() http_server.Shutdown(ctx) cleanup() os.Exit(1) }