<commit_before>package api

import (
	"encoding/json"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"time"
)

type Config map[string]interface{}
type HandlerFunc func(w http.ResponseWriter, r *http.Request)

type Router interface {
	Get(string, http.Handler)
	Head(string, http.Handler)
	Post(string, http.Handler)
	Put(string, http.Handler)
	Delete(string, http.Handler)
	http.Handler
}

type APIError struct {
	ApiStatus int    `json:"api_status"`
	Message   string `json:"message"`
}

type APIErrors struct {
	ApiStatus int         `json:"api_status"`
	Errors    []*APIError `json:"errors"`
}

type Api struct {
	Router         Router
	Config         Config
	ReadTimeout    time.Duration
	WriteTimeout   time.Duration
	MaxHeaderBytes int
}

func NewApi(router Router) *Api {
	api := &Api{Router: router, Config: Config{}}
	return api
}

// --- routing helper ---

func (api *Api) Get(path string, f HandlerFunc) {
	api.Router.Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "apilication/json; charset=utf-8")
		f(w, r)
	}))
}

func (api *Api) Post(path string, f HandlerFunc) {
	api.Router.Post(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "apilication/json; charset=utf-8")
		f(w, r)
	}))
}

func (api *Api) Put(path string, f HandlerFunc) {
	api.Router.Put(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "apilication/json; charset=utf-8")
		f(w, r)
	}))
}

func (api *Api) Delete(path string, f HandlerFunc) {
	api.Router.Delete(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "apilication/json; charset=utf-8")
		f(w, r)
	}))
}

// --- error helper ---

// write `{message: "error content"}` with http-status-code:http.StatusInternalServerError
func (api *Api) Error(w http.ResponseWriter, err error) {
	api.ErrorWithHttpStatusAndApiStatus(w, err, http.StatusInternalServerError, 0)
}

// write `{message: "error content"}` with http-status-code
func (api *Api) ErrorWithHttpStatus(w http.ResponseWriter, err error, httpStatus int) {
	api.ErrorWithHttpStatusAndApiStatus(w, err, httpStatus, 0)
}

// write `{message: "error content"}` with http-status-code and api-status-code
func (api *Api) ErrorWithHttpStatusAndApiStatus(w http.ResponseWriter, err error, httpStatus, apiStatus int) {
	log.Print(err.Error())

	j, marchalError := json.Marshal(&APIError{Message: err.Error(), ApiStatus: apiStatus})

	if marchalError != nil {
		panic(marchalError)
	}

	w.Header().Set("Content-Type", "apilication/json; charset=utf-8")
	http.Error(w, string(j), httpStatus)
}

// write `{errors: [{message: "error content"}, {message: "error content"}]}` with http-status-code:http.StatusInternalServerError
func (api *Api) Errors(w http.ResponseWriter, errs []error) {
	api.ErrorsWithHttpStatusAndApiStatus(w, errs, http.StatusInternalServerError, 0)
}

// write `{errors: [{message: "error content"}, {message: "error content"}]}` with http-status-code
func (api *Api) ErrorsWithHttpStatus(w http.ResponseWriter, errs []error, httpStatus int) {
	api.ErrorsWithHttpStatusAndApiStatus(w, errs, httpStatus, 0)
}

// write `{errors: [{message: "error content"}, {message: "error content"}]}` with http-status-code and api-status-code
func (api *Api) ErrorsWithHttpStatusAndApiStatus(w http.ResponseWriter, errs []error, httpStatus, apiStatus int) {
	apiErrors := &APIErrors{ApiStatus: apiStatus}

	for _, err := range errs {
		log.Print(err.Error())
		apiErrors.Errors = append(apiErrors.Errors, &APIError{Message: err.Error()})
	}

	j, marchalError := json.Marshal(apiErrors)

	if marchalError != nil {
		panic(marchalError)
	}

	w.Header().Set("Content-Type", "apilication/json; charset=utf-8")
	http.Error(w, string(j), httpStatus)
}

// --- server helper ---

func (api *Api) Run(addr string) {
	s := &http.Server{
		Addr:           addr,
		Handler:        api.Router,
		ReadTimeout:    api.ReadTimeout,
		WriteTimeout:   api.WriteTimeout,
		MaxHeaderBytes: api.MaxHeaderBytes,
	}

	// notify signal Interrupt to channel c
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	listener, err := net.Listen("tcp", addr)

	if err != nil {
		log.Fatalf("Could not listen: %s", addr)
	}

	go func() {
		for _ = range c {
			// sig is a ^C, handle it
			log.Print("Stopping the server...")
			listener.Close()

			log.Print("Tearing down...")
			log.Fatal("Finished - bye bye.  ;-)")

		}
	}()

	log.Printf("HTTP Server: %s", addr)

	log.Fatalf("Error in Serve: %s", s.Serve(listener))
}
<commit_msg>Push out signal handling to out of this lib<commit_after>package api

