mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-01-18 18:55:54 +08:00
make server & router reusable outside asynqmon package
This commit is contained in:
parent
29dd0c8213
commit
3839f96b44
3
.gitignore
vendored
3
.gitignore
vendored
@ -25,8 +25,11 @@ package-json.lock
|
||||
|
||||
# main binary
|
||||
asynqmon
|
||||
!cmd/asynqmon
|
||||
dist/
|
||||
cmd/asynqmon/ui-assets
|
||||
|
||||
# Editor configs
|
||||
.idea/
|
||||
.vscode/
|
||||
.editorconfig
|
||||
|
@ -36,13 +36,13 @@ RUN go mod download
|
||||
COPY . .
|
||||
|
||||
# Copy frontend static files from /static to the root folder of the backend container.
|
||||
COPY --from=frontend ["/static/build", "ui/build"]
|
||||
COPY --from=frontend ["/static/build", "ui-assets"]
|
||||
|
||||
# Set necessary environmet variables needed for the image and build the server.
|
||||
ENV CGO_ENABLED=0 GOOS=linux GOARCH=amd64
|
||||
|
||||
# Run go build (with ldflags to reduce binary size).
|
||||
RUN go build -ldflags="-s -w" -o asynqmon .
|
||||
RUN go build -ldflags="-s -w" -o asynqmon ./cmd/asynqmon
|
||||
|
||||
#
|
||||
# Third stage:
|
||||
@ -55,4 +55,4 @@ FROM scratch
|
||||
COPY --from=backend ["/build/asynqmon", "/"]
|
||||
|
||||
# Command to run when starting the container.
|
||||
ENTRYPOINT ["/asynqmon"]
|
||||
ENTRYPOINT ["/asynqmon"]
|
||||
|
10
Makefile
10
Makefile
@ -1,15 +1,14 @@
|
||||
.PHONY: assets go_binary build docker
|
||||
|
||||
NODE_MODULES_PATH = $(PWD)/ui/node_modules
|
||||
NODE_PATH = $(PWD)/ui/node_modules
|
||||
|
||||
# Checking for a node_modules folder before building.
|
||||
assets:
|
||||
@if [ -d "$(NODE_MODULES_PATH)" ]; then cd ./ui && yarn install; fi
|
||||
cd ./ui && yarn build
|
||||
@cd ./ui && yarn install --modules-folder $(NODE_PATH) && yarn build --modules-folder $(NODE_PATH)
|
||||
@rsync -avu --delete "./ui/build/" "./internal/assets"
|
||||
|
||||
# Build go binary.
|
||||
go_binary: assets
|
||||
go build -o asynqmon .
|
||||
go build -o asynqmon ./cmd/asynqmon
|
||||
|
||||
# Target to build a release binary.
|
||||
build: go_binary
|
||||
@ -21,4 +20,3 @@ docker:
|
||||
--name asynqmon \
|
||||
-p 8080:8080 \
|
||||
asynqmon --redis-addr=host.docker.internal:6379
|
||||
|
||||
|
138
cmd/asynqmon/main.go
Normal file
138
cmd/asynqmon/main.go
Normal file
@ -0,0 +1,138 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ajatprabha/asynqmon"
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/rs/cors"
|
||||
)
|
||||
|
||||
// Command-line flags
|
||||
var (
|
||||
flagPort int
|
||||
flagRedisAddr string
|
||||
flagRedisDB int
|
||||
flagRedisPassword string
|
||||
flagRedisTLS string
|
||||
flagRedisURL string
|
||||
flagRedisInsecureTLS bool
|
||||
flagRedisClusterNodes string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.IntVar(&flagPort, "port", 8080, "port number to use for web ui server")
|
||||
flag.StringVar(&flagRedisAddr, "redis-addr", "127.0.0.1:6379", "address of redis server to connect to")
|
||||
flag.IntVar(&flagRedisDB, "redis-db", 0, "redis database number")
|
||||
flag.StringVar(&flagRedisPassword, "redis-password", "", "password to use when connecting to redis server")
|
||||
flag.StringVar(&flagRedisTLS, "redis-tls", "", "server name for TLS validation used when connecting to redis server")
|
||||
flag.StringVar(&flagRedisURL, "redis-url", "", "URL to redis server")
|
||||
flag.BoolVar(&flagRedisInsecureTLS, "redis-insecure-tls", false, "disable TLS certificate host checks")
|
||||
flag.StringVar(&flagRedisClusterNodes, "redis-cluster-nodes", "", "comma separated list of host:port addresses of cluster nodes")
|
||||
}
|
||||
|
||||
func getRedisOptionsFromFlags() (*redis.UniversalOptions, error) {
|
||||
var opts redis.UniversalOptions
|
||||
|
||||
if flagRedisClusterNodes != "" {
|
||||
opts.Addrs = strings.Split(flagRedisClusterNodes, ",")
|
||||
opts.Password = flagRedisPassword
|
||||
} else {
|
||||
if flagRedisURL != "" {
|
||||
res, err := redis.ParseURL(flagRedisURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.Addrs = append(opts.Addrs, res.Addr)
|
||||
opts.DB = res.DB
|
||||
opts.Password = res.Password
|
||||
|
||||
} else {
|
||||
opts.Addrs = []string{flagRedisAddr}
|
||||
opts.DB = flagRedisDB
|
||||
opts.Password = flagRedisPassword
|
||||
}
|
||||
}
|
||||
|
||||
if flagRedisTLS != "" {
|
||||
opts.TLSConfig = &tls.Config{ServerName: flagRedisTLS}
|
||||
}
|
||||
if flagRedisInsecureTLS {
|
||||
if opts.TLSConfig == nil {
|
||||
opts.TLSConfig = &tls.Config{}
|
||||
}
|
||||
opts.TLSConfig.InsecureSkipVerify = true
|
||||
}
|
||||
|
||||
return &opts, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
opts, err := getRedisOptionsFromFlags()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
useRedisCluster := flagRedisClusterNodes != ""
|
||||
|
||||
var redisConnOpt asynq.RedisConnOpt
|
||||
if useRedisCluster {
|
||||
redisConnOpt = asynq.RedisClusterClientOpt{
|
||||
Addrs: opts.Addrs,
|
||||
Password: opts.Password,
|
||||
TLSConfig: opts.TLSConfig,
|
||||
}
|
||||
} else {
|
||||
redisConnOpt = asynq.RedisClientOpt{
|
||||
Addr: opts.Addrs[0],
|
||||
DB: opts.DB,
|
||||
Password: opts.Password,
|
||||
TLSConfig: opts.TLSConfig,
|
||||
}
|
||||
}
|
||||
|
||||
inspector := asynq.NewInspector(redisConnOpt)
|
||||
defer inspector.Close()
|
||||
|
||||
var redisClient redis.UniversalClient
|
||||
if useRedisCluster {
|
||||
redisClient = redis.NewClusterClient(opts.Cluster())
|
||||
} else {
|
||||
redisClient = redis.NewClient(opts.Simple())
|
||||
}
|
||||
defer redisClient.Close()
|
||||
|
||||
router := asynqmon.NewRouter(asynqmon.RouterOptions{
|
||||
Inspector: inspector,
|
||||
Middlewares: []mux.MiddlewareFunc{loggingMiddleware},
|
||||
RedisClient: redisClient,
|
||||
})
|
||||
|
||||
router.PathPrefix("/").Handler(asynqmon.NewStaticContentHandler())
|
||||
|
||||
c := cors.New(cors.Options{
|
||||
AllowedMethods: []string{"GET", "POST", "DELETE"},
|
||||
})
|
||||
|
||||
handler := c.Handler(router)
|
||||
|
||||
srv := &http.Server{
|
||||
Handler: handler,
|
||||
Addr: fmt.Sprintf(":%d", flagPort),
|
||||
WriteTimeout: 10 * time.Second,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
fmt.Printf("Asynq Monitoring WebUI server is listening on port %d\n", flagPort)
|
||||
log.Fatal(srv.ListenAndServe())
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package asynqmon
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
4
go.mod
4
go.mod
@ -1,9 +1,9 @@
|
||||
module asynqmon
|
||||
module github.com/ajatprabha/asynqmon
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/go-redis/redis/v8 v8.8.0
|
||||
github.com/go-redis/redis/v7 v7.4.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/hibiken/asynq v0.18.3
|
||||
github.com/rs/cors v1.7.0
|
||||
|
77
go.sum
77
go.sum
@ -1,23 +1,14 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
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=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4=
|
||||
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
||||
github.com/go-redis/redis/v8 v8.8.0 h1:fDZP58UN/1RD3DjtTXP/fFZ04TFohSYhjZDkcDe2dnw=
|
||||
github.com/go-redis/redis/v8 v8.8.0/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@ -27,38 +18,30 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/hibiken/asynq v0.18.3 h1:qmn0ce+ppDf40oMJkbX8hVtwRpdOFvYfnMgwiisCHJs=
|
||||
github.com/hibiken/asynq v0.18.3/go.mod h1:Sn3Ql1clxIO5kXoFOAE3W73tX81Hkau+2Kam9LfgymM=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4=
|
||||
github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ=
|
||||
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
@ -68,63 +51,35 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opentelemetry.io/otel v0.19.0 h1:Lenfy7QHRXPZVsw/12CWpxX6d/JkrX8wrx2vO8G80Ng=
|
||||
go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg=
|
||||
go.opentelemetry.io/otel/metric v0.19.0 h1:dtZ1Ju44gkJkYvo+3qGqVXmf88tc+a42edOywypengg=
|
||||
go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc=
|
||||
go.opentelemetry.io/otel/oteltest v0.19.0 h1:YVfA0ByROYqTwOxqHVZYZExzEpfZor+MU1rU+ip2v9Q=
|
||||
go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA=
|
||||
go.opentelemetry.io/otel/trace v0.19.0 h1:1ucYlenXIDA1OlHVLDZKX0ObXV5RLaq06DtUKz5e5zc=
|
||||
go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg=
|
||||
go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4=
|
||||
go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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-20180906233101-161cd47e91fd/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=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@ -132,13 +87,8 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
@ -153,21 +103,18 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/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.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
BIN
internal/assets/android-chrome-192x192.png
Normal file
BIN
internal/assets/android-chrome-192x192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
internal/assets/android-chrome-512x512.png
Normal file
BIN
internal/assets/android-chrome-512x512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
internal/assets/apple-touch-icon.png
Normal file
BIN
internal/assets/apple-touch-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
17
internal/assets/asset-manifest.json
Normal file
17
internal/assets/asset-manifest.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"files": {
|
||||
"main.js": "/static/js/main.7f58c4a5.chunk.js",
|
||||
"main.js.map": "/static/js/main.7f58c4a5.chunk.js.map",
|
||||
"runtime-main.js": "/static/js/runtime-main.371e21b1.js",
|
||||
"runtime-main.js.map": "/static/js/runtime-main.371e21b1.js.map",
|
||||
"static/js/2.17755345.chunk.js": "/static/js/2.17755345.chunk.js",
|
||||
"static/js/2.17755345.chunk.js.map": "/static/js/2.17755345.chunk.js.map",
|
||||
"index.html": "/index.html",
|
||||
"static/js/2.17755345.chunk.js.LICENSE.txt": "/static/js/2.17755345.chunk.js.LICENSE.txt"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/runtime-main.371e21b1.js",
|
||||
"static/js/2.17755345.chunk.js",
|
||||
"static/js/main.7f58c4a5.chunk.js"
|
||||
]
|
||||
}
|
BIN
internal/assets/favicon-16x16.png
Normal file
BIN
internal/assets/favicon-16x16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 740 B |
BIN
internal/assets/favicon-32x32.png
Normal file
BIN
internal/assets/favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
internal/assets/favicon.ico
Normal file
BIN
internal/assets/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
1
internal/assets/index.html
Normal file
1
internal/assets/index.html
Normal file
@ -0,0 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" type="image/png" href="/favicon.ico"/><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"/><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Asynq monitoring web console"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"/><link rel="manifest" href="/manifest.json"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/><title>Asynq - Monitoring</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,l=r[0],f=r[1],a=r[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var f=t[l];0!==o[f]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="/";var l=this.webpackJsonpui=this.webpackJsonpui||[],f=l.push.bind(l);l.push=r,l=l.slice();for(var a=0;a<l.length;a++)r(l[a]);var p=f;t()}([])</script><script src="/static/js/2.17755345.chunk.js"></script><script src="/static/js/main.7f58c4a5.chunk.js"></script></body></html>
|
19
internal/assets/manifest.json
Normal file
19
internal/assets/manifest.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Asynq Monitoring",
|
||||
"short_name": "Asynqmon",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
3
internal/assets/robots.txt
Normal file
3
internal/assets/robots.txt
Normal file
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
3
internal/assets/static/js/2.17755345.chunk.js
Normal file
3
internal/assets/static/js/2.17755345.chunk.js
Normal file
File diff suppressed because one or more lines are too long
253
internal/assets/static/js/2.17755345.chunk.js.LICENSE.txt
Normal file
253
internal/assets/static/js/2.17755345.chunk.js.LICENSE.txt
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
@license MIT
|
||||
*/
|
||||
|
||||
/*!
|
||||
Copyright (c) 2017 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/*! Conditions:: INITIAL */
|
||||
|
||||
/*! Production:: $accept : expression $end */
|
||||
|
||||
/*! Production:: css_value : ANGLE */
|
||||
|
||||
/*! Production:: css_value : CHS */
|
||||
|
||||
/*! Production:: css_value : EMS */
|
||||
|
||||
/*! Production:: css_value : EXS */
|
||||
|
||||
/*! Production:: css_value : FREQ */
|
||||
|
||||
/*! Production:: css_value : LENGTH */
|
||||
|
||||
/*! Production:: css_value : PERCENTAGE */
|
||||
|
||||
/*! Production:: css_value : REMS */
|
||||
|
||||
/*! Production:: css_value : RES */
|
||||
|
||||
/*! Production:: css_value : SUB css_value */
|
||||
|
||||
/*! Production:: css_value : TIME */
|
||||
|
||||
/*! Production:: css_value : VHS */
|
||||
|
||||
/*! Production:: css_value : VMAXS */
|
||||
|
||||
/*! Production:: css_value : VMINS */
|
||||
|
||||
/*! Production:: css_value : VWS */
|
||||
|
||||
/*! Production:: css_variable : CSS_VAR LPAREN CSS_CPROP COMMA math_expression RPAREN */
|
||||
|
||||
/*! Production:: css_variable : CSS_VAR LPAREN CSS_CPROP RPAREN */
|
||||
|
||||
/*! Production:: expression : math_expression EOF */
|
||||
|
||||
/*! Production:: math_expression : LPAREN math_expression RPAREN */
|
||||
|
||||
/*! Production:: math_expression : NESTED_CALC LPAREN math_expression RPAREN */
|
||||
|
||||
/*! Production:: math_expression : SUB PREFIX SUB NESTED_CALC LPAREN math_expression RPAREN */
|
||||
|
||||
/*! Production:: math_expression : css_value */
|
||||
|
||||
/*! Production:: math_expression : css_variable */
|
||||
|
||||
/*! Production:: math_expression : math_expression ADD math_expression */
|
||||
|
||||
/*! Production:: math_expression : math_expression DIV math_expression */
|
||||
|
||||
/*! Production:: math_expression : math_expression MUL math_expression */
|
||||
|
||||
/*! Production:: math_expression : math_expression SUB math_expression */
|
||||
|
||||
/*! Production:: math_expression : value */
|
||||
|
||||
/*! Production:: value : NUMBER */
|
||||
|
||||
/*! Production:: value : SUB NUMBER */
|
||||
|
||||
/*! Rule:: $ */
|
||||
|
||||
/*! Rule:: (--[0-9a-z-A-Z-]*) */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)% */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)Hz\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ch\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)cm\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)deg\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dpcm\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dpi\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)dppx\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)em\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ex\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)grad\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)in\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)kHz\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)mm\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)ms\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)pc\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)pt\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)px\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)rad\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)rem\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)s\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)turn\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vh\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vmax\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vmin\b */
|
||||
|
||||
/*! Rule:: ([0-9]+(\.[0-9]*)?|\.[0-9]+)vw\b */
|
||||
|
||||
/*! Rule:: ([a-z]+) */
|
||||
|
||||
/*! Rule:: (calc) */
|
||||
|
||||
/*! Rule:: (var) */
|
||||
|
||||
/*! Rule:: , */
|
||||
|
||||
/*! Rule:: - */
|
||||
|
||||
/*! Rule:: \( */
|
||||
|
||||
/*! Rule:: \) */
|
||||
|
||||
/*! Rule:: \* */
|
||||
|
||||
/*! Rule:: \+ */
|
||||
|
||||
/*! Rule:: \/ */
|
||||
|
||||
/*! Rule:: \s+ */
|
||||
|
||||
/*! decimal.js-light v2.5.1 https://github.com/MikeMcl/decimal.js-light/LICENCE */
|
||||
|
||||
/**
|
||||
* A better abstraction over CSS.
|
||||
*
|
||||
* @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present
|
||||
* @website https://github.com/cssinjs/jss
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/** @license React v0.19.1
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v16.10.2
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v16.13.1
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v16.14.0
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v16.14.0
|
||||
* react-jsx-runtime.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v16.14.0
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/** @license React v17.0.1
|
||||
* react-is.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**!
|
||||
* @fileOverview Kickass library to create and place poppers near their reference elements.
|
||||
* @version 1.16.1-lts
|
||||
* @license
|
||||
* Copyright (c) 2016 Federico Zivolo and contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
1
internal/assets/static/js/2.17755345.chunk.js.map
Normal file
1
internal/assets/static/js/2.17755345.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
internal/assets/static/js/main.7f58c4a5.chunk.js
Normal file
2
internal/assets/static/js/main.7f58c4a5.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
internal/assets/static/js/main.7f58c4a5.chunk.js.map
Normal file
1
internal/assets/static/js/main.7f58c4a5.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
internal/assets/static/js/runtime-main.371e21b1.js
Normal file
2
internal/assets/static/js/runtime-main.371e21b1.js
Normal file
@ -0,0 +1,2 @@
|
||||
!function(e){function r(r){for(var n,i,l=r[0],f=r[1],a=r[2],c=0,s=[];c<l.length;c++)i=l[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var f=t[l];0!==o[f]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="/";var l=this.webpackJsonpui=this.webpackJsonpui||[],f=l.push.bind(l);l.push=r,l=l.slice();for(var a=0;a<l.length;a++)r(l[a]);var p=f;t()}([]);
|
||||
//# sourceMappingURL=runtime-main.371e21b1.js.map
|
1
internal/assets/static/js/runtime-main.371e21b1.js.map
Normal file
1
internal/assets/static/js/runtime-main.371e21b1.js.map
Normal file
File diff suppressed because one or more lines are too long
6
internal/static.go
Normal file
6
internal/static.go
Normal file
@ -0,0 +1,6 @@
|
||||
package internal
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed assets/*
|
||||
var StaticContents embed.FS
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package asynqmon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -1,12 +1,11 @@
|
||||
package main
|
||||
package asynqmon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/hibiken/asynq"
|
||||
)
|
||||
|
||||
@ -34,8 +33,7 @@ type QueueLocationInfo struct {
|
||||
|
||||
func newRedisInfoHandlerFunc(client *redis.Client) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.Background()
|
||||
res, err := client.Info(ctx).Result()
|
||||
res, err := client.Info().Result()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -56,14 +54,13 @@ func newRedisInfoHandlerFunc(client *redis.Client) http.HandlerFunc {
|
||||
|
||||
func newRedisClusterInfoHandlerFunc(client *redis.ClusterClient, inspector *asynq.Inspector) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.Background()
|
||||
rawClusterInfo, err := client.ClusterInfo(ctx).Result()
|
||||
rawClusterInfo, err := client.ClusterInfo().Result()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
info := parseRedisInfo(rawClusterInfo)
|
||||
rawClusterNodes, err := client.ClusterNodes(ctx).Result()
|
||||
rawClusterNodes, err := client.ClusterNodes().Result()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -1,173 +1,24 @@
|
||||
package main
|
||||
package asynqmon
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"embed"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/rs/cors"
|
||||
)
|
||||
|
||||
// Command-line flags
|
||||
var (
|
||||
flagPort int
|
||||
flagRedisAddr string
|
||||
flagRedisDB int
|
||||
flagRedisPassword string
|
||||
flagRedisTLS string
|
||||
flagRedisURL string
|
||||
flagRedisInsecureTLS bool
|
||||
flagRedisClusterNodes string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.IntVar(&flagPort, "port", 8080, "port number to use for web ui server")
|
||||
flag.StringVar(&flagRedisAddr, "redis-addr", "127.0.0.1:6379", "address of redis server to connect to")
|
||||
flag.IntVar(&flagRedisDB, "redis-db", 0, "redis database number")
|
||||
flag.StringVar(&flagRedisPassword, "redis-password", "", "password to use when connecting to redis server")
|
||||
flag.StringVar(&flagRedisTLS, "redis-tls", "", "server name for TLS validation used when connecting to redis server")
|
||||
flag.StringVar(&flagRedisURL, "redis-url", "", "URL to redis server")
|
||||
flag.BoolVar(&flagRedisInsecureTLS, "redis-insecure-tls", false, "disable TLS certificate host checks")
|
||||
flag.StringVar(&flagRedisClusterNodes, "redis-cluster-nodes", "", "comma separated list of host:port addresses of cluster nodes")
|
||||
type RouterOptions struct {
|
||||
Inspector *asynq.Inspector
|
||||
Middlewares []mux.MiddlewareFunc
|
||||
RedisClient redis.UniversalClient
|
||||
}
|
||||
|
||||
// staticFileServer implements the http.Handler interface, so we can use it
|
||||
// to respond to HTTP requests. The path to the static directory and
|
||||
// path to the index file within that static directory are used to
|
||||
// serve the SPA in the given static directory.
|
||||
type staticFileServer struct {
|
||||
contents embed.FS
|
||||
staticDirPath string
|
||||
indexFileName string
|
||||
}
|
||||
|
||||
// ServeHTTP inspects the URL path to locate a file within the static dir
|
||||
// on the SPA handler.
|
||||
// If path '/' is requested, it will serve the index file, otherwise it will
|
||||
// serve the file specified by the URL path.
|
||||
func (srv *staticFileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Get the absolute path to prevent directory traversal.
|
||||
path, err := filepath.Abs(r.URL.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if path == "/" {
|
||||
path = srv.indexFilePath()
|
||||
} else {
|
||||
path = filepath.Join(srv.staticDirPath, path)
|
||||
}
|
||||
|
||||
bytes, err := srv.contents.ReadFile(path)
|
||||
// If path is error (e.g. file not exist, path is a directory), serve index file.
|
||||
var pathErr *fs.PathError
|
||||
if errors.As(err, &pathErr) {
|
||||
bytes, err = srv.contents.ReadFile(srv.indexFilePath())
|
||||
}
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := w.Write(bytes); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *staticFileServer) indexFilePath() string {
|
||||
return filepath.Join(srv.staticDirPath, srv.indexFileName)
|
||||
}
|
||||
|
||||
func getRedisOptionsFromFlags() (*redis.UniversalOptions, error) {
|
||||
var opts redis.UniversalOptions
|
||||
|
||||
if flagRedisClusterNodes != "" {
|
||||
opts.Addrs = strings.Split(flagRedisClusterNodes, ",")
|
||||
opts.Password = flagRedisPassword
|
||||
} else {
|
||||
if flagRedisURL != "" {
|
||||
res, err := redis.ParseURL(flagRedisURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.Addrs = append(opts.Addrs, res.Addr)
|
||||
opts.DB = res.DB
|
||||
opts.Password = res.Password
|
||||
|
||||
} else {
|
||||
opts.Addrs = []string{flagRedisAddr}
|
||||
opts.DB = flagRedisDB
|
||||
opts.Password = flagRedisPassword
|
||||
}
|
||||
}
|
||||
|
||||
if flagRedisTLS != "" {
|
||||
opts.TLSConfig = &tls.Config{ServerName: flagRedisTLS}
|
||||
}
|
||||
if flagRedisInsecureTLS {
|
||||
if opts.TLSConfig == nil {
|
||||
opts.TLSConfig = &tls.Config{}
|
||||
}
|
||||
opts.TLSConfig.InsecureSkipVerify = true
|
||||
}
|
||||
return &opts, nil
|
||||
}
|
||||
|
||||
//go:embed ui/build/*
|
||||
var staticContents embed.FS
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
opts, err := getRedisOptionsFromFlags()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
useRedisCluster := flagRedisClusterNodes != ""
|
||||
|
||||
var redisConnOpt asynq.RedisConnOpt
|
||||
if useRedisCluster {
|
||||
redisConnOpt = asynq.RedisClusterClientOpt{
|
||||
Addrs: opts.Addrs,
|
||||
Password: opts.Password,
|
||||
TLSConfig: opts.TLSConfig,
|
||||
}
|
||||
} else {
|
||||
redisConnOpt = asynq.RedisClientOpt{
|
||||
Addr: opts.Addrs[0],
|
||||
DB: opts.DB,
|
||||
Password: opts.Password,
|
||||
TLSConfig: opts.TLSConfig,
|
||||
}
|
||||
}
|
||||
|
||||
inspector := asynq.NewInspector(redisConnOpt)
|
||||
defer inspector.Close()
|
||||
|
||||
var redisClient redis.UniversalClient
|
||||
if useRedisCluster {
|
||||
redisClient = redis.NewClusterClient(opts.Cluster())
|
||||
} else {
|
||||
redisClient = redis.NewClient(opts.Simple())
|
||||
}
|
||||
defer redisClient.Close()
|
||||
|
||||
func NewRouter(opts RouterOptions) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
router.Use(loggingMiddleware)
|
||||
inspector := opts.Inspector
|
||||
|
||||
for _, mf := range opts.Middlewares {
|
||||
router.Use(mf)
|
||||
}
|
||||
|
||||
api := router.PathPrefix("/api").Subrouter()
|
||||
// Queue endpoints.
|
||||
@ -234,31 +85,12 @@ func main() {
|
||||
api.HandleFunc("/scheduler_entries/{entry_id}/enqueue_events", newListSchedulerEnqueueEventsHandlerFunc(inspector)).Methods("GET")
|
||||
|
||||
// Redis info endpoint.
|
||||
if useRedisCluster {
|
||||
api.HandleFunc("/redis_info", newRedisClusterInfoHandlerFunc(redisClient.(*redis.ClusterClient), inspector)).Methods("GET")
|
||||
} else {
|
||||
api.HandleFunc("/redis_info", newRedisInfoHandlerFunc(redisClient.(*redis.Client))).Methods("GET")
|
||||
switch c := opts.RedisClient.(type) {
|
||||
case *redis.ClusterClient:
|
||||
api.HandleFunc("/redis_info", newRedisClusterInfoHandlerFunc(c, inspector)).Methods("GET")
|
||||
case *redis.Client:
|
||||
api.HandleFunc("/redis_info", newRedisInfoHandlerFunc(c)).Methods("GET")
|
||||
}
|
||||
|
||||
fs := &staticFileServer{
|
||||
contents: staticContents,
|
||||
staticDirPath: "ui/build",
|
||||
indexFileName: "index.html",
|
||||
}
|
||||
router.PathPrefix("/").Handler(fs)
|
||||
|
||||
c := cors.New(cors.Options{
|
||||
AllowedMethods: []string{"GET", "POST", "DELETE"},
|
||||
})
|
||||
handler := c.Handler(router)
|
||||
|
||||
srv := &http.Server{
|
||||
Handler: handler,
|
||||
Addr: fmt.Sprintf(":%d", flagPort),
|
||||
WriteTimeout: 10 * time.Second,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
fmt.Printf("Asynq Monitoring WebUI server is listening on port %d\n", flagPort)
|
||||
log.Fatal(srv.ListenAndServe())
|
||||
return router
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package asynqmon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package asynqmon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
68
static.go
Normal file
68
static.go
Normal file
@ -0,0 +1,68 @@
|
||||
package asynqmon
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ajatprabha/asynqmon/internal"
|
||||
)
|
||||
|
||||
func NewStaticContentHandler() http.Handler {
|
||||
return &staticContentHandler{
|
||||
contents: internal.StaticContents,
|
||||
staticDirPath: "assets",
|
||||
indexFileName: "index.html",
|
||||
}
|
||||
}
|
||||
|
||||
// staticFileServer implements the http.Handler interface, so we can use it
|
||||
// to respond to HTTP requests. The path to the static directory and
|
||||
// path to the index file within that static directory are used to
|
||||
// serve the SPA in the given static directory.
|
||||
type staticContentHandler struct {
|
||||
contents embed.FS
|
||||
staticDirPath string
|
||||
indexFileName string
|
||||
}
|
||||
|
||||
// ServeHTTP inspects the URL path to locate a file within the static dir
|
||||
// on the SPA handler.
|
||||
// If path '/' is requested, it will serve the index file, otherwise it will
|
||||
// serve the file specified by the URL path.
|
||||
func (h *staticContentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Get the absolute path to prevent directory traversal.
|
||||
path, err := filepath.Abs(r.URL.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if path == "/" {
|
||||
path = h.indexFilePath()
|
||||
} else {
|
||||
path = filepath.Join(h.staticDirPath, path)
|
||||
}
|
||||
|
||||
bytes, err := h.contents.ReadFile(path)
|
||||
// If path is error (e.g. file not exist, path is a directory), serve index file.
|
||||
var pathErr *fs.PathError
|
||||
if errors.As(err, &pathErr) {
|
||||
bytes, err = h.contents.ReadFile(h.indexFilePath())
|
||||
}
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := w.Write(bytes); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (h *staticContentHandler) indexFilePath() string {
|
||||
return filepath.Join(h.staticDirPath, h.indexFileName)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package asynqmon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
Loading…
Reference in New Issue
Block a user