<commit_before>package router

import (
	"encoding/json"
	"errors"
	"log"
	"net/http"

	"github.com/oursky/ourd/oderr"
)

// Handler specifies the function signature of a request handler function
type Handler func(*Payload, *Response)

// pipeline encapsulates a transformation which a request will come throught
// from preprocessors to the actual handler. (and postprocessor later)
type pipeline struct {
	Action        string
	Preprocessors []Processor
	Handler
}

// Router to dispatch HTTP request to respective handler
type Router struct {
	actions map[string]pipeline
}

// Processor specifies the function signature for a Preprocessor
type Processor func(*Payload, *Response) int

// NewRouter is factory for Router
func NewRouter() *Router {
	return &Router{actions: make(map[string]pipeline)}
}

// Map to register action to handle mapping
func (r *Router) Map(action string, handler Handler, preprocessors ...Processor) {
	r.actions[action] = pipeline{
		Action:        action,
		Preprocessors: preprocessors,
		Handler:       handler,
	}
}

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var (
		httpStatus = http.StatusOK
		reqJSON    map[string]interface{}
		resp       Response
	)
	defer func() {
		w.WriteHeader(httpStatus)
		if err := json.NewEncoder(w).Encode(resp); err != nil {
			panic(err)
		}
	}()

	if err := json.NewDecoder(req.Body).Decode(&reqJSON); err != nil {
		httpStatus = http.StatusBadRequest
		resp.Err = oderr.NewFmt(oderr.RequestInvalidErr, err.Error())
		return
	}

	payload := Payload{
		Meta: map[string]interface{}{},
		Data: reqJSON,
	}

	if pipeline, ok := r.actions[payload.RouteAction()]; ok {
		for _, p := range pipeline.Preprocessors {
			httpStatus = p(&payload, &resp)
			if resp.Err != nil {
				if httpStatus == 200 {
					httpStatus = 500
				}
				if _, ok := resp.Err.(oderr.Error); !ok {
					resp.Err = oderr.New(oderr.UnknownErr, resp.Err.Error())
				}
				return
			}
		}
		pipeline.Handler(&payload, &resp)
	} else {
		httpStatus = http.StatusNotFound
		resp.Err = oderr.New(oderr.RequestInvalidErr, "Unmatched Route")<commit_msg>Treat empty request as empty map in router, #23<commit_after>package router

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"

	"github.com/oursky/ourd/oderr"
)

// Handler specifies the function signature of a request handler function
type Handler func(*Payload, *Response)

// pipeline encapsulates a transformation which a request will come throught
// from preprocessors to the actual handler. (and postprocessor later)
type pipeline struct {
	Action        string
	Preprocessors []Processor
	Handler
}

// Router to dispatch HTTP request to respective handler
type Router struct {
	actions map[string]pipeline
}

// Processor specifies the function signature for a Preprocessor
type Processor func(*Payload, *Response) int

// NewRouter is factory for Router
func NewRouter() *Router {
	return &Router{actions: make(map[string]pipeline)}
}

// Map to register action to handle mapping
func (r *Router) Map(action string, handler Handler, preprocessors ...Processor) {
	r.actions[action] = pipeline{
		Action:        action,
		Preprocessors: preprocessors,
		Handler:       handler,
	}
}

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var (
		httpStatus = http.StatusOK
		reqJSON    map[string]interface{}
		resp       Response
	)
	defer func() {
		w.WriteHeader(httpStatus)
		if err := json.NewEncoder(w).Encode(resp); err != nil {
			panic(err)
		}
	}()

	if err := json.NewDecoder(req.Body).Decode(&reqJSON); err != nil {
		if err == io.EOF {
			reqJSON = map[string]interface{}{}
		} else {
			httpStatus = http.StatusBadRequest
			resp.Err = oderr.NewFmt(oderr.RequestInvalidErr, err.Error())
			return
		}
	}

	payload := Payload{
		Meta: map[string]interface{}{},
		Data: reqJSON,
	}

	if pipeline, ok := r.actions[payload.RouteAction()]; ok {
		for _, p := range pipeline.Preprocessors {
			httpStatus = p(&payload, &resp)
			if resp.Err != nil {
				if httpStatus == 200 {
					httpStatus = 500
				}
				if _, ok := resp.Err.(oderr.Error); !ok {
					resp.Err = oderr.New(oderr.UnknownErr, resp.Err.Error())
				}
				return
			}
		}
		pipeline.Handler(&payload, &resp)
	} else {
		httpStatus = http.StatusNotFound
		resp.Err = oderr.New(oderr.RequestInvalidErr, "Unmatched Route")
{'fraction_non_alphanumeric': 0.11956771671648656, 'fraction_numerical': 0.0032191308346746377, 'mean_word_length': 3.697624190064795, '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': '7010654', 'n_tokens_mistral': 1511, 'n_tokens_neox': 1372, 'n_words': 388}