-
Notifications
You must be signed in to change notification settings - Fork 55
/
local_server.go
112 lines (88 loc) · 2.49 KB
/
local_server.go
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
package cmd
import (
"context"
"embed"
"fmt"
"html/template"
"net/http"
"strings"
"time"
)
type ErrResultTimedOut struct{}
func (e *ErrResultTimedOut) Error() string {
return "timed out waiting for result"
}
type CodeResponse struct {
Code string
State string
Error error
}
type LocalServer struct {
ResultChan chan CodeResponse
srv *http.Server
}
const defaultTimeout = 300000 * time.Millisecond
//go:embed pages
var pages embed.FS
func newLocalServer() (*LocalServer, error) {
ls := &LocalServer{ResultChan: make(chan CodeResponse, 1), srv: &http.Server{Addr: "127.0.0.1:8301"}}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
ls.ResultChan <- CodeResponse{
Code: params.Get("code"),
State: params.Get("state"),
}
templateFile := "pages/success.html"
templateVals := make(map[string]string)
if params.Get("error") != "" {
templateFile = "pages/error.html"
templateVals["error"] = formatURLMsg(params.Get("error"), "Error")
templateVals["error_description"] = formatURLMsg(params.Get("error_description"), "Please contact your administrator for assistance.")
}
t, err := template.ParseFS(pages, templateFile)
if err != nil {
// these templates are static so they should be able to be parsed, but this fallback ensures something is returned
fmt.Fprintf(w, "Something went wrong, please contact your administrator for assistance.")
return
}
if err := t.Execute(w, templateVals); err != nil {
fmt.Fprintf(w, "Something went wrong, please contact your administrator for assistance.")
return
}
})
go func() {
if err := ls.srv.ListenAndServe(); err != nil {
ls.ResultChan <- CodeResponse{Error: err}
}
}()
return ls, nil
}
func (l *LocalServer) wait(timeout time.Duration) (string, string, error) {
var result CodeResponse
timedOut := false
if timeout <= 0 {
timeout = defaultTimeout
}
select {
case result = <-l.ResultChan:
// do nothing
case <-time.After(timeout):
timedOut = true
}
if err := l.srv.Shutdown(context.Background()); err != nil {
return "", "", err
}
if timedOut {
return "", "", &ErrResultTimedOut{}
}
return result.Code, result.State, result.Error
}
// formatURLMsg takes a message from a URL and converts it into an easily readable form
func formatURLMsg(msg string, fallback string) string {
if msg == "" {
return fallback
}
formatted := strings.ReplaceAll(msg, "_", " ")
formatted = strings.Title(strings.ToLower(formatted))
return formatted
}