summaryrefslogtreecommitdiff
path: root/api/serve.go
blob: dad50099e1eb0573e475c66cb29f92adee1ad4c5 (plain) (blame)
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package api

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

	"penguins.lan/api/auth"
	"penguins.lan/api/canvas"
	"penguins.lan/api/devices"
	"penguins.lan/api/dns"
	"penguins.lan/api/minecraft"
	"penguins.lan/api/presence"
	"penguins.lan/api/template"
	"penguins.lan/api/types"
	"penguins.lan/api/ws"
	"penguins.lan/args"
	"penguins.lan/utils"
)

func LogRequestContinuation(context *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
	return func(success types.Continuation, _failure types.Continuation) types.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 *types.RequestContext, req *http.Request, resp http.ResponseWriter) types.ContinuationChain {
	return func(success types.Continuation, _failure types.Continuation) types.ContinuationChain {
		log.Println(context.Id, "took", time.Since(context.Start))
		return success(context, req, resp)
	}
}

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

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

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

func CacheControlMiddleware(next http.Handler, maxAge int) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", maxAge))
		next.ServeHTTP(w, r)
	})
}

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

	hub := ws.NewHub(dbConn)
	go hub.Run()

	canvasHub := canvas.NewHub(dbConn)
	go canvasHub.Run()

	makeRequestContext := func() *types.RequestContext {
		return &types.RequestContext{
			DBConn:       dbConn,
			Args:         argv,
			TemplateData: &map[string]interface{}{},
		}
	}

	staticFileServer := http.FileServer(http.Dir(argv.StaticPath))
	mux.Handle("GET /static/", http.StripPrefix("/static/", CacheControlMiddleware(staticFileServer, 3600)))

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

	mux.HandleFunc("GET /portal", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.ShowPortalContinuation, FailurePassingContinuation)(template.TemplateContinuation("portal.html", true), IdContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("POST /portal", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.SetupUserContinuation, FailurePassingContinuation)(IdContinuation, template.TemplateContinuation("portal.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /profile", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(devices.ListDevicesContinuation, auth.GoPortalContinuation)(dns.ListDNSRecordsContinuation, FailurePassingContinuation)(template.TemplateContinuation("profile.html", true), auth.GoPortalContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("POST /profile/primary", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(devices.SetPrimaryContinuation, auth.GoPortalContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /dns", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/profile", http.StatusSeeOther)
	})

	mux.HandleFunc("POST /dns", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(devices.ListDevicesContinuation, auth.GoPortalContinuation)(dns.ListDNSRecordsContinuation, auth.GoPortalContinuation)(dns.CreateDNSRecordContinuation, auth.GoPortalContinuation)(IdContinuation, template.TemplateContinuation("profile.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("POST /dns/delete", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(devices.ListDevicesContinuation, auth.GoPortalContinuation)(dns.ListDNSRecordsContinuation, auth.GoPortalContinuation)(dns.DeleteDNSRecordContinuation, auth.GoPortalContinuation)(IdContinuation, template.TemplateContinuation("profile.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

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

	mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(presence.RosterContinuation(hub), FailurePassingContinuation)(canvas.PageContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(template.TemplateContinuation("home.html", true), auth.GoPortalContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("POST /rename", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(presence.RosterContinuation(hub), auth.GoPortalContinuation)(auth.RenameContinuation, auth.GoPortalContinuation)(IdContinuation, template.TemplateContinuation("home.html", true))(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /waddlers", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(presence.StatusContinuation(hub), auth.UnauthorizedContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /canvas/state", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(canvas.StateContinuation, auth.UnauthorizedContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /canvas/ws", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(canvas.ServeWSContinuation(canvasHub), auth.UnauthorizedContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /minecraft", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(minecraft.StatusContinuation, auth.UnauthorizedContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /chat", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(template.TemplateContinuation("chat.html", true), auth.GoPortalContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /ws", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(ws.ServeWSContinuation(hub), auth.UnauthorizedContinuation)(IdContinuation, IdContinuation)
	})

	mux.HandleFunc("GET /{template}", func(w http.ResponseWriter, r *http.Request) {
		ctx := makeRequestContext()
		templateFile := r.PathValue("template")
		LogRequestContinuation(ctx, r, w)(auth.ResolveSessionContinuation, FailurePassingContinuation)(auth.RequireUserContinuation, FailurePassingContinuation)(template.TemplateContinuation(templateFile+".html", true), auth.GoPortalContinuation)(LogExecutionTimeContinuation, LogExecutionTimeContinuation)(IdContinuation, IdContinuation)
	})

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