import (
	"encoding/json"
	"log"
	"net"
	"net/http"
	"time"
)

type Config map[string]interface{}
type HandlerFunc func(w http.ResponseWriter, r *http.Request)

type Router interface {
	Get(string, http.Handler)
	Head(string, http.Handler)
	Post(string, http.Handler)
	Put(string, http.Handler)
	Delete(string, http.Handler)
	http.Handler
}

type APIError struct {
	ApiStatus int    `json:"api_status"`
	Message   string `json:"message"`
}

type APIErrors struct {
	ApiStatus int         `json:"api_status"`
	Errors    []*APIError `json:"errors"`
}

type Api struct {
	Router         Router
	Config         Config
	ReadTimeout    time.Duration
	WriteTimeout   time.Duration
	MaxHeaderBytes int
	Listener       net.Listener
	Server         *http.Server
}

func NewApi(router Router) *Api {
	api := &Api{Router: router, Config: Config{}}
	return api
}

// --- routing helper ---

func (api *Api) Get(path string, f HandlerFunc) {
	api.Router.Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		f(w, r)
	}))
}

func (api *Api) Post(path string, f HandlerFunc) {
	api.Router.Post(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		f(w, r)
	}))
}

func (api *Api) Put(path string, f HandlerFunc) {
	api.Router.Put(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		f(w, r)
	}))
}

func (api *Api) Delete(path string, f HandlerFunc) {
	api.Router.Delete(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		f(w, r)
	}))
}

// --- error helper ---

// write `{message: "error content"}` with http-status-code:http.StatusInternalServerError
func (api *Api) Error(w http.ResponseWriter, err error) {
	api.ErrorWithHttpStatusAndApiStatus(w, err, http.StatusInternalServerError, 0)
}

// write `{message: "error content"}` with http-status-code
func (api *Api) ErrorWithHttpStatus(w http.ResponseWriter, err error, httpStatus int) {
	api.ErrorWithHttpStatusAndApiStatus(w, err, httpStatus, 0)
}

// write `{message: "error content"}` with http-status-code and api-status-code
func (api *Api) ErrorWithHttpStatusAndApiStatus(w http.ResponseWriter, err error, httpStatus, apiStatus int) {
	log.Print(err.Error())

	j, marchalError := json.Marshal(&APIError{Message: err.Error(), ApiStatus: apiStatus})

	if marchalError != nil {
		panic(marchalError)
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	http.Error(w, string(j), httpStatus)
}

// write `{errors: [{message: "error content"}, {message: "error content"}]}` with http-status-code:http.StatusInternalServerError
func (api *Api) Errors(w http.ResponseWriter, errs []error) {
	api.ErrorsWithHttpStatusAndApiStatus(w, errs, http.StatusInternalServerError, 0)
}

// write `{errors: [{message: "error content"}, {message: "error content"}]}` with http-status-code
func (api *Api) ErrorsWithHttpStatus(w http.ResponseWriter, errs []error, httpStatus int) {
	api.ErrorsWithHttpStatusAndApiStatus(w, errs, httpStatus, 0)
}

// write `{errors: [{message: "error content"}, {message: "error content"}]}` with http-status-code and api-status-code
func (api *Api) ErrorsWithHttpStatusAndApiStatus(w http.ResponseWriter, errs []error, httpStatus, apiStatus int) {
	apiErrors := &APIErrors{ApiStatus: apiStatus}

	for _, err := range errs {
		log.Print(err.Error())
		apiErrors.Errors = append(apiErrors.Errors, &APIError{Message: err.Error()})
	}

	j, marchalError := json.Marshal(apiErrors)

	if marchalError != nil {
		panic(marchalError)
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	http.Error(w, string(j), httpStatus)
}

// --- server helper ---

func (api *Api) Run(l net.Listener) {
	var err error

	api.Listener = l
	api.Server = &http.Server{
		Handler:        api.Router,
		ReadTimeout:    api.ReadTimeout,
		WriteTimeout:   api.WriteTimeout,
		MaxHeaderBytes: api.MaxHeaderBytes,
	}

	if err != nil {
		log.Fatalf("Could not listen: %s", api.Listener)
	}

	log.Printf("HTTP Server: %s", api.Listener.Addr())

	// Serve
	log.Fatalf("Error in Serve: %s", api.Server.Serve(api.Listener))
}

func (api *Api) Stop() {
	api.Listener.Close()
}

{'fraction_non_alphanumeric': 0.15644610811405923, 'fraction_numerical': 0.0023120114499614666, 'mean_word_length': 4.49546279491833, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2660666', 'n_tokens_mistral': 3231, 'n_tokens_neox': 3125, 'n_words': 745}