medinet/main.go

170 lines
4.1 KiB
Go

// MediNET - Session repository and community portal for Meditation Assistant
// https://code.rocket9labs.com/tslocum/medinet
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"math/rand"
"os"
"regexp"
"time"
"gopkg.in/yaml.v2"
)
type configuration struct {
TimeZone string
DBDriver string
DBSource string
Om string
Web string
}
type statistics struct {
AccountsCreated int
ActiveAccounts []int
SessionsPosted int
TopStreak int
}
var (
db *database
config *configuration
printDebug bool
stats *statistics
serverLocation *time.Location
regexpNumbers = regexp.MustCompile("[0-9]+")
regexpMarket = regexp.MustCompile(".*?([a-zA-Z]+)$")
)
func logDebug(message string) {
if printDebug {
log.Println(message)
}
}
func logDebugf(format string, a ...interface{}) {
logDebug(fmt.Sprintf(format, a...))
}
func atWindowStart(t time.Time, streakBuffer int) time.Time {
year, month, day := t.Date()
return time.Date(year, month, day, streakBuffer/3600, (streakBuffer%3600)/60, streakBuffer%60, 0, t.Location())
}
func beforeWindowStart(t time.Time, streakBuffer int) bool {
return t.Before(atWindowStart(t, streakBuffer))
}
func failOnError(err error) {
if err != nil {
log.Fatal(err)
}
}
func trackActiveAccount(accountID int) {
active := false
for _, aID := range stats.ActiveAccounts {
if aID == accountID {
active = true
}
}
if !active {
stats.ActiveAccounts = append(stats.ActiveAccounts, accountID)
}
err := db.updateLastActive(accountID)
failOnError(err)
}
func printStatistics() {
for {
stats.ActiveAccounts = nil
stats.AccountsCreated, stats.SessionsPosted, stats.TopStreak = 0, 0, 0
now := time.Now().In(serverLocation)
fourAM := time.Date(now.Year(), now.Month(), now.Day(), 4, 0, 0, 0, serverLocation)
if !fourAM.After(now) {
fourAM = fourAM.AddDate(0, 0, 1)
}
time.Sleep(time.Until(fourAM))
log.Printf("%d accounts (%d new) posted %d sessions (top streak %d)", len(stats.ActiveAccounts), stats.AccountsCreated, stats.SessionsPosted, stats.TopStreak)
}
}
func main() {
var opts struct {
ConfigFile string
Debug bool
}
flag.StringVar(&opts.ConfigFile, "config", "", "Configuration file")
flag.BoolVar(&opts.Debug, "debug", false, "Print debug information")
flag.Parse()
rand.Seed(time.Now().UTC().UnixNano())
if opts.ConfigFile == "" {
log.Fatal("Please specify configuration file with: medinet -c <config file>")
}
_, err := os.Stat(opts.ConfigFile)
if err != nil {
log.Fatalf("Configuration file %s does not exist: %s", opts.ConfigFile, err)
}
configData, err := ioutil.ReadFile(opts.ConfigFile)
if err != nil {
log.Fatalf("Failed to read %s: %v", opts.ConfigFile, err)
}
config = new(configuration)
err = yaml.Unmarshal(configData, config)
if err != nil {
log.Fatalf("Failed to read %s: %v", opts.ConfigFile, err)
} else if config.DBDriver == "" {
log.Fatal("Specify database driver in configuration file")
} else if config.Om == "" {
log.Fatal("Specify Om host:port in configuration file")
} else if config.Web == "" {
log.Fatal("Specify Web directory in configuration file")
}
tz := "UTC"
if config.TimeZone != "" {
tz = config.TimeZone
}
loc, err := time.LoadLocation(tz)
failOnError(err)
serverLocation = loc
printDebug = opts.Debug
stats = new(statistics)
go printStatistics()
db, err = connect(config.DBDriver, config.DBSource)
failOnError(err)
initWeb()
listenWeb()
log.Printf("Listening on %+v", config.Om)
}