summaryrefslogtreecommitdiff
path: root/api/serve.go
blob: df30e76284c2b7d2d0630e826e6d0c49a9aa5743 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package api

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"time"

	"git.hatecomputers.club/hatecomputers/hatecomputers.club/args"
	"git.hatecomputers.club/hatecomputers/hatecomputers.club/database"
	"git.hatecomputers.club/hatecomputers/hatecomputers.club/utils"
)

type RequestContext struct {
	DBConn *sql.DB
	Args   *args.Arguments

	Id    string
	Start time.Time

	User *database.User
}

type Continuation func(*RequestContext, *http.Request, http.ResponseWriter) ContinuationChain
type ContinuationChain func(Continuation, Continuation) ContinuationChain

func LogRequestContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain {
	return func(success Continuation, _failure Continuation) ContinuationChain {
		context.Start = time.Now()
		context.Id = utils.RandomId()

		log.Println(req.Method, req.URL.Path, req.RemoteAddr, context.Id)
		return success(context, req, resp)
	}
}

func LogExecutionTimeContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain {
	return func(success Continuation, _failure Continuation) ContinuationChain {
		end := time.Now()

		log.Println(context.Id, "took", end.Sub(context.Start))

		return success(context, req, resp)
	}
}

func HealthCheckContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain {
	return func(success Continuation, _failure Continuation) ContinuationChain {
		resp.WriteHeader(200)
		resp.Write([]byte("healthy"))
		return success(context, req, resp)
	}
}

func FailurePassingContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain {
	return func(_success Continuation, failure Continuation) ContinuationChain {
		return failure(context, req, resp)
	}
}

func IdContinuation(context *RequestContext, req *http.Request, resp http.ResponseWriter) ContinuationChain {
	return func(success Continuation, _failure Continuation) ContinuationChain {
		return success(context, req, resp)
	}
}

func MakeServer(argv *args.Arguments, dbConn *sql.DB) *http.Server {
	mux := http.NewServeMux()

	fileServer := http.FileServer(http.Dir(argv.StaticPath))
	mux.Handle("/static/", http.StripPrefix("/static/", fileServer))

	makeRequestContext := func() *RequestContext {
		return &RequestContext{
			DBConn: dbConn,
			Args:   argv,
		}
	}

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		requestContext := makeRequestContext()
		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(IdContinuation, IdContinuation)(TemplateContinuation("home.html", nil, true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /api/health", func(w http.ResponseWriter, r *http.Request) {
		requestContext := makeRequestContext()
		LogRequestContinuation(requestContext, r, w)(HealthCheckContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /login", func(w http.ResponseWriter, r *http.Request) {
		requestContext := makeRequestContext()
		LogRequestContinuation(requestContext, r, w)(StartSessionContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /auth", func(w http.ResponseWriter, r *http.Request) {
		requestContext := makeRequestContext()
		LogRequestContinuation(requestContext, r, w)(InterceptCodeContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /me", func(w http.ResponseWriter, r *http.Request) {
		requestContext := makeRequestContext()
		LogRequestContinuation(requestContext, r, w)(VerifySessionContinuation, FailurePassingContinuation)(RefreshSessionContinuation, GoLoginContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /logout", func(w http.ResponseWriter, r *http.Request) {
		requestContext := makeRequestContext()
		LogRequestContinuation(requestContext, r, w)(LogoutContinuation, FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /{name}", func(w http.ResponseWriter, r *http.Request) {
		requestContext := makeRequestContext()
		name := r.PathValue("name")
		LogRequestContinuation(requestContext, r, w)(TemplateContinuation(name+".html", nil, true), FailurePassingContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	return &http.Server{
		Addr:    ":" + fmt.Sprint(argv.Port),
		Handler: mux,
	}
}