package main import ( "log" "net/http" "os" "strconv" "strings" "deadbeef.codes/steven/siteviewcounter/countersql" "github.com/go-sql-driver/mysql" ) var ( database countersql.Configuration uniqueVisits int ) // Application Startup func init() { envVars := make(map[string]string) envVars["dbusername"] = os.Getenv("dbusername") envVars["dbpassword"] = os.Getenv("dbpassword") envVars["dbhostname"] = os.Getenv("dbhostname") envVars["dbname"] = os.Getenv("dbname") envVars["timezone"] = os.Getenv("timezone") for key, value := range envVars { if value == "" { log.Fatalf("shell environment variable %s is not set", key) } } // Database Config dbConfig := mysql.Config{} dbConfig.User = envVars["dbusername"] dbConfig.Passwd = envVars["dbpassword"] dbConfig.Addr = envVars["dbhostname"] dbConfig.DBName = envVars["dbname"] dbConfig.Net = "tcp" dbConfig.ParseTime = true dbConfig.AllowNativePasswords = true database = countersql.Configuration{} database.DSN = dbConfig.FormatDSN() // Test database online at startup and get count of visits dbConn, err := database.Connect() if err != nil { log.Fatalf("failed to connect to database: %v", err) } uniqueVisits, err = dbConn.GetUniqueVisits() if err != nil { log.Fatalf("failed to get number of unique visits from database: %v", err) } dbConn.DB.Close() } // HTTP Routing func main() { // API Handlers http.HandleFunc("/", countHandler) log.Print("Service listening on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } func countHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "GET" { w.Header().Set("Access-Control-Allow-Origin", "*") w.Write([]byte(strconv.Itoa(uniqueVisits))) dbConn, err := database.Connect() if err != nil { log.Printf("failed to connect to database: %v", err) w.WriteHeader(http.StatusFailedDependency) return } defer dbConn.DB.Close() var ipAddress string if len(r.Header.Get("X-Forwarded-For")) > 0 { ipAddress = r.Header.Get("X-Forwarded-For") } else { ipAddress = r.RemoteAddr } ipAddress = strings.Split(ipAddress, ":")[0] returnVisitor, err := dbConn.HasIPVisited(ipAddress) if err != nil { log.Printf("failed to determine if this is a return visitor, no data is being logged: %v", err) return } if returnVisitor { err = dbConn.IncrementVisitor(ipAddress) log.Printf("return visitor from %s", ipAddress) } else { err = dbConn.AddVisitor(ipAddress) uniqueVisits++ log.Printf("new visitor from %s", ipAddress) } if err != nil { log.Printf("failed to add/update visit record in database: %v", err) return } } else { w.WriteHeader(http.StatusMethodNotAllowed) } }