mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-10 16:10:55 +00:00
Start of statsweb program
This commit is contained in:
parent
56b86ad4e3
commit
9fc946e373
7 changed files with 130 additions and 10 deletions
3
socketserver/cmd/statsweb/.gitignore
vendored
Normal file
3
socketserver/cmd/statsweb/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
database.sqlite
|
||||||
|
gobcache/
|
||||||
|
statsweb
|
74
socketserver/cmd/statsweb/config.go
Normal file
74
socketserver/cmd/statsweb/config.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"fmt"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigFile struct {
|
||||||
|
ListenAddr string
|
||||||
|
DatabaseLocation string
|
||||||
|
GobFilesLocation string
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeConfig() {
|
||||||
|
config.ListenAddr = "localhost:3000"
|
||||||
|
home, ok := os.LookupEnv("HOME")
|
||||||
|
if ok {
|
||||||
|
config.DatabaseLocation = fmt.Sprintf("%s/.ffzstatsweb/database.sqlite", home)
|
||||||
|
config.GobFilesLocation = fmt.Sprintf("%s/.ffzstatsweb/gobcache", home)
|
||||||
|
os.MkdirAll(config.GobFilesLocation, 0644)
|
||||||
|
} else {
|
||||||
|
config.DatabaseLocation = "./database.sqlite"
|
||||||
|
config.GobFilesLocation = "./gobcache"
|
||||||
|
os.MkdirAll(config.GobFilesLocation, 0644)
|
||||||
|
}
|
||||||
|
file, err := os.Create(*configLocation)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: could not create config file: %v\n", err)
|
||||||
|
os.Exit(ExitCodeBadConfig)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
enc := json.NewEncoder(file)
|
||||||
|
err = enc.Encode(config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: could not write config file: %v\n", err)
|
||||||
|
os.Exit(ExitCodeBadConfig)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = file.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: could not write config file: %v\n", err)
|
||||||
|
os.Exit(ExitCodeBadConfig)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfig() {
|
||||||
|
file, err := os.Open(*configLocation)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
fmt.Println("You must create a config file with -genconf")
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Error: could not load config file: %v", err)
|
||||||
|
}
|
||||||
|
os.Exit(ExitCodeBadConfig)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dec := json.NewDecoder(file)
|
||||||
|
err = dec.Decode(&config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: could not load config file: %v\n", err)
|
||||||
|
os.Exit(ExitCodeBadConfig)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = file.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: could not load config file: %v\n", err)
|
||||||
|
os.Exit(ExitCodeBadConfig)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
1
socketserver/cmd/statsweb/config.json
Normal file
1
socketserver/cmd/statsweb/config.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"ListenAddr":"localhost:3000","DatabaseLocation":"./database.sqlite","GobFilesLocation":"./gobcache"}
|
|
@ -1,3 +1,40 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"flag"
|
||||||
|
"github.com/clarkduvall/hyperloglog"
|
||||||
|
"time"
|
||||||
|
"bitbucket.org/stendec/frankerfacez/socketserver/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
var configLocation = flag.String("config", "./config.json", "Location of the configuration file. Defaults to ./config.json")
|
||||||
|
var genConfig = flag.Bool("genconf", false, "Generate a new configuration file.")
|
||||||
|
|
||||||
|
var config ConfigFile
|
||||||
|
|
||||||
|
const ExitCodeBadConfig = 2
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *genConfig {
|
||||||
|
makeConfig()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loadConfig()
|
||||||
|
|
||||||
|
http.ListenAndServe(config.ListenAddr, http.DefaultServeMux)
|
||||||
|
}
|
||||||
|
|
||||||
|
func combineDateRange(from time.Time, to time.Time, dest *hyperloglog.HyperLogLogPlus) error {
|
||||||
|
from = server.TruncateToMidnight(from)
|
||||||
|
to = server.TruncateToMidnight(to)
|
||||||
|
year, month, day := from.Date()
|
||||||
|
for current := from; current.Before(to); day = day + 1 {
|
||||||
|
current = time.Date(year, month, day, 0, 0, 0, 0, server.CounterLocation)
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"./logstasher"
|
"bitbucket.org/stendec/frankerfacez/socketserver/server/logstasher"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SuccessCommand is a Reply Command to indicate success in reply to a C2S Command.
|
// SuccessCommand is a Reply Command to indicate success in reply to a C2S Command.
|
||||||
|
|
|
@ -43,13 +43,18 @@ var uniqueCounter PeriodUniqueUsers
|
||||||
var uniqueUserChannel chan uuid.UUID
|
var uniqueUserChannel chan uuid.UUID
|
||||||
var uniqueCtrWritingToken chan usageToken
|
var uniqueCtrWritingToken chan usageToken
|
||||||
|
|
||||||
var counterLocation *time.Location = time.FixedZone("UTC-5", int((time.Hour*-5)/time.Second))
|
var CounterLocation *time.Location = time.FixedZone("UTC-5", int((time.Hour*-5)/time.Second))
|
||||||
|
|
||||||
|
func TruncateToMidnight(at time.Time) time.Time {
|
||||||
|
year, month, day := at.Date()
|
||||||
|
return time.Date(year, month, day, 0, 0, 0, 0, CounterLocation)
|
||||||
|
}
|
||||||
|
|
||||||
// GetCounterPeriod calculates the start and end timestamps for the HLL measurement period that includes the 'at' timestamp.
|
// GetCounterPeriod calculates the start and end timestamps for the HLL measurement period that includes the 'at' timestamp.
|
||||||
func GetCounterPeriod(at time.Time) (start time.Time, end time.Time) {
|
func GetCounterPeriod(at time.Time) (start time.Time, end time.Time) {
|
||||||
year, month, day := at.Date()
|
year, month, day := at.Date()
|
||||||
start = time.Date(year, month, day, 0, 0, 0, 0, counterLocation)
|
start = time.Date(year, month, day, 0, 0, 0, 0, CounterLocation)
|
||||||
end = time.Date(year, month, day+1, 0, 0, 0, 0, counterLocation)
|
end = time.Date(year, month, day+1, 0, 0, 0, 0, CounterLocation)
|
||||||
return start, end
|
return start, end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +148,7 @@ func loadUniqueUsers() {
|
||||||
log.Panicln("could not make unique users data dir:", err)
|
log.Panicln("could not make unique users data dir:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().In(counterLocation)
|
now := time.Now().In(CounterLocation)
|
||||||
uniqueCounter.Start, uniqueCounter.End = GetCounterPeriod(now)
|
uniqueCounter.Start, uniqueCounter.End = GetCounterPeriod(now)
|
||||||
err = loadHLL(now, &uniqueCounter)
|
err = loadHLL(now, &uniqueCounter)
|
||||||
isIgnorableError := err != nil && (false ||
|
isIgnorableError := err != nil && (false ||
|
||||||
|
@ -194,9 +199,9 @@ func processNewUsers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNextMidnight() time.Time {
|
func getNextMidnight() time.Time {
|
||||||
now := time.Now().In(counterLocation)
|
now := time.Now().In(CounterLocation)
|
||||||
year, month, day := now.Date()
|
year, month, day := now.Date()
|
||||||
return time.Date(year, month, day+1, 0, 0, 1, 0, counterLocation)
|
return time.Date(year, month, day+1, 0, 0, 1, 0, CounterLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_init_func
|
// is_init_func
|
||||||
|
@ -214,7 +219,7 @@ func rolloverCounters_do() {
|
||||||
var now time.Time
|
var now time.Time
|
||||||
|
|
||||||
token = <-uniqueCtrWritingToken
|
token = <-uniqueCtrWritingToken
|
||||||
now = time.Now().In(counterLocation)
|
now = time.Now().In(CounterLocation)
|
||||||
// Cycle for period
|
// Cycle for period
|
||||||
err := writeHLL_do(&uniqueCounter)
|
err := writeHLL_do(&uniqueCounter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
func TestUniqueConnections(t *testing.T) {
|
func TestUniqueConnections(t *testing.T) {
|
||||||
const TestExpectedCount = 1000
|
const TestExpectedCount = 1000
|
||||||
|
|
||||||
testStart := time.Now().In(counterLocation)
|
testStart := time.Now().In(CounterLocation)
|
||||||
|
|
||||||
var server *httptest.Server
|
var server *httptest.Server
|
||||||
var backendExpected = NewTBackendRequestChecker(t,
|
var backendExpected = NewTBackendRequestChecker(t,
|
||||||
|
@ -35,7 +35,7 @@ func TestUniqueConnections(t *testing.T) {
|
||||||
TCheckHLLValue(t, TestExpectedCount, readCurrentHLL())
|
TCheckHLLValue(t, TestExpectedCount, readCurrentHLL())
|
||||||
|
|
||||||
token := <-uniqueCtrWritingToken
|
token := <-uniqueCtrWritingToken
|
||||||
uniqueCounter.End = time.Now().In(counterLocation).Add(-1 * time.Second)
|
uniqueCounter.End = time.Now().In(CounterLocation).Add(-1 * time.Second)
|
||||||
uniqueCtrWritingToken <- token
|
uniqueCtrWritingToken <- token
|
||||||
|
|
||||||
rolloverCounters_do()
|
rolloverCounters_do()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue