Просмотр исходного кода

Add BoltDB as embedded database option instead of SQLite (#282)

maddie 6 лет назад
Родитель
Сommit
a81bb0380d
10 измененных файлов с 143 добавлено и 24 удалено
  1. 21 9
      README.md
  2. 2 0
      config/config.go
  3. 84 0
      database/bolt/bolt.go
  4. 4 3
      database/database.go
  5. 3 2
      database/mysql/mysql.go
  6. 3 2
      database/postgresql/postgresql.go
  7. 1 1
      go.mod
  8. 15 0
      go.sum
  9. 2 2
      results/telemetry.go
  10. 8 5
      settings.toml

+ 21 - 9
README.md

@@ -27,7 +27,7 @@ Works with mobile versions too.
 
 ## Server requirements
 * Any [Go supported platforms](https://github.com/golang/go/wiki/MinimumRequirements)
-* PostgreSQL or MySQL database to store test results (optional)
+* BoltDB, PostgreSQL or MySQL database to store test results (optional)
 * A fast! Internet connection
 
 ## Installation
@@ -40,12 +40,19 @@ You need Go 1.13+ to compile the binary.
     $ go get github.com/librespeed/speedtest@go
     ```
 
-2. If you're using telemetry function, create database and import the corresponding `.sql` file under `database/{mysql,postgresql}`
+2. If you have telemetry enabled,
+    - For PostgreSQL/MySQL, create database and import the corresponding `.sql` file under `database/{postgresql,mysql}`
 
-    ```
-    # assume you have already created a database named `speedtest` under current user
-    $ psql speedtest < database/postgresql/telemetry_postgresql.sql
-    ```
+        ```
+        # assume you have already created a database named `speedtest` under current user
+        $ psql speedtest < database/postgresql/telemetry_postgresql.sql
+        ```
+     
+    - For embedded BoltDB, make sure to define the `database_file` path in `settings.toml`:
+    
+        ```
+        database_file="speedtest.db"
+        ```
 
 3. Put `assets` folder under the same directory as your compiled binary.
     - Make sure the font files and JavaScripts are in the `assets` directory
@@ -74,25 +81,30 @@ You need Go 1.13+ to compile the binary.
     # redact IP addresses
     redact_ip_addresses=false
     
-    # database type for statistics data, currently supports: mysql, postgresql
+    # database type for statistics data, currently supports: bolt, mysql, postgresql
     database_type="postgresql"
     database_hostname="localhost"
     database_name="speedtest"
     database_username="postgres"
     database_password=""
+   
+    # if you use `bolt` as database, set database_file to database file location
+    database_file="speedtest.db"
     ```
 
 ## Differences between Go and PHP implementation and caveats
 
+- Since there is no CGo-free SQLite implementation available, I've opted to use [BoltDB](https://github.com/etcd-io/bbolt)
+  instead, as an embedded database alternative to SQLite
 - Test IDs are generated ULID, there is no option to change them to plain ID
 - API endpoints have the same names, except the `.php` extension (e.g `empty`, `garbage`, `getIP`)
 - You can use the same HTML template from the PHP implementation
 - There might be a slight delay on program start if your Internet connection is slow. That's because the program will
 attempt to fetch your current network's ISP info for distance calculation between your network and the speed test client's.
-This action will only be done once, and cached for later use.
+This action will only be taken once, and cached for later use.
 
 ## License
-Copyright (C) 2016-2019 Federico Dossena
+Copyright (C) 2016-2019 Federico Dossena  
 Copyright (C) 2020 Maddie Zhan
 
 This program is free software: you can redistribute it and/or modify

+ 2 - 0
config/config.go

@@ -20,6 +20,8 @@ type Config struct {
 	DatabaseName     string `mapstructure:"database_name"`
 	DatabaseUsername string `mapstructure:"database_username"`
 	DatabasePassword string `mapstructure:"database_password"`
+
+	DatabaseFile string `mapstructure:"database_file"`
 }
 
 var (

+ 84 - 0
database/bolt/bolt.go

@@ -0,0 +1,84 @@
+package bolt
+
+import (
+	"encoding/json"
+	"errors"
+	"time"
+
+	"go.etcd.io/bbolt"
+
+	"backend/database/schema"
+
+	_ "github.com/go-sql-driver/mysql"
+	log "github.com/sirupsen/logrus"
+)
+
+const (
+	bucketName = `speedtest`
+)
+
+type Bolt struct {
+	db *bbolt.DB
+}
+
+func Open(databaseFile string) *Bolt {
+	db, err := bbolt.Open(databaseFile, 0666, nil)
+	if err != nil {
+		log.Fatalf("Cannot open BoltDB database file: %s", err)
+	}
+	return &Bolt{db: db}
+}
+
+func (p *Bolt) Insert(data *schema.TelemetryData) error {
+	return p.db.Update(func(tx *bbolt.Tx) error {
+		data.Timestamp = time.Now()
+		b, _ := json.Marshal(data)
+		bucket, err := tx.CreateBucketIfNotExists([]byte(bucketName))
+		if err != nil {
+			return err
+		}
+		return bucket.Put([]byte(data.UUID), b)
+	})
+}
+
+func (p *Bolt) FetchByUUID(uuid string) (*schema.TelemetryData, error) {
+	var record schema.TelemetryData
+	err := p.db.View(func(tx *bbolt.Tx) error {
+		bucket := tx.Bucket([]byte(bucketName))
+		if bucket == nil {
+			return errors.New("data bucket doesn't exist yet")
+		}
+		b := bucket.Get([]byte(uuid))
+		return json.Unmarshal(b, &record)
+	})
+	return &record, err
+}
+
+func (p *Bolt) FetchLast100() ([]schema.TelemetryData, error) {
+	var records []schema.TelemetryData
+	err := p.db.View(func(tx *bbolt.Tx) error {
+		var record schema.TelemetryData
+		bucket := tx.Bucket([]byte(bucketName))
+		if bucket == nil {
+			return errors.New("data bucket doesn't exist yet")
+		}
+
+		cursor := bucket.Cursor()
+		_, b := cursor.Last()
+
+		for len(records) < 100 {
+			if err := json.Unmarshal(b, &record); err != nil {
+				return err
+			}
+			records = append(records, record)
+
+			_, b = cursor.Prev()
+			if b == nil {
+				break
+			}
+		}
+
+		return nil
+	})
+	return records, err
+}

+ 4 - 3
database/database.go

@@ -1,9 +1,8 @@
 package database
 
 import (
-	"database/sql"
-
 	"backend/config"
+	"backend/database/bolt"
 	"backend/database/mysql"
 	"backend/database/postgresql"
 	"backend/database/schema"
@@ -14,7 +13,7 @@ var (
 )
 
 type DataAccess interface {
-	Insert(*schema.TelemetryData) (sql.Result, error)
+	Insert(*schema.TelemetryData) error
 	FetchByUUID(string) (*schema.TelemetryData, error)
 	FetchLast100() ([]schema.TelemetryData, error)
 }
@@ -25,5 +24,7 @@ func SetDBInfo(conf *config.Config) {
 		DB = postgresql.Open(conf.DatabaseHostname, conf.DatabaseUsername, conf.DatabasePassword, conf.DatabaseName)
 	case "mysql":
 		DB = mysql.Open(conf.DatabaseHostname, conf.DatabaseUsername, conf.DatabasePassword, conf.DatabaseName)
+	case "bolt":
+		DB = bolt.Open(conf.DatabaseFile)
 	}
 }

+ 3 - 2
database/mysql/mysql.go

@@ -27,9 +27,10 @@ func Open(hostname, username, password, database string) *MySQL {
 	return &MySQL{db: conn}
 }
 
-func (p *MySQL) Insert(data *schema.TelemetryData) (sql.Result, error) {
+func (p *MySQL) Insert(data *schema.TelemetryData) error {
 	stmt := `INSERT INTO speedtest_users (ip, ispinfo, extra, ua, lang, dl, ul, ping, jitter, log, uuid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`
-	return p.db.Exec(stmt, data.IPAddress, data.ISPInfo, data.Extra, data.UserAgent, data.Language, data.Download, data.Upload, data.Ping, data.Jitter, data.Log, data.UUID)
+	_, err := p.db.Exec(stmt, data.IPAddress, data.ISPInfo, data.Extra, data.UserAgent, data.Language, data.Download, data.Upload, data.Ping, data.Jitter, data.Log, data.UUID)
+	return err
 }
 
 func (p *MySQL) FetchByUUID(uuid string) (*schema.TelemetryData, error) {

+ 3 - 2
database/postgresql/postgresql.go

@@ -27,9 +27,10 @@ func Open(hostname, username, password, database string) *PostgreSQL {
 	return &PostgreSQL{db: conn}
 }
 
-func (p *PostgreSQL) Insert(data *schema.TelemetryData) (sql.Result, error) {
+func (p *PostgreSQL) Insert(data *schema.TelemetryData) error {
 	stmt := `INSERT INTO speedtest_users (ip, ispinfo, extra, ua, lang, dl, ul, ping, jitter, log, uuid) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id;`
-	return p.db.Exec(stmt, data.IPAddress, data.ISPInfo, data.Extra, data.UserAgent, data.Language, data.Download, data.Upload, data.Ping, data.Jitter, data.Log, data.UUID)
+	_, err := p.db.Exec(stmt, data.IPAddress, data.ISPInfo, data.Extra, data.UserAgent, data.Language, data.Download, data.Upload, data.Ping, data.Jitter, data.Log, data.UUID)
+	return err
 }
 
 func (p *PostgreSQL) FetchByUUID(uuid string) (*schema.TelemetryData, error) {

+ 1 - 1
go.mod

@@ -12,6 +12,6 @@ require (
 	github.com/oklog/ulid/v2 v2.0.2
 	github.com/sirupsen/logrus v1.4.2
 	github.com/spf13/viper v1.6.2
+	go.etcd.io/bbolt v1.3.3
 	golang.org/x/image v0.0.0-20200119044424-58c23975cae1
-	gopkg.in/yaml.v2 v2.2.4
 )

+ 15 - 0
go.sum

@@ -1,4 +1,5 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -13,6 +14,7 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
@@ -42,6 +44,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@@ -50,6 +53,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -57,8 +61,10 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
 github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -76,6 +82,7 @@ github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwp
 github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
@@ -90,7 +97,9 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -105,6 +114,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
 github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
 github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
@@ -112,7 +122,10 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
@@ -126,6 +139,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -151,6 +165,7 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
 google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

+ 2 - 2
results/telemetry.go

@@ -176,12 +176,12 @@ func Record(w http.ResponseWriter, r *http.Request) {
 	record.Jitter = jitter
 	record.Log = logs
 
-	t := time.Now()
+	t := time.Unix(1048576, 0)
 	entropy := ulid.Monotonic(rand.New(rand.NewSource(t.UnixNano())), 0)
 	uuid := ulid.MustNew(ulid.Timestamp(t), entropy)
 	record.UUID = uuid.String()
 
-	_, err := database.DB.Insert(&record)
+	err := database.DB.Insert(&record)
 	if err != nil {
 		log.Errorf("Error inserting into database: %s", err)
 		w.WriteHeader(http.StatusInternalServerError)

+ 8 - 5
settings.toml

@@ -14,9 +14,12 @@ statistics_password="PASSWORD"
 # redact IP addresses
 redact_ip_addresses=false
 
-# database type for statistics data, currently supports: mysql, postgresql
-database_type="postgresql"
-database_hostname="localhost"
-database_name="speedtest"
-database_username="postgres"
+# database type for statistics data, currently supports: bolt, mysql, postgresql
+database_type="bolt"
+database_hostname=""
+database_name=""
+database_username=""
 database_password=""
+
+# if you use `bolt` as database, set database_file to database file location
+database_file="speedtest.db"