mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-06 06:10:54 +00:00
Add documentation to ProcessSingleGetRequest
Make a collectError() function to reduce repetitiveness
This commit is contained in:
parent
a327f6cf57
commit
aca50d9de5
4 changed files with 152 additions and 53 deletions
|
@ -1,9 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"fmt"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConfigFile struct {
|
type ConfigFile struct {
|
||||||
|
@ -71,4 +71,4 @@ func loadConfig() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bitbucket.org/stendec/frankerfacez/socketserver/server"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
"bitbucket.org/stendec/frankerfacez/socketserver/server"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CalendarData struct {
|
type CalendarData struct {
|
||||||
|
@ -14,13 +14,13 @@ type CalWeekData struct {
|
||||||
Days []CalDayData
|
Days []CalDayData
|
||||||
}
|
}
|
||||||
type CalDayData struct {
|
type CalDayData struct {
|
||||||
NoData bool
|
NoData bool
|
||||||
Date int
|
Date int
|
||||||
UniqUsers int
|
UniqUsers int
|
||||||
}
|
}
|
||||||
|
|
||||||
type CalendarMonthInfo struct {
|
type CalendarMonthInfo struct {
|
||||||
Year int
|
Year int
|
||||||
Month time.Month
|
Month time.Month
|
||||||
// Ranges from -5 to +1.
|
// Ranges from -5 to +1.
|
||||||
// A value of +1 means the 1st of the month is a Sunday.
|
// A value of +1 means the 1st of the month is a Sunday.
|
||||||
|
@ -44,10 +44,10 @@ func GetMonthInfo(at time.Time) CalendarMonthInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
return CalendarMonthInfo{
|
return CalendarMonthInfo{
|
||||||
Year: year,
|
Year: year,
|
||||||
Month: month,
|
Month: month,
|
||||||
FirstSundayOffset: monthWeekStartDay,
|
FirstSundayOffset: monthWeekStartDay,
|
||||||
NeedSixSundays: needSixSundays,
|
NeedSixSundays: needSixSundays,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
70
socketserver/cmd/statsweb/servers.go
Normal file
70
socketserver/cmd/statsweb/servers.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
type serverFilter struct {
|
||||||
|
// Mode is false for blacklist, true for whitelist
|
||||||
|
Mode bool
|
||||||
|
Special string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverFilterModeBlacklist = false
|
||||||
|
const serverFilterModeWhitelist = true
|
||||||
|
|
||||||
|
func (sf *serverFilter) IsServerAllowed(server string) {
|
||||||
|
for _, v := range sf.Special {
|
||||||
|
if server == v {
|
||||||
|
return sf.Mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !sf.Mode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *serverFilter) Remove(server string) {
|
||||||
|
if sf.Mode == serverFilterModeWhitelist {
|
||||||
|
var idx int = -1
|
||||||
|
for i, v := range sf.Special {
|
||||||
|
if server == v {
|
||||||
|
idx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx != -1 {
|
||||||
|
var lenMinusOne = len(sf.Special)-1
|
||||||
|
sf.Special[idx] = sf.Special[lenMinusOne]
|
||||||
|
sf.Special = sf.Special[:lenMinusOne]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, v := range sf.Special {
|
||||||
|
if server == v {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sf.Special = append(sf.Special, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *serverFilter) Add(server string) {
|
||||||
|
if sf.Mode == serverFilterModeBlacklist {
|
||||||
|
var idx int = -1
|
||||||
|
for i, v := range sf.Special {
|
||||||
|
if server == v {
|
||||||
|
idx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx != -1 {
|
||||||
|
var lenMinusOne = len(sf.Special)-1
|
||||||
|
sf.Special[idx] = sf.Special[lenMinusOne]
|
||||||
|
sf.Special = sf.Special[:lenMinusOne]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, v := range sf.Special {
|
||||||
|
if server == v {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sf.Special = append(sf.Special, server)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverFilterAll serverFilter = serverFilter{Mode: serverFilterModeBlacklist}
|
||||||
|
const serverFilterNone serverFilter = serverFilter{Mode: serverFilterModeWhitelist}
|
|
@ -30,13 +30,14 @@ func main() {
|
||||||
|
|
||||||
loadConfig()
|
loadConfig()
|
||||||
|
|
||||||
http.HandleFunc("/api", ServeAPI)
|
http.HandleFunc("/api/get", ServeAPIGet)
|
||||||
http.ListenAndServe(config.ListenAddr, http.DefaultServeMux)
|
http.ListenAndServe(config.ListenAddr, http.DefaultServeMux)
|
||||||
}
|
}
|
||||||
|
|
||||||
const RequestURIName = "q"
|
const RequestURIName = "q"
|
||||||
const separatorRange = "~"
|
const separatorRange = "~"
|
||||||
const separatorAdd = " "
|
const separatorAdd = " "
|
||||||
|
const separatorServer = "@"
|
||||||
const jsonErrMalformedRequest = `{"status":"error","error":"malformed request uri"}`
|
const jsonErrMalformedRequest = `{"status":"error","error":"malformed request uri"}`
|
||||||
const jsonErrBlankRequest = `{"status":"error","error":"no queries given"}`
|
const jsonErrBlankRequest = `{"status":"error","error":"no queries given"}`
|
||||||
const statusError = "error"
|
const statusError = "error"
|
||||||
|
@ -53,15 +54,7 @@ type requestResponse struct {
|
||||||
Count uint64 `json:"count,omitempty"`
|
Count uint64 `json:"count,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type serverFilter struct {
|
func ServeAPIGet(w http.ResponseWriter, r *http.Request) {
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
func (sf *serverFilter) IsServerAllowed(server string) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
const serverFilterAll serverFilter
|
|
||||||
|
|
||||||
func ServeAPI(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
u, err := url.ParseRequestURI(r.RequestURI)
|
u, err := url.ParseRequestURI(r.RequestURI)
|
||||||
|
@ -82,7 +75,10 @@ func ServeAPI(w http.ResponseWriter, r *http.Request) {
|
||||||
resp := apiResponse{Status: statusOk}
|
resp := apiResponse{Status: statusOk}
|
||||||
resp.Responses = make([]requestResponse, reqCount)
|
resp.Responses = make([]requestResponse, reqCount)
|
||||||
for i, v := range query[RequestURIName] {
|
for i, v := range query[RequestURIName] {
|
||||||
resp.Responses[i] = processSingleRequest(v)
|
if len(v) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resp.Responses[i] = ProcessSingleGetRequest(v)
|
||||||
}
|
}
|
||||||
for _, v := range resp.Responses {
|
for _, v := range resp.Responses {
|
||||||
if v.Status == statusError {
|
if v.Status == statusError {
|
||||||
|
@ -96,20 +92,61 @@ func ServeAPI(w http.ResponseWriter, r *http.Request) {
|
||||||
enc.Encode(resp)
|
enc.Encode(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
const errRangeFormatIncorrect = "incorrect range format, must be yyyy-mm-dd~yyyy-mm-dd"
|
const errRangeFormatIncorrect = errors.New("incorrect range format, must be yyyy-mm-dd~yyyy-mm-dd")
|
||||||
|
|
||||||
func processSingleRequest(req string) (result requestResponse) {
|
// ProcessSingleGetRequest takes a request string and pulls the unique user data for the given dates and filters.
|
||||||
// Forms:
|
//
|
||||||
// Single: 2016-01-02
|
// The request string is in the following format:
|
||||||
// Range: 2016-01-03~2016-01-09
|
//
|
||||||
// Add disparate: 2016-01-02 2016-01-03 2016-01-09 2016-01-10
|
// Request = AddDateRanges [ "@" ServerFilter ] .
|
||||||
// NOTE: Spaces are uri-encoded as +
|
// ServerFilter = [ "!" ] ServerName { " " ServerName } .
|
||||||
// Add ranges: 2016-01-04~2016-01-08 2016-01-11~2016-01-15
|
// ServerName = { "a" … "z" } .
|
||||||
|
// AddDateRanges = DateMaybeRange { " " DateMaybeRange } .
|
||||||
|
// DateMaybeRange = DateRange | Date .
|
||||||
|
// DateRange = Date "~" Date .
|
||||||
|
// Date = Year "-" Month "-" Day .
|
||||||
|
// Year = number number number number .
|
||||||
|
// Month = number number .
|
||||||
|
// Day = number number .
|
||||||
|
// number = "0" … "9" .
|
||||||
|
//
|
||||||
|
// Example of a well-formed request:
|
||||||
|
//
|
||||||
|
// 2016-01-04~2016-01-08 2016-01-11~2016-01-15@andknuckles tuturu
|
||||||
|
//
|
||||||
|
// Remember that spaces are urlencoded as "+", so the HTTP request to send to retrieve that data would be this:
|
||||||
|
//
|
||||||
|
// /api/get?q=2016-01-04~2016-01-08+2016-01-11~2016-01-15%40andknuckles+tuturu
|
||||||
|
//
|
||||||
|
// If a ServerFilter is specified, only users connecting to the specified servers will be included in the count.
|
||||||
|
//
|
||||||
|
// It does not matter if a date is specified multiple times, due to the data format used.
|
||||||
|
func ProcessSingleGetRequest(req string) (result requestResponse) {
|
||||||
var hll hyperloglog.HyperLogLogPlus, _ = hyperloglog.NewPlus(server.CounterPrecision)
|
var hll hyperloglog.HyperLogLogPlus, _ = hyperloglog.NewPlus(server.CounterPrecision)
|
||||||
addSplit := strings.Split(req, separatorAdd)
|
|
||||||
|
|
||||||
result.Request = req
|
result.Request = req
|
||||||
result.Status = statusOk
|
result.Status = statusOk
|
||||||
|
filter := serverFilterAll
|
||||||
|
|
||||||
|
collectError := func(err error) bool {
|
||||||
|
if err != nil {
|
||||||
|
result.Status = statusError
|
||||||
|
result.Error = err.Error()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
serverSplit := strings.Split(req, separatorServer)
|
||||||
|
if len(serverSplit) == 2 {
|
||||||
|
filter = serverFilterNone
|
||||||
|
serversOnly := strings.Split(serverSplit[1], separatorAdd)
|
||||||
|
for _, v := range serversOnly {
|
||||||
|
filter.Add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addSplit := strings.Split(serverSplit[0], separatorAdd)
|
||||||
|
|
||||||
outerLoop:
|
outerLoop:
|
||||||
for _, split1 := range addSplit {
|
for _, split1 := range addSplit {
|
||||||
|
@ -119,40 +156,31 @@ func processSingleRequest(req string) (result requestResponse) {
|
||||||
|
|
||||||
rangeSplit := strings.Split(split1, separatorRange)
|
rangeSplit := strings.Split(split1, separatorRange)
|
||||||
if len(rangeSplit) == 1 {
|
if len(rangeSplit) == 1 {
|
||||||
at, err := parseDate(rangeSplit[0])
|
at, err := parseDateFromRequest(rangeSplit[0])
|
||||||
if err != nil {
|
if collectError(err) {
|
||||||
result.Status = statusError
|
|
||||||
result.Error = err.Error()
|
|
||||||
break outerLoop
|
break outerLoop
|
||||||
}
|
}
|
||||||
err = addSingleDate(at, serverFilterAll, &hll)
|
|
||||||
if err != nil {
|
err = addSingleDate(at, filter, &hll)
|
||||||
result.Status = statusError
|
if collectError(err) {
|
||||||
result.Error = err.Error()
|
|
||||||
break outerLoop
|
break outerLoop
|
||||||
}
|
}
|
||||||
} else if len(rangeSplit) == 2 {
|
} else if len(rangeSplit) == 2 {
|
||||||
from, err := parseDate(rangeSplit[0])
|
from, err := parseDateFromRequest(rangeSplit[0])
|
||||||
if err != nil {
|
if collectError(err) {
|
||||||
result.Status = statusError
|
|
||||||
result.Error = err.Error()
|
|
||||||
break outerLoop
|
break outerLoop
|
||||||
}
|
}
|
||||||
to, err := parseDate(rangeSplit[1])
|
to, err := parseDateFromRequest(rangeSplit[1])
|
||||||
if err != nil {
|
if collectError(err) {
|
||||||
result.Status = statusError
|
|
||||||
result.Error = err.Error()
|
|
||||||
break outerLoop
|
break outerLoop
|
||||||
}
|
}
|
||||||
err = addRange(from, to, serverFilterAll, &hll)
|
|
||||||
if err != nil {
|
err = addRange(from, to, filter, &hll)
|
||||||
result.Status = statusError
|
if collectError(err) {
|
||||||
result.Error = err.Error()
|
|
||||||
break outerLoop
|
break outerLoop
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.Status = statusError
|
collectError(errRangeFormatIncorrect)
|
||||||
result.Error = errRangeFormatIncorrect
|
|
||||||
break outerLoop
|
break outerLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,7 +194,7 @@ func processSingleRequest(req string) (result requestResponse) {
|
||||||
var errBadDate = errors.New("bad date format, must be yyyy-mm-dd")
|
var errBadDate = errors.New("bad date format, must be yyyy-mm-dd")
|
||||||
var zeroTime = time.Unix(0, 0)
|
var zeroTime = time.Unix(0, 0)
|
||||||
|
|
||||||
func parseDate(dateStr string) (time.Time, error) {
|
func parseDateFromRequest(dateStr string) (time.Time, error) {
|
||||||
var year, month, day int
|
var year, month, day int
|
||||||
n, err := fmt.Sscanf(dateStr, "%d-%d-%d", &year, &month, &day)
|
n, err := fmt.Sscanf(dateStr, "%d-%d-%d", &year, &month, &day)
|
||||||
if err != nil || n != 3 {
|
if err != nil || n != 3 {
|
||||||
|
@ -182,6 +210,7 @@ func addSingleDate(at time.Time, filter serverFilter, dest *hyperloglog.HyperLog
|
||||||
|
|
||||||
func addRange(start time.Time, end time.Time, filter serverFilter, dest *hyperloglog.HyperLogLogPlus) error {
|
func addRange(start time.Time, end time.Time, filter serverFilter, dest *hyperloglog.HyperLogLogPlus) error {
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func combineDateRange(from time.Time, to time.Time, dest *hyperloglog.HyperLogLogPlus) error {
|
func combineDateRange(from time.Time, to time.Time, dest *hyperloglog.HyperLogLogPlus) error {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue