Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
abc8ac0a7b | |||
8ce11fa824 | |||
![]() |
7001fa4fa5 | ||
![]() |
fa28701928 | ||
![]() |
4afbe82283 | ||
![]() |
a3eec03845 | ||
![]() |
2ea9df0aba | ||
![]() |
8e31fe25ac | ||
![]() |
580fc08e0e | ||
![]() |
9cbc95a6db | ||
![]() |
fa749f3b45 | ||
![]() |
a5d18ef24c | ||
![]() |
f09f2df2e3 | ||
![]() |
86763bd3aa | ||
![]() |
22f21a270b | ||
![]() |
5944c3ca28 | ||
![]() |
c67b8ec91d | ||
![]() |
281aff1725 | ||
![]() |
158e37d3ae | ||
![]() |
2583e5113a |
47
.github/workflows/arm-registry.yml
vendored
Normal file
47
.github/workflows/arm-registry.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
name: Create and publish a Docker image with ARM
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v3
|
||||
env:
|
||||
CI: false
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
64
.github/workflows/docker-publish.yml
vendored
Normal file
64
.github/workflows/docker-publish.yml
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
name: Docker
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: ghcr.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
PLATFORMS: linux/amd64,linux/arm64,linux/arm/v7,linux/386
|
||||
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
# Build and push Docker image with Buildx (don't push on PR)
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: ${{ env.PLATFORMS }}
|
@ -22,15 +22,10 @@ builds:
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
- mips
|
||||
- mipsle
|
||||
goarm:
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
gomips:
|
||||
- hardfloat
|
||||
- softfloat
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: 386
|
||||
@ -77,6 +72,8 @@ builds:
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- mips
|
||||
- mipsle
|
||||
- mips64
|
||||
- mips64le
|
||||
gomips:
|
||||
|
26
Dockerfile
26
Dockerfile
@ -1,20 +1,18 @@
|
||||
FROM golang:alpine AS build_base
|
||||
#ENV GOARCH arm64
|
||||
#ENV GOARCH amd64
|
||||
RUN apk add --no-cache git gcc ca-certificates libc-dev \
|
||||
&& mkdir -p /go/src/github.com/librespeed/ \
|
||||
&& cd /go/src/github.com/librespeed/ \
|
||||
&& git clone https://github.com/librespeed/speedtest-go.git
|
||||
WORKDIR /go/src/github.com/librespeed/speedtest-go
|
||||
RUN go get ./ && go build -ldflags "-w -s" -trimpath -o speedtest main.go
|
||||
FROM golang:1.18-alpine AS build_base
|
||||
RUN apk add --no-cache git gcc ca-certificates libc-dev
|
||||
WORKDIR /build
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY ./ ./
|
||||
RUN go build -ldflags "-w -s" -trimpath -o speedtest .
|
||||
|
||||
FROM alpine:3.9
|
||||
RUN apk add ca-certificates
|
||||
FROM alpine:3.16
|
||||
RUN apk add --no-cache ca-certificates
|
||||
WORKDIR /app
|
||||
COPY --from=build_base /go/src/github.com/librespeed/speedtest-go/speedtest .
|
||||
COPY --from=build_base /go/src/github.com/librespeed/speedtest-go/assets ./assets
|
||||
COPY --from=build_base /go/src/github.com/librespeed/speedtest-go/settings.toml .
|
||||
COPY --from=build_base /build/speedtest ./
|
||||
COPY settings.toml ./
|
||||
|
||||
USER nobody
|
||||
EXPOSE 8989
|
||||
|
||||
CMD ["./speedtest"]
|
||||
|
21
README.md
21
README.md
@ -34,6 +34,19 @@ Works with mobile versions too.
|
||||
|
||||
## Installation
|
||||
|
||||
### Install using prebuilt binaries
|
||||
|
||||
1. Download the appropriate binary file from the [releases](https://github.com/librespeed/speedtest-go/releases/) page.
|
||||
2. Unzip the archive.
|
||||
3. Make changes to the configuration.
|
||||
4. Run the binary.
|
||||
5. Optional: Setup a systemd service file.
|
||||
|
||||
### Use Ansible for automatic installation
|
||||
|
||||
You can use an Ansible role for installing speedtest-go easily. You can find the role on the [Ansible galaxy](https://galaxy.ansible.com/flymia/ansible_speedtest_go). There is a [separate repository](https://github.com/flymia/ansible-speedtest_go) for documentation about the Ansible role.
|
||||
### Compile from source
|
||||
|
||||
You need Go 1.16+ to compile the binary. If you have an older version of Go and don't want to install the tarball
|
||||
manually, you can install newer version of Go into your `GOPATH`:
|
||||
|
||||
@ -116,6 +129,14 @@ manually, you can install newer version of Go into your `GOPATH`:
|
||||
|
||||
# if you use `bolt` as database, set database_file to database file location
|
||||
database_file="speedtest.db"
|
||||
|
||||
# TLS and HTTP/2 settings. TLS is required for HTTP/2
|
||||
enable_tls=false
|
||||
enable_http2=false
|
||||
|
||||
# if you use HTTP/2 or TLS, you need to prepare certificates and private keys
|
||||
# tls_cert_file="cert.pem"
|
||||
# tls_key_file="privkey.pem"
|
||||
```
|
||||
|
||||
## Differences between Go and PHP implementation and caveats
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
type Config struct {
|
||||
BindAddress string `mapstructure:"bind_address"`
|
||||
Port string `mapstructure:"listen_port"`
|
||||
BaseURL string `mapstructure:"url_base"`
|
||||
ProxyProtocolPort string `mapstructure:"proxyprotocol_port"`
|
||||
ServerLat float64 `mapstructure:"server_lat"`
|
||||
ServerLng float64 `mapstructure:"server_lng"`
|
||||
@ -25,6 +26,11 @@ type Config struct {
|
||||
DatabasePassword string `mapstructure:"database_password"`
|
||||
|
||||
DatabaseFile string `mapstructure:"database_file"`
|
||||
|
||||
EnableHTTP2 bool `mapstructure:"enable_http2"`
|
||||
EnableTLS bool `mapstructure:"enable_tls"`
|
||||
TLSCertFile string `mapstructure:"tls_cert_file"`
|
||||
TLSKeyFile string `mapstructure:"tls_key_file"`
|
||||
}
|
||||
|
||||
var (
|
||||
@ -34,6 +40,7 @@ var (
|
||||
|
||||
func init() {
|
||||
viper.SetDefault("listen_port", "8989")
|
||||
viper.SetDefault("url_base", "")
|
||||
viper.SetDefault("proxyprotocol_port", "0")
|
||||
viper.SetDefault("download_chunks", 4)
|
||||
viper.SetDefault("distance_unit", "K")
|
||||
@ -44,6 +51,8 @@ func init() {
|
||||
viper.SetDefault("database_hostname", "localhost")
|
||||
viper.SetDefault("database_name", "speedtest")
|
||||
viper.SetDefault("database_username", "postgres")
|
||||
viper.SetDefault("enable_tls", false)
|
||||
viper.SetDefault("enable_http2", false)
|
||||
|
||||
viper.SetConfigName("settings")
|
||||
viper.AddConfigPath(".")
|
||||
@ -54,14 +63,9 @@ func Load(configPath string) Config {
|
||||
|
||||
configFile = configPath
|
||||
viper.SetConfigFile(configPath)
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||
log.Warnf("No config file found in search paths, using default values")
|
||||
} else {
|
||||
log.Fatalf("Error reading config: %s", err)
|
||||
}
|
||||
}
|
||||
viper.SetEnvPrefix("speedtest")
|
||||
viper.AutomaticEnv()
|
||||
viper.ReadInConfig()
|
||||
|
||||
if err := viper.Unmarshal(&conf); err != nil {
|
||||
log.Fatalf("Error parsing config: %s", err)
|
||||
|
22
go.mod
22
go.mod
@ -3,25 +3,23 @@ module github.com/librespeed/speedtest
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/breml/rootcerts v0.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.4
|
||||
github.com/breml/rootcerts v0.2.1
|
||||
github.com/coreos/go-systemd/v22 v22.4.0
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/go-chi/cors v1.2.0
|
||||
github.com/go-chi/render v1.0.1
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/lib/pq v1.10.3
|
||||
github.com/mitchellh/mapstructure v1.4.2 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1
|
||||
github.com/gorilla/sessions v1.2.1
|
||||
github.com/lib/pq v1.10.4
|
||||
github.com/oklog/ulid/v2 v2.0.2
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pires/go-proxyproto v0.6.1
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/spf13/afero v1.8.0 // indirect
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
golang.org/x/crypto v0.9.0
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
|
||||
)
|
||||
|
327
go.sum
327
go.sum
@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
@ -15,9 +16,18 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
@ -26,7 +36,7 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
@ -36,27 +46,53 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
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=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/breml/rootcerts v0.1.0 h1:jf/F4MHeXBi7FVAHrPq+/MBmPlGXTbUAyR977bZ0j4E=
|
||||
github.com/breml/rootcerts v0.1.0/go.mod h1:24FDtzYMpqIeYC7QzaE8VPRQaFZU5TIUDlyk8qwjD88=
|
||||
github.com/breml/rootcerts v0.2.1 h1:GZMVDXOs945764NFck0vtHSjktKYubOFM0kjf5HAuwc=
|
||||
github.com/breml/rootcerts v0.2.1/go.mod h1:24FDtzYMpqIeYC7QzaE8VPRQaFZU5TIUDlyk8qwjD88=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU=
|
||||
github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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=
|
||||
@ -66,14 +102,19 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi/v5 v5.0.4 h1:5e494iHzsYBiyXQAHHuI4tyJS9M3V84OuX3ufIIGHFo=
|
||||
github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
|
||||
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
|
||||
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
|
||||
@ -81,9 +122,15 @@ github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
@ -91,6 +138,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
@ -99,6 +147,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@ -116,6 +165,7 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@ -129,10 +179,12 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
@ -142,104 +194,159 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
|
||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
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.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
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.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
|
||||
github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
|
||||
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc=
|
||||
github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pires/go-proxyproto v0.6.1 h1:EBupykFmo22SDjv4fQVQd2J9NOoLPmyZA/15ldOGkPw=
|
||||
github.com/pires/go-proxyproto v0.6.1/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60=
|
||||
github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk=
|
||||
github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@ -249,6 +356,7 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 h1:UFHFmFfixpmfRBcxuu+LA9l8MdURWVdVNUHxO5n1d2w=
|
||||
github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26/go.mod h1:IGhd0qMDsUa9acVjsbsT7bu3ktadtGOHI79+idTew/M=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@ -256,11 +364,12 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
@ -268,16 +377,24 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -290,8 +407,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@ -315,10 +432,12 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@ -326,9 +445,11 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@ -347,10 +468,17 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -362,7 +490,12 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -374,24 +507,33 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -411,16 +553,38 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164 h1:7ZDGnxgHAMw7thfC5bEos0RDAccZKxioiWBhfIe+tvw=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -429,8 +593,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@ -440,7 +606,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
@ -448,9 +613,9 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@ -483,8 +648,15 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -510,7 +682,17 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
|
||||
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@ -553,12 +735,34 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@ -578,7 +782,15 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@ -591,15 +803,20 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
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/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
|
||||
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
@ -6,7 +6,10 @@ import (
|
||||
|
||||
"github.com/go-chi/render"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/gorilla/securecookie"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/librespeed/speedtest/config"
|
||||
"github.com/librespeed/speedtest/database"
|
||||
"github.com/librespeed/speedtest/database/schema"
|
||||
@ -18,6 +21,37 @@ type StatsData struct {
|
||||
Data []schema.TelemetryData
|
||||
}
|
||||
|
||||
var (
|
||||
store *sessions.CookieStore
|
||||
conf *config.Config
|
||||
checkPassword func(password string) bool
|
||||
)
|
||||
|
||||
func statsInitialize(c *config.Config) {
|
||||
key := []byte(securecookie.GenerateRandomKey(32))
|
||||
store = sessions.NewCookieStore(key)
|
||||
store.Options = &sessions.Options{
|
||||
Path: c.BaseURL + "/stats",
|
||||
MaxAge: 3600 * 1, // 1 hour
|
||||
HttpOnly: true,
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
}
|
||||
conf = c
|
||||
|
||||
// Check if StatsPassword is a valid bcrypt hash
|
||||
if _, err := bcrypt.Cost([]byte(c.StatsPassword)); err == nil {
|
||||
log.Println("statistics_password is valid bcrypt hash")
|
||||
checkPassword = func(password string) bool {
|
||||
return nil == bcrypt.CompareHashAndPassword([]byte(c.StatsPassword), []byte(password))
|
||||
}
|
||||
|
||||
} else {
|
||||
checkPassword = func(password string) bool {
|
||||
return password == c.StatsPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Stats(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
t, err := template.New("template").Parse(htmlTemplate)
|
||||
@ -27,8 +61,6 @@ func Stats(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
conf := config.LoadedConfig()
|
||||
|
||||
if conf.DatabaseType == "none" {
|
||||
render.PlainText(w, r, "Statistics are disabled")
|
||||
return
|
||||
@ -42,16 +74,15 @@ func Stats(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if !data.NoPassword {
|
||||
op := r.FormValue("op")
|
||||
c, _ := r.Cookie("logged")
|
||||
session, _ := store.Get(r, "logged")
|
||||
auth, ok := session.Values["authenticated"].(bool)
|
||||
|
||||
if c != nil && c.Value == "true" {
|
||||
if auth && ok {
|
||||
if op == "logout" {
|
||||
cookie := &http.Cookie{
|
||||
Name: "logged",
|
||||
Value: "false",
|
||||
}
|
||||
http.SetCookie(w, cookie)
|
||||
http.Redirect(w, r, "/stats", http.StatusTemporaryRedirect)
|
||||
session.Values["authenticated"] = false
|
||||
session.Options.MaxAge = -1
|
||||
session.Save(r, w)
|
||||
http.Redirect(w, r, conf.BaseURL+"/stats", http.StatusTemporaryRedirect)
|
||||
} else {
|
||||
data.LoggedIn = true
|
||||
|
||||
@ -78,14 +109,12 @@ func Stats(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
} else {
|
||||
if op == "login" {
|
||||
session, _ := store.Get(r, "logged")
|
||||
password := r.FormValue("password")
|
||||
if password == conf.StatsPassword {
|
||||
cookie := &http.Cookie{
|
||||
Name: "logged",
|
||||
Value: "true",
|
||||
}
|
||||
http.SetCookie(w, cookie)
|
||||
http.Redirect(w, r, "/stats", http.StatusTemporaryRedirect)
|
||||
if checkPassword(password) {
|
||||
session.Values["authenticated"] = true
|
||||
session.Save(r, w)
|
||||
http.Redirect(w, r, conf.BaseURL+"/stats", http.StatusTemporaryRedirect)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ type IPInfoResponse struct {
|
||||
}
|
||||
|
||||
func Initialize(c *config.Config) {
|
||||
statsInitialize(c)
|
||||
// changed to use Noto Sans instead of OpenSans, due to issue:
|
||||
// https://github.com/golang/freetype/issues/8
|
||||
fLight, err := freetype.ParseFont(fontLightBytes)
|
||||
|
@ -2,6 +2,8 @@
|
||||
bind_address=""
|
||||
# backend listen port
|
||||
listen_port=8989
|
||||
# change the base URL
|
||||
# url_base="/librespeed"
|
||||
# proxy protocol port, use 0 to disable
|
||||
proxyprotocol_port=0
|
||||
# Server location
|
||||
@ -20,7 +22,7 @@ redact_ip_addresses=false
|
||||
|
||||
# database type for statistics data, currently supports: none, memory, bolt, mysql, postgresql
|
||||
# if none is specified, no telemetry/stats will be recorded, and no result PNG will be generated
|
||||
database_type="bolt"
|
||||
database_type="memory"
|
||||
database_hostname=""
|
||||
database_name=""
|
||||
database_username=""
|
||||
@ -28,3 +30,11 @@ database_password=""
|
||||
|
||||
# if you use `bolt` as database, set database_file to database file location
|
||||
database_file="speedtest.db"
|
||||
|
||||
# TLS and HTTP/2 settings. TLS is required for HTTP/2
|
||||
enable_tls=false
|
||||
enable_http2=false
|
||||
|
||||
# if you use HTTP/2 or TLS, you need to prepare certificates and private keys
|
||||
# tls_cert_file="cert.pem"
|
||||
# tls_key_file="privkey.pem"
|
||||
|
28
systemd/README.md
Normal file
28
systemd/README.md
Normal file
@ -0,0 +1,28 @@
|
||||
# Example systemd unit files
|
||||
|
||||
To use these, first review the speedtest.* unit files, and then:
|
||||
|
||||
cp ../speedtest /usr/local/bin/
|
||||
mkdir -p /usr/local/share/speedtest /usr/local/etc
|
||||
cp -aR ../web/assets /usr/local/share/speedtest/assets
|
||||
cp speedtest-settings.toml /usr/local/etc
|
||||
cp speedtest.* /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
|
||||
If you wish to use the bolt database type:
|
||||
|
||||
# Create static system user and group
|
||||
adduser --system --group --no-create-home --disabled-password speedtest
|
||||
mkdir -p /usr/local/var/speedtest
|
||||
touch /usr/local/var/speedtest/speedtest.db
|
||||
chown speedtest. /usr/local/var/speedtest/speedtest.db
|
||||
|
||||
To start (and enable at boot-up):
|
||||
|
||||
systemctl enable --now speedtest.socket
|
||||
|
||||
speedtest-go should now be listening for http request on port 80 on the local
|
||||
machine.
|
||||
|
||||
You will need to customise the html files e.g. edit
|
||||
`/usr/local/share/speedtest/assets/index.html` to suit your site.
|
31
systemd/speedtest-settings.toml
Normal file
31
systemd/speedtest-settings.toml
Normal file
@ -0,0 +1,31 @@
|
||||
# bind address, use empty string to bind to all interfaces, or when using socket activation
|
||||
#bind_address=""
|
||||
# backend listen port. Set this to "" when using socket activation
|
||||
listen_port=""
|
||||
# proxy protocol port, use 0 to disable
|
||||
proxyprotocol_port=0
|
||||
# Server location
|
||||
server_lat=50.82589
|
||||
server_lng=-0.141391
|
||||
# ipinfo.io API key, if applicable
|
||||
ipinfo_api_key=""
|
||||
|
||||
# assets directory path, defaults to `assets` in the same directory
|
||||
assets_path="/usr/local/share/speedtest/assets"
|
||||
|
||||
# password for logging into statistics page
|
||||
statistics_password="PASSWORD"
|
||||
# redact IP addresses
|
||||
redact_ip_addresses=false
|
||||
|
||||
# database type for statistics data, currently supports: none, memory, bolt, mysql, postgresql
|
||||
# if none is specified, no telemetry/stats will be recorded, and no result PNG will be generated
|
||||
#database_type="bolt"
|
||||
database_type="memory"
|
||||
database_hostname=""
|
||||
database_name=""
|
||||
database_username=""
|
||||
database_password=""
|
||||
|
||||
# if you use `bolt` as database, set database_file to database file location
|
||||
database_file="/usr/local/var/speedtest/speedtest.db"
|
135
systemd/speedtest.service
Normal file
135
systemd/speedtest.service
Normal file
@ -0,0 +1,135 @@
|
||||
# Systemd unit file for speedtest-go. The defaults below are suitable for
|
||||
# running all configurations in a medium-security environment. See comments
|
||||
# below for addtional caveats - particularly those labelled "IMPORTANT".
|
||||
|
||||
# You can edit this file, or alternatively you may prefer to use systemd's
|
||||
# "override" mechanisms, to avoid editing this file e.g. using:
|
||||
|
||||
# systemctl edit speedtest.service
|
||||
|
||||
[Unit]
|
||||
Description=Speedtest-go Server
|
||||
After=syslog.target network.target
|
||||
|
||||
# Default to using socket activation (see accompanying socket unit file to
|
||||
# configure the bind address etc.).
|
||||
Requires=speedtest.socket
|
||||
After=speedtest.socket
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# The paths to the installed binary and configuration file:
|
||||
|
||||
ExecStart=/usr/local/bin/speedtest -c /usr/local/etc/speedtest-settings.toml
|
||||
#WorkingDirectory=/usr/local/share/speedtest
|
||||
#Restart=always
|
||||
#RestartSec=5
|
||||
|
||||
# IMPORTANT!
|
||||
# If you use a database file (not server), then you will need to disable the
|
||||
# DynamicUser setting, and manually create the UNIX user and group specified
|
||||
# below, to ensure the file is accessible across multiple invocations of the
|
||||
# service.
|
||||
DynamicUser=true
|
||||
|
||||
# You may prefer to use a different user or group name on your system.
|
||||
User=speedtest
|
||||
Group=speedtest
|
||||
|
||||
|
||||
# The following options will work for all configurations, but are not the
|
||||
# most secure, so you are advised to customise them as described below:
|
||||
|
||||
# If NOT using socket activation, or if using socket activation AND
|
||||
# connecting to an external database server (MySQL, postgres) via TCP:
|
||||
RestrictAddressFamilies=AF_INET AF_INET6
|
||||
|
||||
# If connecting to an external database via unix domain sockets (MySQL
|
||||
# default to this mode of operation):
|
||||
RestrictAddressFamilies=AF_UNIX
|
||||
|
||||
# If using 'none', 'memory', or 'bolt' database types, and socket activation
|
||||
# then the process will not need to bind to any new sockets, so we can remove
|
||||
# the earlier AF_UNIX option again. In systemd versions before 249 this is
|
||||
# the only way to say "Restrict the use of all address families":
|
||||
RestrictAddressFamilies=AF_UNIX
|
||||
RestrictAddressFamilies=~AF_UNIX
|
||||
# ...in systemd version 249 and later, we can instead use the much clearer:
|
||||
#RestrictAddressFamilies=none
|
||||
|
||||
# The following options are available (in systemd v247) to restrict the
|
||||
# actions of the speedtest server for reasons of increased security.
|
||||
|
||||
# As a whole, the purpose of these are to provide an additional layer of
|
||||
# security by mitigating any unknown security vulnerabilities which may exist
|
||||
# in speedtest or in the libraries, tools and operating system components
|
||||
# which it relies upon.
|
||||
|
||||
# IMPORTANT!
|
||||
# The following line must be customised to your individual requirements.
|
||||
# e.g. if using the 'bolt' in-process database type:
|
||||
ReadWritePaths=/usr/local/var/speedtest
|
||||
|
||||
# Makes created files group-readable, but inaccessible by others
|
||||
UMask=027
|
||||
|
||||
# Many of the following options are desribed in the systemd.resource-control(5)
|
||||
# manual page.
|
||||
|
||||
# The following may be useful in your environment:
|
||||
#IPAddressDeny=
|
||||
#IPAddressAllow=
|
||||
#IPAccounting=true
|
||||
#IPIngressFilterPath=
|
||||
#SocketBindAllow=
|
||||
|
||||
# If your system doesn't support all of the features below (e.g. because of
|
||||
# the use of a version of systemd older than 247), you may need to comment-out
|
||||
# some of the following lines.
|
||||
|
||||
# n.b. It may be possible to further restrict speedtest, but this is a good
|
||||
# start, and will guard against many potential zero-day vulnerabilities.
|
||||
|
||||
# See the output of `systemd-analyze security speedtest.service` for further
|
||||
# opportunities. Patches welcome!
|
||||
|
||||
CapabilityBoundingSet=
|
||||
LockPersonality=true
|
||||
MemoryDenyWriteExecute=true
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
PrivateDevices=true
|
||||
PrivateUsers=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
ProtectClock=true
|
||||
ProtectControlGroups=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectProc=invisible
|
||||
ProtectHostname=true
|
||||
RemoveIPC=true
|
||||
RestrictNamespaces=true
|
||||
RestrictSUIDSGID=true
|
||||
RestrictRealtime=true
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
|
||||
# Additionally, you may wish to use some of the systemd options documented in
|
||||
# systemd.resource-control(5) to limit the CPU, memory, file-system I/O and
|
||||
# network I/O that the speedtest server is permitted to consume according to
|
||||
# the individual requirements of your installation.
|
||||
|
||||
#CPUQuota=25%
|
||||
#MemoryMax=bytes
|
||||
#MemorySwapMax=bytes
|
||||
#TasksMax=N
|
||||
#IOReadBandwidthMax=device bytes
|
||||
#IOWriteBandwidthMax=device bytes
|
||||
#IOReadIOPSMax=device IOPS, IOWriteIOPSMax=device IOPS
|
||||
#IPAccounting=true
|
||||
#IPAddressAllow=
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
11
systemd/speedtest.socket
Normal file
11
systemd/speedtest.socket
Normal file
@ -0,0 +1,11 @@
|
||||
# Socket listener systemd unit file for speedtest-go. See the
|
||||
# systemd.socket(5) manual page for many more options.
|
||||
[Unit]
|
||||
Description=Speedtest Web Server (http port 80) Socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=80
|
||||
Accept=no
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
490
web/assets/example-multipleServers-full.html
Executable file
490
web/assets/example-multipleServers-full.html
Executable file
@ -0,0 +1,490 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
|
||||
<meta charset="UTF-8" />
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
function I(i){return document.getElementById(i);}
|
||||
|
||||
//LIST OF TEST SERVERS. See documentation for details if needed
|
||||
var SPEEDTEST_SERVERS=[
|
||||
{ //this server doesn't actually exist, remove it
|
||||
name:"Example Server 1", //user friendly name for the server
|
||||
server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
|
||||
dlURL:"backend/garbage.php", //path to download test on this server (garbage.php or replacement)
|
||||
ulURL:"backend/empty.php", //path to upload test on this server (empty.php or replacement)
|
||||
pingURL:"backend/empty.php", //path to ping/jitter test on this server (empty.php or replacement)
|
||||
getIpURL:"backend/getIP.php" //path to getIP on this server (getIP.php or replacement)
|
||||
},
|
||||
{ //this server doesn't actually exist, remove it
|
||||
name:"Example Server 2", //user friendly name for the server
|
||||
server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
|
||||
dlURL:"garbage.php", //path to download test on this server (garbage.php or replacement)
|
||||
ulURL:"empty.php", //path to upload test on this server (empty.php or replacement)
|
||||
pingURL:"empty.php", //path to ping/jitter test on this server (empty.php or replacement)
|
||||
getIpURL:"getIP.php" //path to getIP on this server (getIP.php or replacement)
|
||||
}
|
||||
//add other servers here, comma separated
|
||||
];
|
||||
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s=new Speedtest(); //create speedtest object
|
||||
s.setParameter("telemetry_level","basic"); //enable telemetry
|
||||
|
||||
//SERVER AUTO SELECTION
|
||||
function initServers(){
|
||||
var noServersAvailable=function(){
|
||||
I("message").innerHTML="No servers available";
|
||||
}
|
||||
var runServerSelect=function(){
|
||||
s.selectServer(function(server){
|
||||
if(server!=null){ //at least 1 server is available
|
||||
I("loading").className="hidden"; //hide loading message
|
||||
//populate server list for manual selection
|
||||
for(var i=0;i<SPEEDTEST_SERVERS.length;i++){
|
||||
if(SPEEDTEST_SERVERS[i].pingT==-1) continue;
|
||||
var option=document.createElement("option");
|
||||
option.value=i;
|
||||
option.textContent=SPEEDTEST_SERVERS[i].name;
|
||||
if(SPEEDTEST_SERVERS[i]===server) option.selected=true;
|
||||
I("server").appendChild(option);
|
||||
}
|
||||
//show test UI
|
||||
I("testWrapper").className="visible";
|
||||
initUI();
|
||||
}else{ //no servers are available, the test cannot proceed
|
||||
noServersAvailable();
|
||||
}
|
||||
});
|
||||
}
|
||||
if(typeof SPEEDTEST_SERVERS === "string"){
|
||||
//need to fetch list of servers from specified URL
|
||||
s.loadServerList(SPEEDTEST_SERVERS,function(servers){
|
||||
if(servers==null){ //failed to load server list
|
||||
noServersAvailable();
|
||||
}else{ //server list loaded
|
||||
SPEEDTEST_SERVERS=servers;
|
||||
runServerSelect();
|
||||
}
|
||||
});
|
||||
}else{
|
||||
//hardcoded server list
|
||||
s.addTestPoints(SPEEDTEST_SERVERS);
|
||||
runServerSelect();
|
||||
}
|
||||
}
|
||||
|
||||
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
|
||||
var dlColor="#6060AA",
|
||||
ulColor="#616161";
|
||||
var progColor=meterBk;
|
||||
|
||||
//CODE FOR GAUGES
|
||||
function drawMeter(c,amount,bk,fg,progress,prog){
|
||||
var ctx=c.getContext("2d");
|
||||
var dp=window.devicePixelRatio||1;
|
||||
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
|
||||
var sizScale=ch*0.0055;
|
||||
if(c.width==cw&&c.height==ch){
|
||||
ctx.clearRect(0,0,cw,ch);
|
||||
}else{
|
||||
c.width=cw;
|
||||
c.height=ch;
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle=bk;
|
||||
ctx.lineWidth=12*sizScale;
|
||||
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle=fg;
|
||||
ctx.lineWidth=12*sizScale;
|
||||
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
|
||||
ctx.stroke();
|
||||
if(typeof progress !== "undefined"){
|
||||
ctx.fillStyle=prog;
|
||||
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
|
||||
}
|
||||
}
|
||||
function mbpsToAmount(s){
|
||||
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
|
||||
}
|
||||
function format(d){
|
||||
d=Number(d);
|
||||
if(d<10) return d.toFixed(2);
|
||||
if(d<100) return d.toFixed(1);
|
||||
return d.toFixed(0);
|
||||
}
|
||||
|
||||
//UI CODE
|
||||
var uiData=null;
|
||||
function startStop(){
|
||||
if(s.getState()==3){
|
||||
//speedtest is running, abort
|
||||
s.abort();
|
||||
data=null;
|
||||
I("startStopBtn").className="";
|
||||
I("server").disabled=false;
|
||||
initUI();
|
||||
}else{
|
||||
//test is not running, begin
|
||||
I("startStopBtn").className="running";
|
||||
I("shareArea").style.display="none";
|
||||
I("server").disabled=true;
|
||||
s.onupdate=function(data){
|
||||
uiData=data;
|
||||
};
|
||||
s.onend=function(aborted){
|
||||
I("startStopBtn").className="";
|
||||
I("server").disabled=false;
|
||||
updateUI(true);
|
||||
if(!aborted){
|
||||
//if testId is present, show sharing panel, otherwise do nothing
|
||||
try{
|
||||
var testId=uiData.testId;
|
||||
if(testId!=null){
|
||||
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
|
||||
I("resultsImg").src=shareURL;
|
||||
I("resultsURL").value=shareURL;
|
||||
I("testId").innerHTML=testId;
|
||||
I("shareArea").style.display="";
|
||||
}
|
||||
}catch(e){}
|
||||
}
|
||||
};
|
||||
s.start();
|
||||
}
|
||||
}
|
||||
//this function reads the data sent back by the test and updates the UI
|
||||
function updateUI(forced){
|
||||
if(!forced&&s.getState()!=3) return;
|
||||
if(uiData==null) return;
|
||||
var status=uiData.testState;
|
||||
I("ip").textContent=uiData.clientIp;
|
||||
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
|
||||
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
|
||||
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
|
||||
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
|
||||
I("pingText").textContent=format(uiData.pingStatus);
|
||||
I("jitText").textContent=format(uiData.jitterStatus);
|
||||
}
|
||||
function oscillate(){
|
||||
return 1+0.02*Math.sin(Date.now()/100);
|
||||
}
|
||||
//update the UI every frame
|
||||
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
|
||||
function frame(){
|
||||
requestAnimationFrame(frame);
|
||||
updateUI();
|
||||
}
|
||||
frame(); //start frame loop
|
||||
//function to (re)initialize UI
|
||||
function initUI(){
|
||||
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
|
||||
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
|
||||
I("dlText").textContent="";
|
||||
I("ulText").textContent="";
|
||||
I("pingText").textContent="";
|
||||
I("jitText").textContent="";
|
||||
I("ip").textContent="";
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
html,body{
|
||||
border:none; padding:0; margin:0;
|
||||
background:#FFFFFF;
|
||||
color:#202020;
|
||||
}
|
||||
body{
|
||||
text-align:center;
|
||||
font-family:"Roboto",sans-serif;
|
||||
}
|
||||
h1{
|
||||
color:#404040;
|
||||
}
|
||||
#loading{
|
||||
background-color:#FFFFFF;
|
||||
color:#404040;
|
||||
text-align:center;
|
||||
}
|
||||
span.loadCircle{
|
||||
display:inline-block;
|
||||
width:2em;
|
||||
height:2em;
|
||||
vertical-align:middle;
|
||||
background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAP1BMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZyFzwnAAAAFHRSTlMAEvRFvX406baecwbf0casimhSHyiwmqgAAADpSURBVHja7dbJbQMxAENRahnN5lkc//5rDRAkDeRgHszXgACJoKiIiIiIiIiIiIiIiIiIiIj4HHspsrpAVhdVVguzrA4OWc10WcEqpwKbnBo0OU1Q5NSpsoJFTgOecrrdEag85DRgktNqfoEdTjnd7hrEHMEJvmRUYJbTYk5Agy6nau6Abp5Cm7mDBtRdPi9gyKdU7w4p1fsLvyqs8hl4z9/w3n/Hmr9WoQ65lAU4d7lMYOz//QboRR5jBZibLMZdAR6O/Vfa1PlxNr3XdS3HzK/HVPRu/KnLs8iAOh993VpRRERERMT/fAN60wwWaVyWwAAAAABJRU5ErkJggg==');
|
||||
background-size:2em 2em;
|
||||
margin-right:0.5em;
|
||||
animation: spin 0.6s linear infinite;
|
||||
}
|
||||
@keyframes spin{
|
||||
0%{transform:rotate(0deg);}
|
||||
100%{transform:rotate(359deg);}
|
||||
}
|
||||
#startStopBtn{
|
||||
display:inline-block;
|
||||
margin:0 auto;
|
||||
color:#6060AA;
|
||||
background-color:rgba(0,0,0,0);
|
||||
border:0.15em solid #6060FF;
|
||||
border-radius:0.3em;
|
||||
transition:all 0.3s;
|
||||
box-sizing:border-box;
|
||||
width:8em; height:3em;
|
||||
line-height:2.7em;
|
||||
cursor:pointer;
|
||||
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn:hover{
|
||||
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn.running{
|
||||
background-color:#FF3030;
|
||||
border-color:#FF6060;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
#startStopBtn:before{
|
||||
content:"Start";
|
||||
}
|
||||
#startStopBtn.running:before{
|
||||
content:"Abort";
|
||||
}
|
||||
#serverArea{
|
||||
margin-top:1em;
|
||||
}
|
||||
#server{
|
||||
font-size:1em;
|
||||
padding:0.2em;
|
||||
}
|
||||
#test{
|
||||
margin-top:2em;
|
||||
margin-bottom:12em;
|
||||
}
|
||||
div.testArea{
|
||||
display:inline-block;
|
||||
width:16em;
|
||||
height:12.5em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
div.testArea2{
|
||||
display:inline-block;
|
||||
width:14em;
|
||||
height:7em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
text-align:center;
|
||||
}
|
||||
div.testArea div.testName{
|
||||
position:absolute;
|
||||
top:0.1em; left:0;
|
||||
width:100%;
|
||||
font-size:1.4em;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.testName{
|
||||
display:block;
|
||||
text-align:center;
|
||||
font-size:1.4em;
|
||||
}
|
||||
div.testArea div.meterText{
|
||||
position:absolute;
|
||||
bottom:1.55em; left:0;
|
||||
width:100%;
|
||||
font-size:2.5em;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.meterText{
|
||||
display:inline-block;
|
||||
font-size:2.5em;
|
||||
}
|
||||
div.meterText:empty:before{
|
||||
content:"0.00";
|
||||
}
|
||||
div.testArea div.unit{
|
||||
position:absolute;
|
||||
bottom:2em; left:0;
|
||||
width:100%;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.unit{
|
||||
display:inline-block;
|
||||
}
|
||||
div.testArea canvas{
|
||||
position:absolute;
|
||||
top:0; left:0; width:100%; height:100%;
|
||||
z-index:1;
|
||||
}
|
||||
div.testGroup{
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#shareArea{
|
||||
width:95%;
|
||||
max-width:40em;
|
||||
margin:0 auto;
|
||||
margin-top:2em;
|
||||
}
|
||||
#shareArea > *{
|
||||
display:block;
|
||||
width:100%;
|
||||
height:auto;
|
||||
margin: 0.25em 0;
|
||||
}
|
||||
#privacyPolicy{
|
||||
position:fixed;
|
||||
top:2em;
|
||||
bottom:2em;
|
||||
left:2em;
|
||||
right:2em;
|
||||
overflow-y:auto;
|
||||
width:auto;
|
||||
height:auto;
|
||||
box-shadow:0 0 3em 1em #000000;
|
||||
z-index:999999;
|
||||
text-align:left;
|
||||
background-color:#FFFFFF;
|
||||
padding:1em;
|
||||
}
|
||||
a.privacy{
|
||||
text-align:center;
|
||||
font-size:0.8em;
|
||||
color:#808080;
|
||||
padding: 0 3em;
|
||||
}
|
||||
div.closePrivacyPolicy {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
div.closePrivacyPolicy a.privacy {
|
||||
padding: 1em 3em;
|
||||
}
|
||||
@media all and (max-width:40em){
|
||||
body{
|
||||
font-size:0.8em;
|
||||
}
|
||||
}
|
||||
div.visible{
|
||||
animation: fadeIn 0.4s;
|
||||
display:block;
|
||||
}
|
||||
div.hidden{
|
||||
animation: fadeOut 0.4s;
|
||||
display:none;
|
||||
}
|
||||
@keyframes fadeIn{
|
||||
0%{
|
||||
opacity:0;
|
||||
}
|
||||
100%{
|
||||
opacity:1;
|
||||
}
|
||||
}
|
||||
@keyframes fadeOut{
|
||||
0%{
|
||||
display:block;
|
||||
opacity:1;
|
||||
}
|
||||
100%{
|
||||
display:block;
|
||||
opacity:0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title>LibreSpeed Example</title>
|
||||
</head>
|
||||
<body onload="initServers()">
|
||||
<h1>LibreSpeed Example</h1>
|
||||
<div id="loading" class="visible">
|
||||
<p id="message"><span class="loadCircle"></span>Selecting a server...</p>
|
||||
</div>
|
||||
<div id="testWrapper" class="hidden">
|
||||
<div id="startStopBtn" onclick="startStop()"></div><br/>
|
||||
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
|
||||
<div id="serverArea">
|
||||
Server: <select id="server" onchange="s.setSelectedServer(SPEEDTEST_SERVERS[this.value])"></select>
|
||||
</div>
|
||||
<div id="test">
|
||||
<div class="testGroup">
|
||||
<div class="testArea2">
|
||||
<div class="testName">Ping</div>
|
||||
<div id="pingText" class="meterText" style="color:#AA6060"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
<div class="testArea2">
|
||||
<div class="testName">Jitter</div>
|
||||
<div id="jitText" class="meterText" style="color:#AA6060"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<canvas id="dlMeter" class="meter"></canvas>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<canvas id="ulMeter" class="meter"></canvas>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ipArea">
|
||||
<span id="ip"></span>
|
||||
</div>
|
||||
<div id="shareArea" style="display:none">
|
||||
<h3>Share results</h3>
|
||||
<p>Test ID: <span id="testId"></span></p>
|
||||
<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
|
||||
<img src="" id="resultsImg" />
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
</div>
|
||||
<div id="privacyPolicy" style="display:none">
|
||||
<h2>Privacy Policy</h2>
|
||||
<p>This HTML5 Speedtest server is configured with telemetry enabled.</p>
|
||||
<h4>What data we collect</h4>
|
||||
<p>
|
||||
At the end of the test, the following data is collected and stored:
|
||||
<ul>
|
||||
<li>Test ID</li>
|
||||
<li>Time of testing</li>
|
||||
<li>Test results (download and upload speed, ping and jitter)</li>
|
||||
<li>IP address</li>
|
||||
<li>ISP information</li>
|
||||
<li>Approximate location (inferred from IP address, not GPS)</li>
|
||||
<li>User agent and browser locale</li>
|
||||
<li>Test log (contains no personal information)</li>
|
||||
</ul>
|
||||
</p>
|
||||
<h4>How we use the data</h4>
|
||||
<p>
|
||||
Data collected through this service is used to:
|
||||
<ul>
|
||||
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
|
||||
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
|
||||
</ul>
|
||||
No personal information is disclosed to third parties.
|
||||
</p>
|
||||
<h4>Your consent</h4>
|
||||
<p>
|
||||
By starting the test, you consent to the terms of this privacy policy.
|
||||
</p>
|
||||
<h4>Data removal</h4>
|
||||
<p>
|
||||
If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
|
||||
Contact this email address for all deletion requests: <a href="mailto:PUT@YOUR_EMAIL.HERE">TO BE FILLED BY DEVELOPER</a>.
|
||||
</p>
|
||||
<br/><br/>
|
||||
<div class="closePrivacyPolicy">
|
||||
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
245
web/assets/example-multipleServers-pretty.html
Executable file
245
web/assets/example-multipleServers-pretty.html
Executable file
@ -0,0 +1,245 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
|
||||
<title>LibreSpeed Example</title>
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
//LIST OF TEST SERVERS. See documentation for details if needed
|
||||
var SPEEDTEST_SERVERS=[
|
||||
{ //this server doesn't actually exist, remove it
|
||||
name:"Example Server 1", //user friendly name for the server
|
||||
server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
|
||||
dlURL:"backend/garbage.php", //path to download test on this server (garbage.php or replacement)
|
||||
ulURL:"backend/empty.php", //path to upload test on this server (empty.php or replacement)
|
||||
pingURL:"backend/empty.php", //path to ping/jitter test on this server (empty.php or replacement)
|
||||
getIpURL:"backend/getIP.php" //path to getIP on this server (getIP.php or replacement)
|
||||
},
|
||||
{ //this server doesn't actually exist, remove it
|
||||
name:"Example Server 2", //user friendly name for the server
|
||||
server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
|
||||
dlURL:"garbage.php", //path to download test on this server (garbage.php or replacement)
|
||||
ulURL:"empty.php", //path to upload test on this server (empty.php or replacement)
|
||||
pingURL:"empty.php", //path to ping/jitter test on this server (empty.php or replacement)
|
||||
getIpURL:"getIP.php" //path to getIP on this server (getIP.php or replacement)
|
||||
}
|
||||
//add other servers here, comma separated
|
||||
];
|
||||
|
||||
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s=new Speedtest(); //create speedtest object
|
||||
|
||||
s.onupdate=function(data){ //callback to update data in UI
|
||||
I("ip").textContent=data.clientIp;
|
||||
I("dlText").textContent=(data.testState==1&&data.dlStatus==0)?"...":data.dlStatus;
|
||||
I("ulText").textContent=(data.testState==3&&data.ulStatus==0)?"...":data.ulStatus;
|
||||
I("pingText").textContent=data.pingStatus;
|
||||
I("jitText").textContent=data.jitterStatus;
|
||||
}
|
||||
s.onend=function(aborted){ //callback for test ended/aborted
|
||||
I("startStopBtn").className=""; //show start button again
|
||||
if(aborted){ //if the test was aborted, clear the UI and prepare for new test
|
||||
initUI();
|
||||
}
|
||||
}
|
||||
function selectServer(){ //called after loading server list
|
||||
s.selectServer(function(server){ //run server selection. When the server has been selected, display it in the UI
|
||||
if(server==null){
|
||||
I("serverId").textContent="No servers available";
|
||||
}else{
|
||||
I("startStopBtn").style.display=""; //show start/stop button again
|
||||
I("serverId").textContent=server.name; //show name of test server
|
||||
}
|
||||
});
|
||||
}
|
||||
function loadServers(){ //called when the page is fully loaded
|
||||
I("startStopBtn").style.display="none"; //hide start/stop button during server selection
|
||||
if(typeof SPEEDTEST_SERVERS === "string"){
|
||||
//load servers from url
|
||||
s.loadServerList(SPEEDTEST_SERVERS,function(servers){
|
||||
//list loaded
|
||||
SPEEDTEST_SERVERS=servers;
|
||||
selectServer();
|
||||
});
|
||||
}else{
|
||||
//hardcoded list of servers, already loaded
|
||||
s.addTestPoints(SPEEDTEST_SERVERS);
|
||||
selectServer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function startStop(){ //start/stop button pressed
|
||||
if(s.getState()==3){
|
||||
//speedtest is running, abort
|
||||
s.abort();
|
||||
}else{
|
||||
//test is not running, begin
|
||||
s.start();
|
||||
I("startStopBtn").className="running";
|
||||
}
|
||||
}
|
||||
|
||||
//function to (re)initialize UI
|
||||
function initUI(){
|
||||
I("dlText").textContent="";
|
||||
I("ulText").textContent="";
|
||||
I("pingText").textContent="";
|
||||
I("jitText").textContent="";
|
||||
I("ip").textContent="";
|
||||
}
|
||||
|
||||
function I(id){return document.getElementById(id);}
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
html,body{
|
||||
border:none; padding:0; margin:0;
|
||||
background:#FFFFFF;
|
||||
color:#202020;
|
||||
}
|
||||
body{
|
||||
text-align:center;
|
||||
font-family:"Roboto",sans-serif;
|
||||
}
|
||||
h1{
|
||||
color:#404040;
|
||||
}
|
||||
#startStopBtn{
|
||||
display:inline-block;
|
||||
margin:0 auto;
|
||||
color:#6060AA;
|
||||
background-color:rgba(0,0,0,0);
|
||||
border:0.15em solid #6060FF;
|
||||
border-radius:0.3em;
|
||||
transition:all 0.3s;
|
||||
box-sizing:border-box;
|
||||
width:8em; height:3em;
|
||||
line-height:2.7em;
|
||||
cursor:pointer;
|
||||
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn:hover{
|
||||
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn.running{
|
||||
background-color:#FF3030;
|
||||
border-color:#FF6060;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
#startStopBtn:before{
|
||||
content:"Start";
|
||||
}
|
||||
#startStopBtn.running:before{
|
||||
content:"Abort";
|
||||
}
|
||||
#test{
|
||||
margin-top:2em;
|
||||
margin-bottom:12em;
|
||||
}
|
||||
div.testArea{
|
||||
display:inline-block;
|
||||
width:14em;
|
||||
height:9em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
div.testName{
|
||||
position:absolute;
|
||||
top:0.1em; left:0;
|
||||
width:100%;
|
||||
font-size:1.4em;
|
||||
z-index:9;
|
||||
}
|
||||
div.meterText{
|
||||
position:absolute;
|
||||
bottom:1.5em; left:0;
|
||||
width:100%;
|
||||
font-size:2.5em;
|
||||
z-index:9;
|
||||
}
|
||||
#dlText{
|
||||
color:#6060AA;
|
||||
}
|
||||
#ulText{
|
||||
color:#309030;
|
||||
}
|
||||
#pingText,#jitText{
|
||||
color:#AA6060;
|
||||
}
|
||||
div.meterText:empty:before{
|
||||
color:#505050 !important;
|
||||
content:"0.00";
|
||||
}
|
||||
div.unit{
|
||||
position:absolute;
|
||||
bottom:2em; left:0;
|
||||
width:100%;
|
||||
z-index:9;
|
||||
}
|
||||
div.testGroup{
|
||||
display:inline-block;
|
||||
}
|
||||
@media all and (max-width:65em){
|
||||
body{
|
||||
font-size:1.5vw;
|
||||
}
|
||||
}
|
||||
@media all and (max-width:40em){
|
||||
body{
|
||||
font-size:0.8em;
|
||||
}
|
||||
div.testGroup{
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LibreSpeed Example</h1>
|
||||
<div id="startStopBtn" onclick="startStop()"></div>
|
||||
<div id="serverId">Selecting server...</div>
|
||||
<div id="test">
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Ping</div>
|
||||
<div id="pingText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Jitter</div>
|
||||
<div id="jitText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ipArea">
|
||||
IP Address: <span id="ip"></span>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
<script type="text/javascript">
|
||||
initUI();
|
||||
loadServers();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
38
web/assets/example-singleServer-basic.html
Executable file
38
web/assets/example-singleServer-basic.html
Executable file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="UTF-8" />
|
||||
<head>
|
||||
<title>LibreSpeed Example</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
</head>
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<body>
|
||||
<h1>LibreSpeed Example</h1>
|
||||
|
||||
<h4>IP Address</h4>
|
||||
<p id="ip"></p>
|
||||
|
||||
<h4>Download</h4>
|
||||
<p id="download"></p>
|
||||
|
||||
<h4>Upload</h4>
|
||||
<p id="upload"></p>
|
||||
|
||||
<h4>Latency</h4>
|
||||
<p id="ping"></p>
|
||||
|
||||
<script type="text/javascript">
|
||||
var s=new Speedtest();
|
||||
s.onupdate = function (data) { // when status is received, put the values in the appropriate fields
|
||||
document.getElementById('download').textContent = data.dlStatus + ' Mbit/s'
|
||||
document.getElementById('upload').textContent = data.ulStatus + ' Mbit/s'
|
||||
document.getElementById('ping').textContent = data.pingStatus + ' ms, ' + data.jitterStatus + ' ms jitter'
|
||||
document.getElementById('ip').textContent = data.clientIp
|
||||
}
|
||||
s.start(); // start the speedtest with default settings
|
||||
</script>
|
||||
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
|
||||
</body>
|
||||
</html>
|
256
web/assets/example-singleServer-chart.html
Executable file
256
web/assets/example-singleServer-chart.html
Executable file
@ -0,0 +1,256 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>LibreSpeed Example</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<style type="text/css">
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#startBtn {
|
||||
display: inline-block;
|
||||
border: 0.15em solid #000000;
|
||||
padding: 0.3em 0.5em;
|
||||
margin: 0.6em;
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#ip {
|
||||
margin: 0.8em 0;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#chart1Area,
|
||||
#chart2Area {
|
||||
width: 100%;
|
||||
max-width: 30em;
|
||||
height: 10em;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script> <!--THIS LIBRARY SUCKS!-->
|
||||
<script src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
var s = null
|
||||
function runTest() {
|
||||
var chart1ctx = document.getElementById('chart1Area').getContext('2d')
|
||||
var chart2ctx = document.getElementById('chart2Area').getContext('2d')
|
||||
var dlDataset = {
|
||||
label: 'Download',
|
||||
fill: false,
|
||||
lineTension: 0.1,
|
||||
backgroundColor: 'rgba(75,192,192,0.4)',
|
||||
borderColor: 'rgba(75,192,192,1)',
|
||||
borderCapStyle: 'butt',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.0,
|
||||
borderJoinStyle: 'miter',
|
||||
pointBorderColor: 'rgba(75,192,192,1)',
|
||||
pointBackgroundColor: '#fff',
|
||||
pointBorderWidth: 1,
|
||||
pointHoverRadius: 5,
|
||||
pointHoverBackgroundColor: 'rgba(75,192,192,1)',
|
||||
pointHoverBorderColor: 'rgba(220,220,220,1)',
|
||||
pointHoverBorderWidth: 2,
|
||||
pointRadius: 1,
|
||||
pointHitRadius: 10,
|
||||
data: [0],
|
||||
spanGaps: false
|
||||
}
|
||||
var ulDataset = {
|
||||
label: 'Upload',
|
||||
fill: false,
|
||||
lineTension: 0.1,
|
||||
backgroundColor: 'rgba(192,192,75,0.4)',
|
||||
borderColor: 'rgba(192,192,75,1)',
|
||||
borderCapStyle: 'butt',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.0,
|
||||
borderJoinStyle: 'miter',
|
||||
pointBorderColor: 'rgba(192,192,75,1)',
|
||||
pointBackgroundColor: '#fff',
|
||||
pointBorderWidth: 1,
|
||||
pointHoverRadius: 5,
|
||||
pointHoverBackgroundColor: 'rgba(192,192,75,1)',
|
||||
pointHoverBorderColor: 'rgba(220,220,220,1)',
|
||||
pointHoverBorderWidth: 2,
|
||||
pointRadius: 1,
|
||||
pointHitRadius: 10,
|
||||
data: [0],
|
||||
spanGaps: false
|
||||
}
|
||||
var pingDataset = {
|
||||
label: 'Ping',
|
||||
fill: false,
|
||||
lineTension: 0.1,
|
||||
backgroundColor: 'rgba(75,220,75,0.4)',
|
||||
borderColor: 'rgba(75,220,75,1)',
|
||||
borderCapStyle: 'butt',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.0,
|
||||
borderJoinStyle: 'miter',
|
||||
pointBorderColor: 'rgba(75,220,75,1)',
|
||||
pointBackgroundColor: '#fff',
|
||||
pointBorderWidth: 1,
|
||||
pointHoverRadius: 5,
|
||||
pointHoverBackgroundColor: 'rgba(75,220,75,1)',
|
||||
pointHoverBorderColor: 'rgba(220,220,220,1)',
|
||||
pointHoverBorderWidth: 2,
|
||||
pointRadius: 1,
|
||||
pointHitRadius: 10,
|
||||
data: [],
|
||||
spanGaps: false
|
||||
}
|
||||
var jitterDataset = {
|
||||
label: 'Jitter',
|
||||
fill: false,
|
||||
lineTension: 0.1,
|
||||
backgroundColor: 'rgba(220,75,75,0.4)',
|
||||
borderColor: 'rgba(220,75,75,1)',
|
||||
borderCapStyle: 'butt',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.0,
|
||||
borderJoinStyle: 'miter',
|
||||
pointBorderColor: 'rgba(220,75,75,1)',
|
||||
pointBackgroundColor: '#fff',
|
||||
pointBorderWidth: 1,
|
||||
pointHoverRadius: 5,
|
||||
pointHoverBackgroundColor: 'rgba(220,75,75,1)',
|
||||
pointHoverBorderColor: 'rgba(220,220,220,1)',
|
||||
pointHoverBorderWidth: 2,
|
||||
pointRadius: 1,
|
||||
pointHitRadius: 10,
|
||||
data: [],
|
||||
spanGaps: false
|
||||
}
|
||||
|
||||
var chart1Options = {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [dlDataset, ulDataset]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
legend: {
|
||||
position: 'bottom'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
display: true,
|
||||
scaleLabel: 'Speed',
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
var chart2Options = {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [pingDataset, jitterDataset]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
legend: {
|
||||
position: 'bottom'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: false
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
display: true,
|
||||
scaleLabel: 'Latency',
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var chart1 = new Chart(chart1ctx, chart1Options)
|
||||
var chart2 = new Chart(chart2ctx, chart2Options)
|
||||
|
||||
document.getElementById('startBtn').style.display = 'none'
|
||||
document.getElementById('testArea').style.display = ''
|
||||
document.getElementById('abortBtn').style.display = ''
|
||||
s=new Speedtest();
|
||||
s.onupdate = function (data) {
|
||||
var status = data.testState
|
||||
if (status === 1 && Number(data.dlStatus) > 0) {
|
||||
for(var i=~~(20*Number(data.dlProgress));i<20;i++) chart1.data.datasets[0].data[i]=(Number(data.dlStatus))
|
||||
chart1.data.labels[chart1.data.datasets[0].data.length - 1] = ''
|
||||
chart1.update()
|
||||
}
|
||||
if (status === 3 && Number(data.ulStatus) > 0) {
|
||||
for(var i=~~(20*Number(data.ulProgress));i<20;i++) chart1.data.datasets[1].data[i]=(Number(data.ulStatus))
|
||||
chart1.data.labels[chart1.data.datasets[1].data.length - 1] = ''
|
||||
chart1.update()
|
||||
}
|
||||
if (status === 2 && Number(data.pingStatus) > 0) {
|
||||
chart2.data.datasets[0].data.push(Number(data.pingStatus))
|
||||
chart2.data.datasets[1].data.push(Number(data.jitterStatus))
|
||||
chart2.data.labels[chart2.data.datasets[0].data.length - 1] = ''
|
||||
chart2.data.labels[chart2.data.datasets[1].data.length - 1] = ''
|
||||
chart2.update()
|
||||
}
|
||||
ip.textContent = data.clientIp
|
||||
}
|
||||
s.onend=function(aborted){
|
||||
document.getElementById('abortBtn').style.display = 'none'
|
||||
document.getElementById('startBtn').style.display = ''
|
||||
s = null
|
||||
if (aborted) {
|
||||
document.getElementById('testArea').style.display = 'none'
|
||||
}
|
||||
}
|
||||
s.start();
|
||||
}
|
||||
function abortTest() {
|
||||
if (s) s.abort();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>LibreSpeed - Chart.js example</h1>
|
||||
<div id="testArea" style="display:none">
|
||||
<p id="ip">Please wait...</p>
|
||||
|
||||
<h2>Speed</h2>
|
||||
<canvas id="chart1Area"></canvas>
|
||||
|
||||
<h2>Latency</h2>
|
||||
<canvas id="chart2Area"></canvas>
|
||||
<br/>
|
||||
<a href="javascript:abortTest()" id="abortBtn">Abort</a>
|
||||
</div>
|
||||
<a href="javascript:runTest()" id="startBtn">Run speedtest</a>
|
||||
<br/><br/> Charts by <a href="http://www.chartjs.org/">Chart.js</a><br/><br/><a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
</body>
|
||||
</html>
|
174
web/assets/example-singleServer-customSettings.html
Executable file
174
web/assets/example-singleServer-customSettings.html
Executable file
@ -0,0 +1,174 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
|
||||
<title>LibreSpeed Example</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s=new Speedtest(); //create speedtest object
|
||||
//CUSTOM SETTINGS HERE
|
||||
s.setParameter("test_order","D_U"); //we only want download and upload test
|
||||
s.setParameter("time_auto",false); //fixed duration for tests
|
||||
s.setParameter("time_dl_max",10); //10 seconds for the download test
|
||||
s.setParameter("time_ul_max",15); //15 seconds for the upload test
|
||||
//END OF CUSTOM SETTINGS
|
||||
s.onupdate=function(data){ //callback to update data in UI
|
||||
I("dlText").textContent=(data.testState==1&&data.dlStatus==0)?"...":data.dlStatus;
|
||||
I("ulText").textContent=(data.testState==3&&data.ulStatus==0)?"...":data.ulStatus;
|
||||
}
|
||||
s.onend=function(aborted){ //callback for test ended/aborted
|
||||
I("startStopBtn").className=""; //show start button again
|
||||
if(aborted){ //if the test was aborted, clear the UI and prepare for new test
|
||||
initUI();
|
||||
}
|
||||
}
|
||||
|
||||
function startStop(){ //start/stop button pressed
|
||||
if(s.getState()==3){
|
||||
//speedtest is running, abort
|
||||
s.abort();
|
||||
}else{
|
||||
//test is not running, begin
|
||||
s.start();
|
||||
I("startStopBtn").className="running";
|
||||
}
|
||||
}
|
||||
|
||||
//function to (re)initialize UI
|
||||
function initUI(){
|
||||
I("dlText").textContent="";
|
||||
I("ulText").textContent="";
|
||||
}
|
||||
|
||||
function I(id){return document.getElementById(id);}
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
html,body{
|
||||
border:none; padding:0; margin:0;
|
||||
background:#FFFFFF;
|
||||
color:#202020;
|
||||
}
|
||||
body{
|
||||
text-align:center;
|
||||
font-family:"Roboto",sans-serif;
|
||||
}
|
||||
h1{
|
||||
color:#404040;
|
||||
}
|
||||
#startStopBtn{
|
||||
display:inline-block;
|
||||
margin:0 auto;
|
||||
color:#6060AA;
|
||||
background-color:rgba(0,0,0,0);
|
||||
border:0.15em solid #6060FF;
|
||||
border-radius:0.3em;
|
||||
transition:all 0.3s;
|
||||
box-sizing:border-box;
|
||||
width:8em; height:3em;
|
||||
line-height:2.7em;
|
||||
cursor:pointer;
|
||||
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn:hover{
|
||||
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn.running{
|
||||
background-color:#FF3030;
|
||||
border-color:#FF6060;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
#startStopBtn:before{
|
||||
content:"Start";
|
||||
}
|
||||
#startStopBtn.running:before{
|
||||
content:"Abort";
|
||||
}
|
||||
#test{
|
||||
margin-top:2em;
|
||||
margin-bottom:12em;
|
||||
}
|
||||
div.testArea{
|
||||
display:inline-block;
|
||||
width:14em;
|
||||
height:9em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
div.testName{
|
||||
position:absolute;
|
||||
top:0.1em; left:0;
|
||||
width:100%;
|
||||
font-size:1.4em;
|
||||
z-index:9;
|
||||
}
|
||||
div.meterText{
|
||||
position:absolute;
|
||||
bottom:1.5em; left:0;
|
||||
width:100%;
|
||||
font-size:2.5em;
|
||||
z-index:9;
|
||||
}
|
||||
#dlText{
|
||||
color:#6060AA;
|
||||
}
|
||||
#ulText{
|
||||
color:#309030;
|
||||
}
|
||||
div.meterText:empty:before{
|
||||
color:#505050 !important;
|
||||
content:"0.00";
|
||||
}
|
||||
div.unit{
|
||||
position:absolute;
|
||||
bottom:2em; left:0;
|
||||
width:100%;
|
||||
z-index:9;
|
||||
}
|
||||
div.testGroup{
|
||||
display:inline-block;
|
||||
}
|
||||
@media all and (max-width:65em){
|
||||
body{
|
||||
font-size:2vw;
|
||||
}
|
||||
}
|
||||
@media all and (max-width:40em){
|
||||
body{
|
||||
font-size:0.8em;
|
||||
}
|
||||
div.testGroup{
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LibreSpeed Example</h1>
|
||||
<div id="startStopBtn" onclick="startStop()"></div>
|
||||
<div id="test">
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
<script type="text/javascript">
|
||||
initUI();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
262
web/assets/example-singleServer-gauges.html
Executable file
262
web/assets/example-singleServer-gauges.html
Executable file
@ -0,0 +1,262 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
function I(i){return document.getElementById(i);}
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s=new Speedtest(); //create speedtest object
|
||||
|
||||
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
|
||||
var dlColor="#6060AA",
|
||||
ulColor="#616161";
|
||||
var progColor=meterBk;
|
||||
|
||||
//CODE FOR GAUGES
|
||||
function drawMeter(c,amount,bk,fg,progress,prog){
|
||||
var ctx=c.getContext("2d");
|
||||
var dp=window.devicePixelRatio||1;
|
||||
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
|
||||
var sizScale=ch*0.0055;
|
||||
if(c.width==cw&&c.height==ch){
|
||||
ctx.clearRect(0,0,cw,ch);
|
||||
}else{
|
||||
c.width=cw;
|
||||
c.height=ch;
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle=bk;
|
||||
ctx.lineWidth=12*sizScale;
|
||||
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle=fg;
|
||||
ctx.lineWidth=12*sizScale;
|
||||
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
|
||||
ctx.stroke();
|
||||
if(typeof progress !== "undefined"){
|
||||
ctx.fillStyle=prog;
|
||||
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
|
||||
}
|
||||
}
|
||||
function mbpsToAmount(s){
|
||||
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
|
||||
}
|
||||
function format(d){
|
||||
d=Number(d);
|
||||
if(d<10) return d.toFixed(2);
|
||||
if(d<100) return d.toFixed(1);
|
||||
return d.toFixed(0);
|
||||
}
|
||||
|
||||
//UI CODE
|
||||
var uiData=null;
|
||||
function startStop(){
|
||||
if(s.getState()==3){
|
||||
//speedtest is running, abort
|
||||
s.abort();
|
||||
data=null;
|
||||
I("startStopBtn").className="";
|
||||
initUI();
|
||||
}else{
|
||||
//test is not running, begin
|
||||
I("startStopBtn").className="running";
|
||||
s.onupdate=function(data){
|
||||
uiData=data;
|
||||
};
|
||||
s.onend=function(aborted){
|
||||
I("startStopBtn").className="";
|
||||
updateUI(true);
|
||||
};
|
||||
s.start();
|
||||
}
|
||||
}
|
||||
//this function reads the data sent back by the test and updates the UI
|
||||
function updateUI(forced){
|
||||
if(!forced&&s.getState()!=3) return;
|
||||
if(uiData==null) return;
|
||||
var status=uiData.testState;
|
||||
I("ip").textContent=uiData.clientIp;
|
||||
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
|
||||
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
|
||||
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
|
||||
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
|
||||
I("pingText").textContent=format(uiData.pingStatus);
|
||||
I("jitText").textContent=format(uiData.jitterStatus);
|
||||
}
|
||||
function oscillate(){
|
||||
return 1+0.02*Math.sin(Date.now()/100);
|
||||
}
|
||||
//update the UI every frame
|
||||
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
|
||||
function frame(){
|
||||
requestAnimationFrame(frame);
|
||||
updateUI();
|
||||
}
|
||||
frame(); //start frame loop
|
||||
//function to (re)initialize UI
|
||||
function initUI(){
|
||||
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
|
||||
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
|
||||
I("dlText").textContent="";
|
||||
I("ulText").textContent="";
|
||||
I("pingText").textContent="";
|
||||
I("jitText").textContent="";
|
||||
I("ip").textContent="";
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
html,body{
|
||||
border:none; padding:0; margin:0;
|
||||
background:#FFFFFF;
|
||||
color:#202020;
|
||||
}
|
||||
body{
|
||||
text-align:center;
|
||||
font-family:"Roboto",sans-serif;
|
||||
}
|
||||
h1{
|
||||
color:#404040;
|
||||
}
|
||||
#startStopBtn{
|
||||
display:inline-block;
|
||||
margin:0 auto;
|
||||
color:#6060AA;
|
||||
background-color:rgba(0,0,0,0);
|
||||
border:0.15em solid #6060FF;
|
||||
border-radius:0.3em;
|
||||
transition:all 0.3s;
|
||||
box-sizing:border-box;
|
||||
width:8em; height:3em;
|
||||
line-height:2.7em;
|
||||
cursor:pointer;
|
||||
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn:hover{
|
||||
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn.running{
|
||||
background-color:#FF3030;
|
||||
border-color:#FF6060;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
#startStopBtn:before{
|
||||
content:"Start";
|
||||
}
|
||||
#startStopBtn.running:before{
|
||||
content:"Abort";
|
||||
}
|
||||
#test{
|
||||
margin-top:2em;
|
||||
margin-bottom:12em;
|
||||
}
|
||||
div.testArea{
|
||||
display:inline-block;
|
||||
width:16em;
|
||||
height:12.5em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
div.testArea2{
|
||||
display:inline-block;
|
||||
width:14em;
|
||||
height:7em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
text-align:center;
|
||||
}
|
||||
div.testArea div.testName{
|
||||
position:absolute;
|
||||
top:0.1em; left:0;
|
||||
width:100%;
|
||||
font-size:1.4em;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.testName{
|
||||
display:block;
|
||||
text-align:center;
|
||||
font-size:1.4em;
|
||||
}
|
||||
div.testArea div.meterText{
|
||||
position:absolute;
|
||||
bottom:1.55em; left:0;
|
||||
width:100%;
|
||||
font-size:2.5em;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.meterText{
|
||||
display:inline-block;
|
||||
font-size:2.5em;
|
||||
}
|
||||
div.meterText:empty:before{
|
||||
content:"0.00";
|
||||
}
|
||||
div.testArea div.unit{
|
||||
position:absolute;
|
||||
bottom:2em; left:0;
|
||||
width:100%;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.unit{
|
||||
display:inline-block;
|
||||
}
|
||||
div.testArea canvas{
|
||||
position:absolute;
|
||||
top:0; left:0; width:100%; height:100%;
|
||||
z-index:1;
|
||||
}
|
||||
div.testGroup{
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@media all and (max-width:40em){
|
||||
body{
|
||||
font-size:0.8em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title>LibreSpeed Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LibreSpeed Example</h1>
|
||||
<div id="testWrapper">
|
||||
<div id="startStopBtn" onclick="startStop()"></div>
|
||||
<div id="test">
|
||||
<div class="testGroup">
|
||||
<div class="testArea2">
|
||||
<div class="testName">Ping</div>
|
||||
<div id="pingText" class="meterText" style="color:#AA6060"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
<div class="testArea2">
|
||||
<div class="testName">Jitter</div>
|
||||
<div id="jitText" class="meterText" style="color:#AA6060"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<canvas id="dlMeter" class="meter"></canvas>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<canvas id="ulMeter" class="meter"></canvas>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ipArea">
|
||||
<span id="ip"></span>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
</div>
|
||||
<script type="text/javascript">setTimeout(function(){initUI()},100);</script>
|
||||
</body>
|
||||
</html>
|
192
web/assets/example-singleServer-pretty.html
Executable file
192
web/assets/example-singleServer-pretty.html
Executable file
@ -0,0 +1,192 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
|
||||
<title>LibreSpeed Example</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s=new Speedtest(); //create speedtest object
|
||||
s.onupdate=function(data){ //callback to update data in UI
|
||||
I("ip").textContent=data.clientIp;
|
||||
I("dlText").textContent=(data.testState==1&&data.dlStatus==0)?"...":data.dlStatus;
|
||||
I("ulText").textContent=(data.testState==3&&data.ulStatus==0)?"...":data.ulStatus;
|
||||
I("pingText").textContent=data.pingStatus;
|
||||
I("jitText").textContent=data.jitterStatus;
|
||||
}
|
||||
s.onend=function(aborted){ //callback for test ended/aborted
|
||||
I("startStopBtn").className=""; //show start button again
|
||||
if(aborted){ //if the test was aborted, clear the UI and prepare for new test
|
||||
initUI();
|
||||
}
|
||||
}
|
||||
|
||||
function startStop(){ //start/stop button pressed
|
||||
if(s.getState()==3){
|
||||
//speedtest is running, abort
|
||||
s.abort();
|
||||
}else{
|
||||
//test is not running, begin
|
||||
s.start();
|
||||
I("startStopBtn").className="running";
|
||||
}
|
||||
}
|
||||
|
||||
//function to (re)initialize UI
|
||||
function initUI(){
|
||||
I("dlText").textContent="";
|
||||
I("ulText").textContent="";
|
||||
I("pingText").textContent="";
|
||||
I("jitText").textContent="";
|
||||
I("ip").textContent="";
|
||||
}
|
||||
|
||||
function I(id){return document.getElementById(id);}
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
html,body{
|
||||
border:none; padding:0; margin:0;
|
||||
background:#FFFFFF;
|
||||
color:#202020;
|
||||
}
|
||||
body{
|
||||
text-align:center;
|
||||
font-family:"Roboto",sans-serif;
|
||||
}
|
||||
h1{
|
||||
color:#404040;
|
||||
}
|
||||
#startStopBtn{
|
||||
display:inline-block;
|
||||
margin:0 auto;
|
||||
color:#6060AA;
|
||||
background-color:rgba(0,0,0,0);
|
||||
border:0.15em solid #6060FF;
|
||||
border-radius:0.3em;
|
||||
transition:all 0.3s;
|
||||
box-sizing:border-box;
|
||||
width:8em; height:3em;
|
||||
line-height:2.7em;
|
||||
cursor:pointer;
|
||||
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn:hover{
|
||||
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn.running{
|
||||
background-color:#FF3030;
|
||||
border-color:#FF6060;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
#startStopBtn:before{
|
||||
content:"Start";
|
||||
}
|
||||
#startStopBtn.running:before{
|
||||
content:"Abort";
|
||||
}
|
||||
#test{
|
||||
margin-top:2em;
|
||||
margin-bottom:12em;
|
||||
}
|
||||
div.testArea{
|
||||
display:inline-block;
|
||||
width:14em;
|
||||
height:9em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
div.testName{
|
||||
position:absolute;
|
||||
top:0.1em; left:0;
|
||||
width:100%;
|
||||
font-size:1.4em;
|
||||
z-index:9;
|
||||
}
|
||||
div.meterText{
|
||||
position:absolute;
|
||||
bottom:1.5em; left:0;
|
||||
width:100%;
|
||||
font-size:2.5em;
|
||||
z-index:9;
|
||||
}
|
||||
#dlText{
|
||||
color:#6060AA;
|
||||
}
|
||||
#ulText{
|
||||
color:#309030;
|
||||
}
|
||||
#pingText,#jitText{
|
||||
color:#AA6060;
|
||||
}
|
||||
div.meterText:empty:before{
|
||||
color:#505050 !important;
|
||||
content:"0.00";
|
||||
}
|
||||
div.unit{
|
||||
position:absolute;
|
||||
bottom:2em; left:0;
|
||||
width:100%;
|
||||
z-index:9;
|
||||
}
|
||||
div.testGroup{
|
||||
display:inline-block;
|
||||
}
|
||||
@media all and (max-width:65em){
|
||||
body{
|
||||
font-size:1.5vw;
|
||||
}
|
||||
}
|
||||
@media all and (max-width:40em){
|
||||
body{
|
||||
font-size:0.8em;
|
||||
}
|
||||
div.testGroup{
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LibreSpeed Example</h1>
|
||||
<div id="startStopBtn" onclick="startStop()"></div>
|
||||
<div id="test">
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Ping</div>
|
||||
<div id="pingText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Jitter</div>
|
||||
<div id="jitText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ipArea">
|
||||
IP Address: <span id="ip"></span>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
<script type="text/javascript">
|
||||
initUI();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
212
web/assets/example-singleServer-progressBar.html
Executable file
212
web/assets/example-singleServer-progressBar.html
Executable file
@ -0,0 +1,212 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
|
||||
<title>LibreSpeed Example</title>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s=new Speedtest(); //create speedtest object
|
||||
s.onupdate=function(data){ //callback to update data in UI
|
||||
I("ip").textContent=data.clientIp;
|
||||
I("dlText").textContent=(data.testState==1&&data.dlStatus==0)?"...":data.dlStatus;
|
||||
I("ulText").textContent=(data.testState==3&&data.ulStatus==0)?"...":data.ulStatus;
|
||||
I("pingText").textContent=data.pingStatus;
|
||||
I("jitText").textContent=data.jitterStatus;
|
||||
var prog=(Number(data.dlProgress)*2+Number(data.ulProgress)*2+Number(data.pingProgress))/5;
|
||||
I("progress").style.width=(100*prog)+"%";
|
||||
}
|
||||
s.onend=function(aborted){ //callback for test ended/aborted
|
||||
I("startStopBtn").className=""; //show start button again
|
||||
if(aborted){ //if the test was aborted, clear the UI and prepare for new test
|
||||
initUI();
|
||||
}
|
||||
}
|
||||
|
||||
function startStop(){ //start/stop button pressed
|
||||
if(s.getState()==3){
|
||||
//speedtest is running, abort
|
||||
s.abort();
|
||||
}else{
|
||||
//test is not running, begin
|
||||
s.start();
|
||||
I("startStopBtn").className="running";
|
||||
}
|
||||
}
|
||||
|
||||
//function to (re)initialize UI
|
||||
function initUI(){
|
||||
I("dlText").textContent="";
|
||||
I("ulText").textContent="";
|
||||
I("pingText").textContent="";
|
||||
I("jitText").textContent="";
|
||||
I("ip").textContent="";
|
||||
}
|
||||
|
||||
function I(id){return document.getElementById(id);}
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
html,body{
|
||||
border:none; padding:0; margin:0;
|
||||
background:#FFFFFF;
|
||||
color:#202020;
|
||||
}
|
||||
body{
|
||||
text-align:center;
|
||||
font-family:"Roboto",sans-serif;
|
||||
}
|
||||
h1{
|
||||
color:#404040;
|
||||
}
|
||||
#startStopBtn{
|
||||
display:inline-block;
|
||||
margin:0 auto;
|
||||
color:#6060AA;
|
||||
background-color:rgba(0,0,0,0);
|
||||
border:0.15em solid #6060FF;
|
||||
border-radius:0.3em;
|
||||
transition:all 0.3s;
|
||||
box-sizing:border-box;
|
||||
width:8em; height:3em;
|
||||
line-height:2.7em;
|
||||
cursor:pointer;
|
||||
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn:hover{
|
||||
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn.running{
|
||||
background-color:#FF3030;
|
||||
border-color:#FF6060;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
#startStopBtn:before{
|
||||
content:"Start";
|
||||
}
|
||||
#startStopBtn.running:before{
|
||||
content:"Abort";
|
||||
}
|
||||
#test{
|
||||
margin-top:2em;
|
||||
margin-bottom:12em;
|
||||
}
|
||||
div.testArea{
|
||||
display:inline-block;
|
||||
width:14em;
|
||||
height:9em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
div.testName{
|
||||
position:absolute;
|
||||
top:0.1em; left:0;
|
||||
width:100%;
|
||||
font-size:1.4em;
|
||||
z-index:9;
|
||||
}
|
||||
div.meterText{
|
||||
position:absolute;
|
||||
bottom:1.5em; left:0;
|
||||
width:100%;
|
||||
font-size:2.5em;
|
||||
z-index:9;
|
||||
}
|
||||
#dlText{
|
||||
color:#6060AA;
|
||||
}
|
||||
#ulText{
|
||||
color:#309030;
|
||||
}
|
||||
#pingText,#jitText{
|
||||
color:#AA6060;
|
||||
}
|
||||
div.meterText:empty:before{
|
||||
color:#505050 !important;
|
||||
content:"0.00";
|
||||
}
|
||||
div.unit{
|
||||
position:absolute;
|
||||
bottom:2em; left:0;
|
||||
width:100%;
|
||||
z-index:9;
|
||||
}
|
||||
div.testGroup{
|
||||
display:inline-block;
|
||||
}
|
||||
@media all and (max-width:65em){
|
||||
body{
|
||||
font-size:1.5vw;
|
||||
}
|
||||
}
|
||||
@media all and (max-width:40em){
|
||||
body{
|
||||
font-size:0.8em;
|
||||
}
|
||||
div.testGroup{
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
#progressBar{
|
||||
width:90%;
|
||||
height:0.3em;
|
||||
background-color:#EEEEEE;
|
||||
position:relative;
|
||||
display:block;
|
||||
margin:0 auto;
|
||||
margin-bottom:2em;
|
||||
}
|
||||
#progress{
|
||||
position:absolute;
|
||||
top:0; left:0;
|
||||
height:100%;
|
||||
width:0%;
|
||||
transition: width 2s;
|
||||
background-color:#90BBFF;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LibreSpeed Example</h1>
|
||||
<div id="startStopBtn" onclick="startStop()"></div>
|
||||
<div id="test">
|
||||
<div id="progressBar"><div id="progress"></div></div>
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Ping</div>
|
||||
<div id="pingText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Jitter</div>
|
||||
<div id="jitText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ipArea">
|
||||
IP Address: <span id="ip"></span>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
<script type="text/javascript">
|
||||
initUI();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
674
web/assets/index.html
Normal file → Executable file
674
web/assets/index.html
Normal file → Executable file
@ -1,479 +1,323 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no"/>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="shortcut icon" href="../../favicon.ico">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Oswald:300,400|Source+Sans+Pro:400,600">
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
function I(i) {
|
||||
return document.getElementById(i);
|
||||
}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
function I(i){return document.getElementById(i);}
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s=new Speedtest(); //create speedtest object
|
||||
s.setParameter("telemetry_level","basic"); //enable telemetry
|
||||
|
||||
var meterBk = "#ebecf0"; // ui--input-border
|
||||
var dlColor = "#02b159", // grass-green
|
||||
ulColor = "#02b159", // grass-green
|
||||
pingColor = "#02b159", // grass-green
|
||||
jitColor = "#02b159"; // grass-green
|
||||
var progColor = "#0ac9f7"; // sky-blue
|
||||
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
|
||||
var dlColor="#6060AA",
|
||||
ulColor="#616161";
|
||||
var progColor=meterBk;
|
||||
|
||||
function setPageTitle() {
|
||||
var pageTitleDiv = document.getElementById('pageTitle');
|
||||
var titlePrefixNode = document.createTextNode("You're currently using this server:");
|
||||
var lineBreakElement = document.createElement('br');
|
||||
var locationNode = document.createTextNode('Unknown');
|
||||
switch (window.location.hostname) {
|
||||
case 'us1.zzz.cat':
|
||||
locationNode.textContent = 'Unites States 1 (Fremont, Linode)';
|
||||
break;
|
||||
case 'us2.zzz.cat':
|
||||
locationNode.textContent = 'Unites States 2 (LAX (CN2), Bandwagon)';
|
||||
break;
|
||||
case 'us3.zzz.cat':
|
||||
locationNode.textContent = 'Unites States 3 (LAX (CN2 GIA-E), Bandwagon)';
|
||||
break;
|
||||
case 'jp1.zzz.cat':
|
||||
locationNode.textContent = 'Japan 1 (Tokyo 2, Linode)';
|
||||
break;
|
||||
case 'jp2.zzz.cat':
|
||||
locationNode.textContent = 'Japan 2 (Tokyo 2, Linode)';
|
||||
break;
|
||||
case 'sg1.zzz.cat':
|
||||
locationNode.textContent = 'Singapore (Singapore, Linode)';
|
||||
break;
|
||||
case 'ca1.zzz.cat':
|
||||
locationNode.textContent = 'Canada (Toronto, Linode)';
|
||||
break;
|
||||
default:
|
||||
locationNode.textContent = window.location.hostname;
|
||||
break;
|
||||
}
|
||||
|
||||
pageTitleDiv.appendChild(titlePrefixNode);
|
||||
pageTitleDiv.appendChild(lineBreakElement);
|
||||
pageTitleDiv.appendChild(locationNode);
|
||||
}
|
||||
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s = new Speedtest(); //create speedtest object
|
||||
|
||||
//CODE FOR GAUGES
|
||||
function drawMeter(c, amount, bk, fg, progress, prog) {
|
||||
var ctx = c.getContext("2d");
|
||||
var dp = window.devicePixelRatio || 1;
|
||||
var cw = c.clientWidth * dp, ch = c.clientHeight * dp;
|
||||
var sizScale = ch * 0.0055;
|
||||
if (c.width == cw && c.height == ch) {
|
||||
ctx.clearRect(0, 0, cw, ch);
|
||||
} else {
|
||||
c.width = cw;
|
||||
c.height = ch;
|
||||
//CODE FOR GAUGES
|
||||
function drawMeter(c,amount,bk,fg,progress,prog){
|
||||
var ctx=c.getContext("2d");
|
||||
var dp=window.devicePixelRatio||1;
|
||||
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
|
||||
var sizScale=ch*0.0055;
|
||||
if(c.width==cw&&c.height==ch){
|
||||
ctx.clearRect(0,0,cw,ch);
|
||||
}else{
|
||||
c.width=cw;
|
||||
c.height=ch;
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = bk;
|
||||
ctx.lineWidth = 4 * sizScale;
|
||||
ctx.arc(c.width / 2, c.height / 2, c.height / 2 - ctx.lineWidth, -Math.PI * 1.2, Math.PI * 0.2);
|
||||
ctx.strokeStyle=bk;
|
||||
ctx.lineWidth=12*sizScale;
|
||||
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = fg;
|
||||
ctx.lineWidth = 4 * sizScale;
|
||||
ctx.arc(c.width / 2, c.height / 2, c.height / 2 - ctx.lineWidth, -Math.PI * 1.2, amount * Math.PI * 1.2 - Math.PI * 1.2);
|
||||
ctx.strokeStyle=fg;
|
||||
ctx.lineWidth=12*sizScale;
|
||||
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
|
||||
ctx.stroke();
|
||||
if (typeof progress !== "undefined") {
|
||||
ctx.fillStyle = prog;
|
||||
ctx.fillRect(c.width * 0.3, c.height - 28 * sizScale, c.width * 0.4 * progress, 4 * sizScale);
|
||||
if(typeof progress !== "undefined"){
|
||||
ctx.fillStyle=prog;
|
||||
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
|
||||
}
|
||||
}
|
||||
|
||||
function mbpsToAmount(s) {
|
||||
return 1 - (1 / (Math.pow(1.3, Math.sqrt(s))));
|
||||
}
|
||||
|
||||
function msToAmount(s) {
|
||||
return 1 - (1 / (Math.pow(1.08, Math.sqrt(s))));
|
||||
}
|
||||
|
||||
function format(d) {
|
||||
d = Number(d);
|
||||
if (d < 10) return d.toFixed(2);
|
||||
if (d < 100) return d.toFixed(1);
|
||||
}
|
||||
function mbpsToAmount(s){
|
||||
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
|
||||
}
|
||||
function format(d){
|
||||
d=Number(d);
|
||||
if(d<10) return d.toFixed(2);
|
||||
if(d<100) return d.toFixed(1);
|
||||
return d.toFixed(0);
|
||||
}
|
||||
}
|
||||
|
||||
//UI CODE
|
||||
var uiData = null;
|
||||
|
||||
function startStop() {
|
||||
if (s.getState() == 3) {
|
||||
//UI CODE
|
||||
var uiData=null;
|
||||
function startStop(){
|
||||
if(s.getState()==3){
|
||||
//speedtest is running, abort
|
||||
s.abort();
|
||||
data = null;
|
||||
I("startStopBtn").className = "";
|
||||
data=null;
|
||||
I("startStopBtn").className="";
|
||||
initUI();
|
||||
} else {
|
||||
}else{
|
||||
//test is not running, begin
|
||||
I("startStopBtn").className = "running";
|
||||
I("shareArea").style.display = "none";
|
||||
s.onupdate = function (data) {
|
||||
uiData = data;
|
||||
I("startStopBtn").className="running";
|
||||
I("shareArea").style.display="none";
|
||||
s.onupdate=function(data){
|
||||
uiData=data;
|
||||
};
|
||||
s.onend = function (aborted) {
|
||||
I("startStopBtn").className = "";
|
||||
s.onend=function(aborted){
|
||||
I("startStopBtn").className="";
|
||||
updateUI(true);
|
||||
if (!aborted) {
|
||||
if(!aborted){
|
||||
//if testId is present, show sharing panel, otherwise do nothing
|
||||
try {
|
||||
var testId = uiData.testId;
|
||||
if (testId != null) {
|
||||
var shareURL = window.location.href.substring(0, window.location.href.lastIndexOf("/")) + "/results?id=" + testId;
|
||||
I("resultsImg").src = shareURL;
|
||||
I("resultsURL").value = shareURL;
|
||||
I("testId").innerHTML = testId;
|
||||
I("shareArea").style.display = "";
|
||||
}
|
||||
} catch (e) {
|
||||
try{
|
||||
var testId=uiData.testId;
|
||||
if(testId!=null){
|
||||
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
|
||||
I("resultsImg").src=shareURL;
|
||||
I("resultsURL").value=shareURL;
|
||||
I("testId").innerHTML=testId;
|
||||
I("shareArea").style.display="";
|
||||
}
|
||||
}catch(e){}
|
||||
}
|
||||
};
|
||||
s.start();
|
||||
}
|
||||
}
|
||||
|
||||
//this function reads the data sent back by the test and updates the UI
|
||||
function updateUI(forced) {
|
||||
if (!forced && s.getState() != 3) return;
|
||||
if (uiData == null) return;
|
||||
var status = uiData.testState;
|
||||
I("ip").textContent = "IP Address: " + uiData.clientIp;
|
||||
I("dlText").textContent = (status == 1 && uiData.dlStatus == 0) ? "..." : format(uiData.dlStatus);
|
||||
drawMeter(I("dlMeter"), mbpsToAmount(Number(uiData.dlStatus * (status == 1 ? oscillate() : 1))), meterBk, dlColor, Number(uiData.dlProgress), progColor);
|
||||
I("ulText").textContent = (status == 3 && uiData.ulStatus == 0) ? "..." : format(uiData.ulStatus);
|
||||
drawMeter(I("ulMeter"), mbpsToAmount(Number(uiData.ulStatus * (status == 3 ? oscillate() : 1))), meterBk, ulColor, Number(uiData.ulProgress), progColor);
|
||||
I("pingText").textContent = format(uiData.pingStatus);
|
||||
drawMeter(I("pingMeter"), msToAmount(Number(uiData.pingStatus * (status == 2 ? oscillate() : 1))), meterBk, pingColor, Number(uiData.pingProgress), progColor);
|
||||
I("jitText").textContent = format(uiData.jitterStatus);
|
||||
drawMeter(I("jitMeter"), msToAmount(Number(uiData.jitterStatus * (status == 2 ? oscillate() : 1))), meterBk, jitColor, Number(uiData.pingProgress), progColor);
|
||||
}
|
||||
|
||||
function oscillate() {
|
||||
return 1 + 0.02 * Math.sin(Date.now() / 100);
|
||||
}
|
||||
|
||||
//update the UI every frame
|
||||
window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || (function (callback, element) {
|
||||
setTimeout(callback, 1000 / 60);
|
||||
});
|
||||
|
||||
function frame() {
|
||||
}
|
||||
//this function reads the data sent back by the test and updates the UI
|
||||
function updateUI(forced){
|
||||
if(!forced&&s.getState()!=3) return;
|
||||
if(uiData==null) return;
|
||||
var status=uiData.testState;
|
||||
I("ip").textContent=uiData.clientIp;
|
||||
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
|
||||
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
|
||||
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
|
||||
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
|
||||
I("pingText").textContent=format(uiData.pingStatus);
|
||||
I("jitText").textContent=format(uiData.jitterStatus);
|
||||
}
|
||||
function oscillate(){
|
||||
return 1+0.02*Math.sin(Date.now()/100);
|
||||
}
|
||||
//update the UI every frame
|
||||
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
|
||||
function frame(){
|
||||
requestAnimationFrame(frame);
|
||||
updateUI();
|
||||
}
|
||||
frame(); //start frame loop
|
||||
//function to (re)initialize UI
|
||||
function initUI(){
|
||||
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
|
||||
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
|
||||
I("dlText").textContent="";
|
||||
I("ulText").textContent="";
|
||||
I("pingText").textContent="";
|
||||
I("jitText").textContent="";
|
||||
I("ip").textContent="";
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
html,body{
|
||||
border:none; padding:0; margin:0;
|
||||
background:#FFFFFF;
|
||||
color:#202020;
|
||||
}
|
||||
|
||||
frame(); //start frame loop
|
||||
//function to (re)initialize UI
|
||||
function initUI() {
|
||||
drawMeter(I("dlMeter"), 0, meterBk, dlColor, 0);
|
||||
drawMeter(I("ulMeter"), 0, meterBk, ulColor, 0);
|
||||
drawMeter(I("pingMeter"), 0, meterBk, pingColor, 0);
|
||||
drawMeter(I("jitMeter"), 0, meterBk, jitColor, 0);
|
||||
I("dlText").textContent = "";
|
||||
I("ulText").textContent = "";
|
||||
I("pingText").textContent = "";
|
||||
I("jitText").textContent = "";
|
||||
I("ip").textContent = "";
|
||||
body{
|
||||
text-align:center;
|
||||
font-family:"Roboto",sans-serif;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
:root {
|
||||
--dark-gray: #32363b;
|
||||
--grass-green: #02b159;
|
||||
h1{
|
||||
color:#404040;
|
||||
}
|
||||
|
||||
html, body {
|
||||
background-color: white;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
color: var(--dark-gray);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
#startStopBtn{
|
||||
display:inline-block;
|
||||
margin:0 auto;
|
||||
color:#6060AA;
|
||||
background-color:rgba(0,0,0,0);
|
||||
border:0.15em solid #6060FF;
|
||||
border-radius:0.3em;
|
||||
transition:all 0.3s;
|
||||
box-sizing:border-box;
|
||||
width:8em; height:3em;
|
||||
line-height:2.7em;
|
||||
cursor:pointer;
|
||||
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
html {
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
#startStopBtn:hover{
|
||||
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 18px;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.33333;
|
||||
font-family: "Source Sans Pro", sans-serif;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
margin: 1rem 1rem 2rem;
|
||||
text-align: center;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
#startStopBtn.running{
|
||||
background-color:#FF3030;
|
||||
border-color:#FF6060;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
|
||||
*, *:before, *:after {
|
||||
box-sizing: inherit;
|
||||
#startStopBtn:before{
|
||||
content:"Start";
|
||||
}
|
||||
|
||||
#startStopBtn {
|
||||
display: inline-block;
|
||||
#startStopBtn.running:before{
|
||||
content:"Abort";
|
||||
}
|
||||
#test{
|
||||
margin-top:2em;
|
||||
margin-bottom:12em;
|
||||
}
|
||||
div.testArea{
|
||||
display:inline-block;
|
||||
width:16em;
|
||||
height:12.5em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
div.testArea2{
|
||||
display:inline-block;
|
||||
width:14em;
|
||||
height:7em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
text-align:center;
|
||||
}
|
||||
div.testArea div.testName{
|
||||
position:absolute;
|
||||
top:0.1em; left:0;
|
||||
width:100%;
|
||||
font-size:1.4em;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.testName{
|
||||
display:block;
|
||||
text-align:center;
|
||||
font-size:1.4em;
|
||||
}
|
||||
div.testArea div.meterText{
|
||||
position:absolute;
|
||||
bottom:1.55em; left:0;
|
||||
width:100%;
|
||||
font-size:2.5em;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.meterText{
|
||||
display:inline-block;
|
||||
font-size:2.5em;
|
||||
}
|
||||
div.meterText:empty:before{
|
||||
content:"0.00";
|
||||
}
|
||||
div.testArea div.unit{
|
||||
position:absolute;
|
||||
bottom:2em; left:0;
|
||||
width:100%;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.unit{
|
||||
display:inline-block;
|
||||
}
|
||||
div.testArea canvas{
|
||||
position:absolute;
|
||||
top:0; left:0; width:100%; height:100%;
|
||||
z-index:1;
|
||||
}
|
||||
div.testGroup{
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
color: white;
|
||||
background-color: var(--grass-green);
|
||||
border: 0.15em solid var(--grass-green);
|
||||
border-radius: 0.3em;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
height: 3em;
|
||||
line-height: 2.7em;
|
||||
cursor: pointer;
|
||||
/*box-shadow:0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);*/
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#startStopBtn:hover {
|
||||
/*box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);*/
|
||||
#shareArea{
|
||||
width:95%;
|
||||
max-width:40em;
|
||||
margin:0 auto;
|
||||
margin-top:2em;
|
||||
}
|
||||
|
||||
#startStopBtn.running {
|
||||
background-color: var(--dark-gray);
|
||||
border-color: var(--dark-gray);
|
||||
color: white;
|
||||
}
|
||||
|
||||
#startStopBtn:before {
|
||||
content: "Start Speed Test";
|
||||
}
|
||||
|
||||
#startStopBtn.running:before {
|
||||
content: "Abort";
|
||||
}
|
||||
|
||||
#test {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
div.testArea {
|
||||
display: inline-block;
|
||||
width: calc(100% - 2rem - 2rem); /* subtract margins */
|
||||
max-width: 16em;
|
||||
margin: 2rem;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
div.testArea::before {
|
||||
content: '';
|
||||
display: block;
|
||||
padding-top: 100%;
|
||||
}
|
||||
|
||||
div.testName {
|
||||
bottom: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
div.meterText {
|
||||
bottom: 1.8em;
|
||||
font-family: "Oswald", sans-serif;
|
||||
font-size: 4em;
|
||||
font-weight: 300;
|
||||
left: 0;
|
||||
line-height: 1;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
div.meterText:empty:before {
|
||||
content: "0.00";
|
||||
}
|
||||
|
||||
div.unit {
|
||||
bottom: 3.5em;
|
||||
font-family: "Oswald", sans-serif;
|
||||
font-size: 1.5em;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.5px;
|
||||
left: 0;
|
||||
line-height: 1;
|
||||
position: absolute;
|
||||
text-transform: uppercase;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
div.testArea canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#ipArea {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#shareArea {
|
||||
width: 95%;
|
||||
max-width: 25em;
|
||||
margin: 0 auto;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#shareArea > * {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
#shareArea > *{
|
||||
display:block;
|
||||
width:100%;
|
||||
height:auto;
|
||||
margin: 0.25em 0;
|
||||
}
|
||||
|
||||
#privacyPolicy {
|
||||
position: fixed;
|
||||
top: 10em;
|
||||
bottom: 10em;
|
||||
left: 15em;
|
||||
right: 15em;
|
||||
overflow-y: auto;
|
||||
width: auto;
|
||||
height: auto;
|
||||
box-shadow: 0 0 3em 1em #000000;
|
||||
z-index: 999999;
|
||||
text-align: left;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1em;
|
||||
#privacyPolicy{
|
||||
position:fixed;
|
||||
top:2em;
|
||||
bottom:2em;
|
||||
left:2em;
|
||||
right:2em;
|
||||
overflow-y:auto;
|
||||
width:auto;
|
||||
height:auto;
|
||||
box-shadow:0 0 3em 1em #000000;
|
||||
z-index:999999;
|
||||
text-align:left;
|
||||
background-color:#FFFFFF;
|
||||
padding:1em;
|
||||
}
|
||||
|
||||
#privacyCloseBtn {
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
color: white;
|
||||
background-color: var(--grass-green);
|
||||
border: 0.15em solid var(--grass-green);
|
||||
border-radius: 0.3em;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
height: 3em;
|
||||
line-height: 2.7em;
|
||||
cursor: pointer;
|
||||
/*box-shadow:0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);*/
|
||||
font-weight: 600;
|
||||
a.privacy{
|
||||
text-align:center;
|
||||
font-size:0.8em;
|
||||
color:#808080;
|
||||
padding: 0 3em;
|
||||
}
|
||||
|
||||
#resultsURL {
|
||||
color: #333;
|
||||
font-size: 1.2rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.2rem;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border: green;
|
||||
display: block;
|
||||
border-style: dashed;
|
||||
border-width: 2px;
|
||||
margin: 0.8em 0 0.8em 0;
|
||||
}
|
||||
|
||||
#testId {
|
||||
margin-top: 1.4em;
|
||||
}
|
||||
|
||||
a.privacy {
|
||||
margin-top: 2em;
|
||||
div.closePrivacyPolicy {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
color: #808080;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media all and (max-width: 65em) {
|
||||
/* 1040 px */
|
||||
div.testGroup {
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
div.closePrivacyPolicy a.privacy {
|
||||
padding: 1em 3em;
|
||||
}
|
||||
|
||||
div.testArea {
|
||||
font-size: 1.5384615vw; /* 16 px */
|
||||
margin: 1rem;
|
||||
width: calc(100% - 1rem - 1rem); /* subtract margins */
|
||||
@media all and (max-width:40em){
|
||||
body{
|
||||
font-size:0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 40em) {
|
||||
/* 640 px */
|
||||
div.testArea {
|
||||
font-size: 0.8em; /* 12.8 px */
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<title>zzz.cat Speedtest</title>
|
||||
</style>
|
||||
<title>LibreSpeed Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LibreSpeed Example</h1>
|
||||
<div id="testWrapper">
|
||||
<h1 id="pageTitle"></h1>
|
||||
<div id="startStopBtn" onclick="startStop()"></div>
|
||||
<br/>
|
||||
<div id="startStopBtn" onclick="startStop()"></div><br/>
|
||||
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
|
||||
<div id="test">
|
||||
<div class="testGroup">
|
||||
<div class="testArea2">
|
||||
<div class="testName">Ping</div>
|
||||
<div id="pingText" class="meterText" style="color:#AA6060"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
<div class="testArea2">
|
||||
<div class="testName">Jitter</div>
|
||||
<div id="jitText" class="meterText" style="color:#AA6060"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<canvas id="dlMeter" class="meter"></canvas>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbit/s</div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<canvas id="ulMeter" class="meter"></canvas>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbit/s</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Ping</div>
|
||||
<canvas id="pingMeter" class="meter"></canvas>
|
||||
<div id="pingText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
|
||||
<div class="testArea">
|
||||
<div class="testName">Jitter</div>
|
||||
<canvas id="jitMeter" class="meter"></canvas>
|
||||
<div id="jitText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
<div class="unit">Mbps</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ipArea">
|
||||
<span id="ip"></span>
|
||||
</div>
|
||||
<div><a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a></div>
|
||||
<div id="shareArea" style="display:none">
|
||||
<h3>Share your results</h3>
|
||||
<input type="text" value="" id="resultsURL" readonly="readonly"
|
||||
onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
|
||||
<img src="" id="resultsImg"/>
|
||||
<h3>Share results</h3>
|
||||
<p>Test ID: <span id="testId"></span></p>
|
||||
<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
|
||||
<img src="" id="resultsImg" />
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
</div>
|
||||
<div id="privacyPolicy" style="display:none">
|
||||
<h2>Privacy Policy</h2>
|
||||
@ -507,17 +351,15 @@
|
||||
</p>
|
||||
<h4>Data removal</h4>
|
||||
<p>
|
||||
If you want to have your information deleted, you need to provide either the ID of the test or your IP address.
|
||||
This is the only way to identify your data, without this information we won't be able to comply with your
|
||||
request.<br/><br/>
|
||||
Contact this email address for all deletion requests: maddie at zzz dot cat.
|
||||
If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
|
||||
Contact this email address for all deletion requests: <a href="mailto:PUT@YOUR_EMAIL.HERE">TO BE FILLED BY DEVELOPER</a>.
|
||||
</p>
|
||||
<br/><br/>
|
||||
<a id="privacyCloseBtn" class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a><br/>
|
||||
<div class="closePrivacyPolicy">
|
||||
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
<script type="text/javascript">setPageTitle();</script>
|
||||
<script type="text/javascript">setTimeout(function () {
|
||||
initUI()
|
||||
}, 100);</script>
|
||||
<script type="text/javascript">setTimeout(function(){initUI()},100);</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,508 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no"/>
|
||||
|
||||
<title>zzz.cat Speedtest</title>
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Oswald:300,400|Source+Sans+Pro:400,600"
|
||||
type="text/css" media="all"/>
|
||||
|
||||
<style type="text/css">
|
||||
:root {
|
||||
--dark-gray: #32363b;
|
||||
--grass-green: #02b159;
|
||||
}
|
||||
|
||||
html, body {
|
||||
background-color: white;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
color: var(--dark-gray);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
line-height: 1.15;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 18px;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.33333;
|
||||
font-family: "Source Sans Pro", sans-serif;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
margin: 1rem 1rem 2rem;
|
||||
text-align: center;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
*, *:before, *:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
#startStopBtn {
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
color: white;
|
||||
background-color: var(--grass-green);
|
||||
border: 0.15em solid var(--grass-green);
|
||||
border-radius: 0.3em;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
height: 3em;
|
||||
line-height: 2.7em;
|
||||
cursor: pointer;
|
||||
/*box-shadow:0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);*/
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#startStopBtn:hover {
|
||||
/*box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);*/
|
||||
}
|
||||
|
||||
#startStopBtn.running {
|
||||
background-color: var(--dark-gray);
|
||||
border-color: var(--dark-gray);
|
||||
color: white;
|
||||
}
|
||||
|
||||
#startStopBtn:before {
|
||||
content: "Start Speed Test";
|
||||
}
|
||||
|
||||
#startStopBtn.running:before {
|
||||
content: "Abort";
|
||||
}
|
||||
|
||||
#test {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
div.testArea {
|
||||
display: inline-block;
|
||||
width: calc(100% - 2rem - 2rem); /* subtract margins */
|
||||
max-width: 16em;
|
||||
margin: 2rem;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
div.testArea::before {
|
||||
content: '';
|
||||
display: block;
|
||||
padding-top: 100%;
|
||||
}
|
||||
|
||||
div.testName {
|
||||
bottom: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
div.meterText {
|
||||
bottom: 1.8em;
|
||||
font-family: "Oswald", sans-serif;
|
||||
font-size: 4em;
|
||||
font-weight: 300;
|
||||
left: 0;
|
||||
line-height: 1;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
div.meterText:empty:before {
|
||||
content: "0.00";
|
||||
}
|
||||
|
||||
div.unit {
|
||||
bottom: 3.5em;
|
||||
font-family: "Oswald", sans-serif;
|
||||
font-size: 1.5em;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.5px;
|
||||
left: 0;
|
||||
line-height: 1;
|
||||
position: absolute;
|
||||
text-transform: uppercase;
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
div.testArea canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#ipArea {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#shareArea {
|
||||
width: 95%;
|
||||
max-width: 40em;
|
||||
margin: 0 auto;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#shareArea > * {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin: 0.25em 0;
|
||||
}
|
||||
|
||||
#privacyPolicy {
|
||||
position: fixed;
|
||||
top: 10em;
|
||||
bottom: 10em;
|
||||
left: 15em;
|
||||
right: 15em;
|
||||
overflow-y: auto;
|
||||
width: auto;
|
||||
height: auto;
|
||||
box-shadow: 0 0 3em 1em #000000;
|
||||
z-index: 999999;
|
||||
text-align: left;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#privacyCloseBtn {
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
color: white;
|
||||
background-color: var(--grass-green);
|
||||
border: 0.15em solid var(--grass-green);
|
||||
border-radius: 0.3em;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
height: 3em;
|
||||
line-height: 2.7em;
|
||||
cursor: pointer;
|
||||
/*box-shadow:0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);*/
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
a.privacy {
|
||||
margin-top: 2em;
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
color: #808080;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media all and (max-width: 65em) {
|
||||
/* 1040 px */
|
||||
div.testGroup {
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
}
|
||||
|
||||
div.testArea {
|
||||
font-size: 1.5384615vw; /* 16 px */
|
||||
margin: 1rem;
|
||||
width: calc(100% - 1rem - 1rem); /* subtract margins */
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 40em) {
|
||||
/* 640 px */
|
||||
div.testArea {
|
||||
font-size: 0.8em; /* 12.8 px */
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
function I(id) {
|
||||
return document.getElementById(id);
|
||||
}
|
||||
|
||||
var meterBk = "#ebecf0"; // ui--input-border
|
||||
var dlColor = "#02b159", // grass-green
|
||||
ulColor = "#02b159", // grass-green
|
||||
pingColor = "#02b159", // grass-green
|
||||
jitColor = "#02b159"; // grass-green
|
||||
var progColor = "#0ac9f7"; // sky-blue
|
||||
|
||||
function setPageTitle() {
|
||||
var pageTitleDiv = document.getElementById('pageTitle');
|
||||
var titlePrefixNode = document.createTextNode('Speed Test:');
|
||||
var lineBreakElement = document.createElement('br');
|
||||
var locationNode = document.createTextNode('Unknown');
|
||||
switch (window.location.hostname) {
|
||||
case 'us1.zzz.cat':
|
||||
locationNode.textContent = 'Unites States 1 (Fremont, Linode)';
|
||||
break;
|
||||
case 'us2.zzz.cat':
|
||||
locationNode.textContent = 'Unites States 2 (LAX (CN2), Bandwagon)';
|
||||
break;
|
||||
case 'us3.zzz.cat':
|
||||
locationNode.textContent = 'Unites States 3 (LAX (CN2 GIA-E), Bandwagon)';
|
||||
break;
|
||||
case 'jp1.zzz.cat':
|
||||
locationNode.textContent = 'Japan 1 (Tokyo 2, Linode)';
|
||||
break;
|
||||
case 'jp2.zzz.cat':
|
||||
locationNode.textContent = 'Japan 2 (Tokyo 2, Linode)';
|
||||
break;
|
||||
case 'sg1.zzz.cat':
|
||||
locationNode.textContent = 'Singapore (Singapore, Linode)';
|
||||
break;
|
||||
case 'ca1.zzz.cat':
|
||||
locationNode.textContent = 'Canada (Toronto, Linode)';
|
||||
break;
|
||||
default:
|
||||
locationNode.textContent = window.location.hostname;
|
||||
break;
|
||||
}
|
||||
|
||||
pageTitleDiv.appendChild(titlePrefixNode);
|
||||
pageTitleDiv.appendChild(lineBreakElement);
|
||||
pageTitleDiv.appendChild(locationNode);
|
||||
}
|
||||
|
||||
//CODE FOR GAUGES
|
||||
function drawMeter(c, amount, bk, fg, progress, prog) {
|
||||
var ctx = c.getContext("2d");
|
||||
var dp = window.devicePixelRatio || 1;
|
||||
var cw = c.clientWidth * dp, ch = c.clientHeight * dp;
|
||||
var sizScale = ch * 0.0055;
|
||||
if (c.width == cw && c.height == ch) {
|
||||
ctx.clearRect(0, 0, cw, ch);
|
||||
} else {
|
||||
c.width = cw;
|
||||
c.height = ch;
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = bk;
|
||||
ctx.lineCap = "round";
|
||||
ctx.lineWidth = 4 * sizScale;
|
||||
ctx.arc(
|
||||
c.width / 2,
|
||||
c.height / 2,// c.height/2-58*sizScale,
|
||||
c.height / 2 - ctx.lineWidth,//c.height/1.8-ctx.lineWidth,
|
||||
-Math.PI * 1.2,
|
||||
Math.PI * 0.2
|
||||
);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = fg;
|
||||
ctx.lineCap = (amount > 0 ? "round" : "butt");
|
||||
ctx.lineWidth = 4 * sizScale;
|
||||
ctx.arc(
|
||||
c.width / 2,
|
||||
c.height / 2,// c.height/2-58*sizScale,
|
||||
c.height / 2 - ctx.lineWidth,//c.height/1.8-ctx.lineWidth,
|
||||
-Math.PI * 1.2,
|
||||
amount * Math.PI * 1.2 - Math.PI * 1.2
|
||||
);
|
||||
ctx.stroke();
|
||||
if (typeof progress !== "undefined") {
|
||||
ctx.fillStyle = prog;
|
||||
ctx.fillRect(
|
||||
c.width * 0.3,
|
||||
c.height - 28 * sizScale,
|
||||
c.width * 0.4 * progress,
|
||||
4 * sizScale
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mbpsToAmount(s) {
|
||||
return 1 - (1 / (Math.pow(1.3, Math.sqrt(s))));
|
||||
}
|
||||
|
||||
function msToAmount(s) {
|
||||
return 1 - (1 / (Math.pow(1.08, Math.sqrt(s))));
|
||||
}
|
||||
|
||||
//SPEEDTEST AND UI CODE
|
||||
var w = null; //speedtest worker
|
||||
var data = null; //data from worker
|
||||
function startStop() {
|
||||
if (w != null) {
|
||||
//speedtest is running, abort
|
||||
w.postMessage('abort');
|
||||
w = null;
|
||||
data = null;
|
||||
I("startStopBtn").className = "";
|
||||
initUI();
|
||||
} else {
|
||||
//test is not running, begin
|
||||
w = new Worker('speedtest_worker.js');
|
||||
w.postMessage('start'); //Add optional parameters as a JSON object to this command
|
||||
I("startStopBtn").className = "running";
|
||||
w.onmessage = function (e) {
|
||||
data = JSON.parse(e.data);
|
||||
var status = data.testState;
|
||||
if (status >= 4) {
|
||||
//test completed
|
||||
I("startStopBtn").className = "";
|
||||
w = null;
|
||||
updateUI(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//this function reads the data sent back by the worker and updates the UI
|
||||
function updateUI(forced) {
|
||||
if (!forced && (!data || !w)) return;
|
||||
console.log(data);
|
||||
var status = data.testState;
|
||||
I("ip").textContent = data.clientIp;
|
||||
I("dlText").textContent = (status == 1 && data.dlStatus == 0) ? "..." : data.dlStatus;
|
||||
drawMeter(I("dlMeter"), mbpsToAmount(Number(data.dlStatus * (status == 1 ? oscillate() : 1))), meterBk, dlColor, Number(data.dlProgress), progColor);
|
||||
I("ulText").textContent = (status == 3 && data.ulStatus == 0) ? "..." : data.ulStatus;
|
||||
drawMeter(I("ulMeter"), mbpsToAmount(Number(data.ulStatus * (status == 3 ? oscillate() : 1))), meterBk, ulColor, Number(data.ulProgress), progColor);
|
||||
I("pingText").textContent = data.pingStatus;
|
||||
drawMeter(I("pingMeter"), msToAmount(Number(data.pingStatus * (status == 2 ? oscillate() : 1))), meterBk, pingColor, Number(data.pingProgress), progColor);
|
||||
I("jitText").textContent = data.jitterStatus;
|
||||
drawMeter(I("jitMeter"), msToAmount(Number(data.jitterStatus * (status == 2 ? oscillate() : 1))), meterBk, jitColor, Number(data.pingProgress), progColor);
|
||||
}
|
||||
|
||||
function oscillate() {
|
||||
return 1 + 0.02 * Math.sin(Date.now() / 100);
|
||||
}
|
||||
|
||||
//poll the status from the worker (this will call updateUI)
|
||||
setInterval(function () {
|
||||
if (w) w.postMessage('status');
|
||||
}, 200);
|
||||
//update the UI every frame
|
||||
window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || (function (callback, element) {
|
||||
setTimeout(callback, 1000 / 60);
|
||||
});
|
||||
|
||||
function frame() {
|
||||
requestAnimationFrame(frame);
|
||||
updateUI();
|
||||
}
|
||||
|
||||
frame(); //start frame loop
|
||||
//function to (re)initialize UI
|
||||
function initUI() {
|
||||
drawMeter(I("dlMeter"), 0, meterBk, dlColor, 0);
|
||||
drawMeter(I("ulMeter"), 0, meterBk, ulColor, 0);
|
||||
drawMeter(I("pingMeter"), 0, meterBk, pingColor, 0);
|
||||
drawMeter(I("jitMeter"), 0, meterBk, jitColor, 0);
|
||||
I("dlText").textContent = "";
|
||||
I("ulText").textContent = "";
|
||||
I("pingText").textContent = "";
|
||||
I("jitText").textContent = "";
|
||||
I("ip").textContent = "";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1 id="pageTitle"></h1>
|
||||
<div id="test">
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<canvas id="dlMeter" class="meter"></canvas>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbit/s</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<canvas id="ulMeter" class="meter"></canvas>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbit/s</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Ping</div>
|
||||
<canvas id="pingMeter" class="meter"></canvas>
|
||||
<div id="pingText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
|
||||
<div class="testArea">
|
||||
<div class="testName">Jitter</div>
|
||||
<canvas id="jitMeter" class="meter"></canvas>
|
||||
<div id="jitText" class="meterText"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ipArea">
|
||||
IP Address: <span id="ip"></span>
|
||||
</div>
|
||||
<div id="shareArea" style="display:none">
|
||||
<h3>Share results</h3>
|
||||
<p>Test ID: <span id="testId"></span></p>
|
||||
<input type="text" value="" id="resultsURL" readonly="readonly"
|
||||
onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
|
||||
<img src="" id="resultsImg"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="startStopBtn" onclick="startStop()"></div>
|
||||
<div id="privacyPolicy" style="display:none;">
|
||||
<h2>Privacy Policy</h2>
|
||||
<p>This HTML5 Speedtest server is configured with telemetry enabled.</p>
|
||||
<h4>What data we collect</h4>
|
||||
<p>
|
||||
At the end of the test, the following data is collected and stored:
|
||||
<ul>
|
||||
<li>Test ID</li>
|
||||
<li>Time of testing</li>
|
||||
<li>Test results (download and upload speed, ping and jitter)</li>
|
||||
<li>IP address</li>
|
||||
<li>ISP information</li>
|
||||
<li>Approximate location (inferred from IP address, not GPS)</li>
|
||||
<li>User agent and browser locale</li>
|
||||
<li>Test log (contains no personal information)</li>
|
||||
</ul>
|
||||
</p>
|
||||
<h4>How we use the data</h4>
|
||||
<p>
|
||||
Data collected through this service is used to:
|
||||
<ul>
|
||||
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
|
||||
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
|
||||
</ul>
|
||||
No personal information is disclosed to third parties.
|
||||
</p>
|
||||
<h4>Your consent</h4>
|
||||
<p>
|
||||
By starting the test, you consent to the terms of this privacy policy.
|
||||
</p>
|
||||
<h4>Data removal</h4>
|
||||
<p>
|
||||
If you want to have your information deleted, you need to provide either the ID of the test or your IP
|
||||
address. This is the only way to identify your data, without this information we won't be able to comply
|
||||
with your request.<br/><br/>
|
||||
Contact this email address for all deletion requests: maddie at zzz dot cat</a>.
|
||||
</p>
|
||||
<br/><br/>
|
||||
<a id="privacyCloseBtn" class="privacy" href="#"
|
||||
onclick="I('privacyPolicy').style.display='none'">Close</a><br/>
|
||||
</div>
|
||||
<div><a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a></div>
|
||||
</div>
|
||||
<script type="text/javascript">setPageTitle();</script>
|
||||
<script type="text/javascript">setTimeout(initUI, 100);</script>
|
||||
</body>
|
||||
</html>
|
42
web/listener.go
Normal file
42
web/listener.go
Normal file
@ -0,0 +1,42 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/librespeed/speedtest/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func startListener(conf *config.Config, r *chi.Mux) error {
|
||||
var s error
|
||||
|
||||
addr := net.JoinHostPort(conf.BindAddress, conf.Port)
|
||||
log.Infof("Starting backend server on %s", addr)
|
||||
|
||||
// TLS and HTTP/2.
|
||||
if conf.EnableTLS {
|
||||
log.Info("Use TLS connection.")
|
||||
if !(conf.EnableHTTP2) {
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: r,
|
||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||
}
|
||||
s = srv.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile)
|
||||
} else {
|
||||
s = http.ListenAndServeTLS(addr, conf.TLSCertFile, conf.TLSKeyFile, r)
|
||||
}
|
||||
} else {
|
||||
if conf.EnableHTTP2 {
|
||||
log.Errorf("TLS is mandatory for HTTP/2. Ignore settings that enable HTTP/2.")
|
||||
}
|
||||
s = http.ListenAndServe(addr, r)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
60
web/listener_linux.go
Normal file
60
web/listener_linux.go
Normal file
@ -0,0 +1,60 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package web
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"github.com/coreos/go-systemd/v22/activation"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/librespeed/speedtest/config"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func startListener(conf *config.Config, r *chi.Mux) error {
|
||||
// See if systemd socket activation has been used when starting our process
|
||||
listeners, err := activation.Listeners()
|
||||
if err != nil {
|
||||
log.Fatalf("Error whilst checking for systemd socket activation %s", err)
|
||||
}
|
||||
|
||||
var s error
|
||||
|
||||
switch len(listeners) {
|
||||
case 0:
|
||||
addr := net.JoinHostPort(conf.BindAddress, conf.Port)
|
||||
log.Infof("Starting backend server on %s", addr)
|
||||
|
||||
// TLS and HTTP/2.
|
||||
if conf.EnableTLS {
|
||||
log.Info("Use TLS connection.")
|
||||
if !(conf.EnableHTTP2) {
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: r,
|
||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||
}
|
||||
s = srv.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile)
|
||||
} else {
|
||||
s = http.ListenAndServeTLS(addr, conf.TLSCertFile, conf.TLSKeyFile, r)
|
||||
}
|
||||
} else {
|
||||
if conf.EnableHTTP2 {
|
||||
log.Errorf("TLS is mandatory for HTTP/2. Ignore settings that enable HTTP/2.")
|
||||
}
|
||||
s = http.ListenAndServe(addr, r)
|
||||
}
|
||||
case 1:
|
||||
log.Info("Starting backend server on inherited file descriptor via systemd socket activation")
|
||||
if conf.BindAddress != "" || conf.Port != "" {
|
||||
log.Errorf("Both an address/port (%s:%s) has been specificed in the config AND externally configured socket activation has been detected", conf.BindAddress, conf.Port)
|
||||
log.Fatal(`Please deconfigure socket activation (e.g. in systemd unit files), or set both 'bind_address' and 'listen_port' to ''`)
|
||||
}
|
||||
s = http.Serve(listeners[0], r)
|
||||
default:
|
||||
log.Fatalf("Asked to listen on %d sockets via systemd activation. Sorry we currently only support listening on 1 socket.", len(listeners))
|
||||
}
|
||||
return s
|
||||
}
|
64
web/web.go
64
web/web.go
@ -64,38 +64,37 @@ func ListenAndServe(conf *config.Config) error {
|
||||
assetFS = justFilesFilesystem{fs: http.Dir(conf.AssetsPath), readDirBatchSize: 2}
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(conf.BindAddress, conf.Port)
|
||||
log.Infof("Starting backend server on %s", addr)
|
||||
r.Get("/*", pages(assetFS))
|
||||
r.HandleFunc("/empty", empty)
|
||||
r.HandleFunc("/backend/empty", empty)
|
||||
r.Get("/garbage", garbage)
|
||||
r.Get("/backend/garbage", garbage)
|
||||
r.Get("/getIP", getIP)
|
||||
r.Get("/backend/getIP", getIP)
|
||||
r.Get("/results", results.DrawPNG)
|
||||
r.Get("/results/", results.DrawPNG)
|
||||
r.Get("/backend/results", results.DrawPNG)
|
||||
r.Get("/backend/results/", results.DrawPNG)
|
||||
r.Post("/results/telemetry", results.Record)
|
||||
r.Post("/backend/results/telemetry", results.Record)
|
||||
r.HandleFunc("/stats", results.Stats)
|
||||
r.HandleFunc("/backend/stats", results.Stats)
|
||||
r.Get(conf.BaseURL+"/*", pages(assetFS, conf.BaseURL))
|
||||
r.HandleFunc(conf.BaseURL+"/empty", empty)
|
||||
r.HandleFunc(conf.BaseURL+"/backend/empty", empty)
|
||||
r.Get(conf.BaseURL+"/garbage", garbage)
|
||||
r.Get(conf.BaseURL+"/backend/garbage", garbage)
|
||||
r.Get(conf.BaseURL+"/getIP", getIP)
|
||||
r.Get(conf.BaseURL+"/backend/getIP", getIP)
|
||||
r.Get(conf.BaseURL+"/results", results.DrawPNG)
|
||||
r.Get(conf.BaseURL+"/results/", results.DrawPNG)
|
||||
r.Get(conf.BaseURL+"/backend/results", results.DrawPNG)
|
||||
r.Get(conf.BaseURL+"/backend/results/", results.DrawPNG)
|
||||
r.Post(conf.BaseURL+"/results/telemetry", results.Record)
|
||||
r.Post(conf.BaseURL+"/backend/results/telemetry", results.Record)
|
||||
r.HandleFunc(conf.BaseURL+"/stats", results.Stats)
|
||||
r.HandleFunc(conf.BaseURL+"/backend/stats", results.Stats)
|
||||
|
||||
// PHP frontend default values compatibility
|
||||
r.HandleFunc("/empty.php", empty)
|
||||
r.HandleFunc("/backend/empty.php", empty)
|
||||
r.Get("/garbage.php", garbage)
|
||||
r.Get("/backend/garbage.php", garbage)
|
||||
r.Get("/getIP.php", getIP)
|
||||
r.Get("/backend/getIP.php", getIP)
|
||||
r.Post("/results/telemetry.php", results.Record)
|
||||
r.Post("/backend/results/telemetry.php", results.Record)
|
||||
r.HandleFunc("/stats.php", results.Stats)
|
||||
r.HandleFunc("/backend/stats.php", results.Stats)
|
||||
r.HandleFunc(conf.BaseURL+"/empty.php", empty)
|
||||
r.HandleFunc(conf.BaseURL+"/backend/empty.php", empty)
|
||||
r.Get(conf.BaseURL+"/garbage.php", garbage)
|
||||
r.Get(conf.BaseURL+"/backend/garbage.php", garbage)
|
||||
r.Get(conf.BaseURL+"/getIP.php", getIP)
|
||||
r.Get(conf.BaseURL+"/backend/getIP.php", getIP)
|
||||
r.Post(conf.BaseURL+"/results/telemetry.php", results.Record)
|
||||
r.Post(conf.BaseURL+"/backend/results/telemetry.php", results.Record)
|
||||
r.HandleFunc(conf.BaseURL+"/stats.php", results.Stats)
|
||||
r.HandleFunc(conf.BaseURL+"/backend/stats.php", results.Stats)
|
||||
|
||||
go listenProxyProtocol(conf, r)
|
||||
return http.ListenAndServe(addr, r)
|
||||
|
||||
return startListener(conf, r)
|
||||
}
|
||||
|
||||
func listenProxyProtocol(conf *config.Config, r *chi.Mux) {
|
||||
@ -114,8 +113,15 @@ func listenProxyProtocol(conf *config.Config, r *chi.Mux) {
|
||||
}
|
||||
}
|
||||
|
||||
func pages(fs http.FileSystem) http.HandlerFunc {
|
||||
func pages(fs http.FileSystem, BaseURL string) http.HandlerFunc {
|
||||
var removeBaseURL *regexp.Regexp
|
||||
if BaseURL != "" {
|
||||
removeBaseURL = regexp.MustCompile("^" + BaseURL + "/")
|
||||
}
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
if BaseURL != "" {
|
||||
r.URL.Path = removeBaseURL.ReplaceAllString(r.URL.Path, "/")
|
||||
}
|
||||
if r.RequestURI == "/" {
|
||||
r.RequestURI = "/index.html"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user