-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
api.go
131 lines (113 loc) · 3.21 KB
/
api.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
json2 "encoding/json"
"fmt"
"log"
"strconv"
"time"
"github.com/ferluci/fast-realip"
"github.com/valyala/fasthttp"
)
var (
apiBeatPath = "/api/beat"
apiUpdateStatsPath = "/api/update/stats"
apiUpdateDevicesPath = "/api/update/devices"
apiInfoPath = "/api/info"
apiStatsPath = "/api/stats"
apiDevicesPath = "/api/devices"
jsonMime = "application/json"
)
func ApiHandler(ctx *fasthttp.RequestCtx, path string) {
switch path {
case apiBeatPath, apiUpdateStatsPath, apiUpdateDevicesPath:
if !ctx.IsPost() {
ErrorBadRequest(ctx, true)
return
}
// The authentication key provided with said Auth header
header := ctx.Request.Header.Peek("Auth")
// Make sure Auth key is correct
if string(header) != authToken {
ErrorForbidden(ctx, true)
return
}
case apiInfoPath, apiStatsPath, apiDevicesPath:
if !ctx.IsGet() {
ErrorBadRequest(ctx, true)
return
}
if string(ctx.QueryArgs().Peek("countVisit")) != "false" {
heartbeatStats.TotalVisits += 1
heartbeatStats.TotalVisitsFormatted = FormattedNum(heartbeatStats.TotalVisits)
}
}
switch path {
case apiBeatPath:
HandleSuccessfulBeat(ctx)
case apiUpdateStatsPath:
handleUpdateStats(ctx)
case apiUpdateDevicesPath:
handleUpdateDevices(ctx)
case apiInfoPath:
handleJsonObject(ctx, FormattedInfo())
case apiStatsPath:
UpdateUptime()
UpdateNumDevices()
UpdateLastBeatFmt()
handleJsonObject(ctx, heartbeatStats)
case apiDevicesPath:
handleJsonObject(ctx, heartbeatDevices)
default:
ErrorBadRequest(ctx, true)
}
}
// handleUpdateStats will allow authenticated users to replace the current stats
func handleUpdateStats(ctx *fasthttp.RequestCtx) {
var stats HeartbeatStats
err := json2.Unmarshal(ctx.PostBody(), &stats)
if err != nil {
HandleClientErr(ctx, "Error unmarshalling json", err)
return
}
heartbeatStats = &stats
HandleSuccess(ctx)
}
// handleUpdateDevices will allow authenticated users to replace the current devices
func handleUpdateDevices(ctx *fasthttp.RequestCtx) {
var devices []HeartbeatDevice
err := json2.Unmarshal(ctx.PostBody(), &devices)
if err != nil {
HandleClientErr(ctx, "Error unmarshalling json", err)
return
}
heartbeatDevices = &devices
HandleSuccess(ctx)
}
// handleJsonObject will print the raw json of v
func handleJsonObject(ctx *fasthttp.RequestCtx, v interface{}) {
json, err := json2.MarshalIndent(v, "", " ")
if err != nil {
HandleInternalErr(ctx, "Error formatting json", err)
return
}
ctx.Response.Header.SetContentType(jsonMime)
_, _ = fmt.Fprintf(ctx, "%s\n", json)
}
// HandleSuccessfulBeat will update the db's Device with the new last beat, and print the last beat's unix timestamp
func HandleSuccessfulBeat(ctx *fasthttp.RequestCtx) {
device := ctx.Request.Header.Peek("Device")
// Make sure a device is set
if len(device) == 0 {
ErrorBadRequest(ctx, true)
return
}
timestamp := time.Now().Unix()
timestampStr := strconv.FormatInt(timestamp, 10)
err := UpdateLastBeat(string(device), timestamp)
if err != nil {
HandleInternalErr(ctx, "Error updating last beat", err)
return
}
_, _ = fmt.Fprintf(ctx, "%v\n", timestampStr)
log.Printf("- Successful beat from %s", realip.FromRequest(ctx))
}