Compare commits
18 Commits
5c852fe559
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
541cd8d506 | ||
|
|
b8905b53f9 | ||
| 48517b9334 | |||
|
|
2e13671bb7 | ||
|
|
32b30ae183 | ||
|
|
534b9586f2 | ||
|
|
3c0b7479a0 | ||
|
|
5c9d91ff63 | ||
|
|
e5ae2efcef | ||
|
|
3ec150b015 | ||
|
|
c117d363a0 | ||
|
|
f9d59b99a0 | ||
|
|
eea192e385 | ||
|
|
d55c6b1932 | ||
|
|
53f124c9ec | ||
|
|
cee0bfb43d | ||
|
|
1b1143e93e | ||
|
|
dac1f65fc2 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -4,4 +4,6 @@
|
||||
.data
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
xtest
|
||||
xtest
|
||||
*.sock
|
||||
__debug*
|
||||
2
.nfctl
2
.nfctl
@@ -12,7 +12,7 @@ EOF
|
||||
# 替换 go module name
|
||||
!replace content
|
||||
exact go.mod
|
||||
module ultone => module {{.PROJECT_NAME}}
|
||||
module ultone => module {{ .MODULE_NAME }}
|
||||
EOF
|
||||
|
||||
# 替换 config name
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#FROM golang:1.20-alpine AS builder
|
||||
FROM repository.umisen.com/external/golang:latest AS builder
|
||||
FROM golang:alpine AS builder
|
||||
|
||||
ENV GO111MODULE on
|
||||
ENV CGO_ENABLED 0
|
||||
@@ -13,10 +12,7 @@ COPY . .
|
||||
RUN go mod download
|
||||
RUN go build -ldflags '-s -w' -o server .
|
||||
|
||||
#FROM alpine:latest
|
||||
FROM repository.umisen.com/external/alpine:latest
|
||||
|
||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && apk add curl
|
||||
FROM alpine:latest
|
||||
|
||||
ENV TZ Asia/Shanghai
|
||||
|
||||
|
||||
20
etc/config.yaml
Normal file
20
etc/config.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: ult
|
||||
listen:
|
||||
http: 0.0.0.0:8080
|
||||
db:
|
||||
# uri: postgres::host=pg.dev user=xx_user password=xx_password dbname=xx_database port=5432 sslmode=disable TimeZone=Asia/Shanghai
|
||||
uri: sqlite::db.sqlite3
|
||||
cache:
|
||||
uri: 'lru::'
|
||||
# uri: 'memory::'
|
||||
# uri: redis::u:p@redis.dev:6379
|
||||
es:
|
||||
uri: http://es.dev:9200
|
||||
index:
|
||||
staff: some_staff
|
||||
nebula:
|
||||
uri: nebula.1.dev:9669,nebula.2.dev:9669
|
||||
space: test_space
|
||||
username: admin
|
||||
password: password
|
||||
90
go.mod
90
go.mod
@@ -3,39 +3,85 @@ module ultone
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
gitea.com/taozitaozi/gredis v0.0.0-20240131032054-b02845ce1e9d
|
||||
gitea.com/taozitaozi/gredis v0.0.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.72.0
|
||||
github.com/elastic/go-elasticsearch/v7 v7.17.10
|
||||
github.com/glebarez/sqlite v1.10.0
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
github.com/jackc/pgtype v1.12.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.5.9
|
||||
github.com/loveuer/esgo2dump v0.3.3
|
||||
github.com/loveuer/nf v0.2.7
|
||||
github.com/loveuer/nf v0.3.1
|
||||
github.com/loveuer/ngorm/v2 v2.1.1
|
||||
github.com/olivere/elastic/v7 v7.0.32
|
||||
github.com/rabbitmq/amqp091-go v1.10.0
|
||||
github.com/samber/lo v1.39.0
|
||||
github.com/segmentio/kafka-go v0.4.47
|
||||
github.com/sirupsen/logrus v1.9.2
|
||||
github.com/spf13/cast v1.6.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/tdewolff/minify/v2 v2.20.16
|
||||
golang.org/x/crypto v0.23.0
|
||||
google.golang.org/grpc v1.50.0
|
||||
golang.org/x/crypto v0.27.0
|
||||
google.golang.org/grpc v1.62.1
|
||||
gorm.io/driver/mysql v1.4.5
|
||||
gorm.io/driver/postgres v1.4.4
|
||||
gorm.io/gorm v1.25.5
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 // indirect
|
||||
github.com/aws/smithy-go v1.22.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/facebook/fbthrift v0.31.1-0.20211129061412-801ed7f9f295 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.13.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
@@ -45,23 +91,21 @@ require (
|
||||
github.com/jackc/pgx/v4 v4.17.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.17.2 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.7.11 // indirect
|
||||
github.com/vesoft-inc/nebula-go/v3 v3.5.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/net v0.27.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
)
|
||||
|
||||
254
go.sum
254
go.sum
@@ -1,42 +1,73 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
gitea.com/taozitaozi/gredis v0.0.0-20240131032054-b02845ce1e9d h1:TpEOdRGqwzxx+DaN18nFE+g4EQYjneZOO1jcHtSon/g=
|
||||
gitea.com/taozitaozi/gredis v0.0.0-20240131032054-b02845ce1e9d/go.mod h1:QtcL846XUtSnhmW6TZAujUQ9V5jalY7frxzZOs00kFI=
|
||||
gitea.com/taozitaozi/gredis v0.0.1 h1:SfL/2MGkk8m06pqo/kK4j1XvKxHiZQaoMEhlqdq1hJ8=
|
||||
gitea.com/taozitaozi/gredis v0.0.1/go.mod h1:E5Y+tGZwLdT3Z7oHocc+7C3vOpPTDPd09LXwIDVbnFA=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7/go.mod h1:vZGX6GVkIE8uECSUHB6MWAUsd4ZcG2Yq/dMa4refR3M=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48 h1:IYdLD1qTJ0zanRavulofmqut4afs45mOWEI+MzZtTfQ=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48/go.mod h1:tOscxHN3CGmuX9idQ3+qbkzrjVIx32lqDSU1/0d/qXs=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 h1:GeNJsIFHB+WW5ap2Tec4K6dzcVTsRbsT1Lra46Hv9ME=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26/go.mod h1:zfgMpwHDXX2WGoG84xG2H+ZlPTkJUU4YUvx2svLQYWo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 h1:tB4tNw83KcajNAzaIMhkhVI2Nt8fAZd5A5ro113FEMY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7/go.mod h1:lvpyBGkZ3tZ9iSsUIcC2EWp+0ywa7aK3BLT+FwZi+mQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 h1:8eUsivBQzZHqe/3FE+cqwfH+0p5Jo8PFM/QYQSmeZ+M=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7/go.mod h1:kLPQvGUmxn/fqiCrDeohwG33bq2pQpGeY62yRO6Nrh0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 h1:Hi0KGbrnr57bEHWM0bJ1QcBzxLrL/k2DHvGYhb8+W1w=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7/go.mod h1:wKNgWgExdjjrm4qvfbTorkvocEstaoDl4WCvGfeCy9c=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.72.0 h1:SAfh4pNx5LuTafKKWR02Y+hL3A+3TX8cTKG1OIAJaBk=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.72.0/go.mod h1:r+xl5yzMk9083rMR+sJ5TYj9Tihvf/l1oxzZXDgGj2Q=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 h1:CvuUmnXI7ebaUAhbJcDy9YQx8wHR69eZ9I7q5hszt/g=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8/go.mod h1:XDeGv1opzwm8ubxddF0cgqkZWsyOtw4lr6dxwmb6YQg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 h1:F2rBfNAL5UyswqoeWv9zs74N/NanhK16ydHW1pahX6E=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7/go.mod h1:JfyQ0g2JG8+Krq0EuZNnRwX0mU0HrwY/tG6JNfcqh4k=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 h1:Xgv/hyNgvLda/M9l9qxXc4UFSgppnRczLxlMs5Ae/QY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc=
|
||||
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
|
||||
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/elastic/go-elasticsearch/v7 v7.17.10 h1:TCQ8i4PmIJuBunvBS6bwT2ybzVFxxUhhltAs3Gyu1yo=
|
||||
github.com/elastic/go-elasticsearch/v7 v7.17.10/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/facebook/fbthrift v0.31.1-0.20211129061412-801ed7f9f295 h1:ZA+qQ3d2In0RNzVpk+D/nq1sjDSv+s1Wy2zrAPQAmsg=
|
||||
github.com/facebook/fbthrift v0.31.1-0.20211129061412-801ed7f9f295/go.mod h1:2tncLx5rmw69e5kMBv/yJneERbzrr1yr5fdlnTbu8lU=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||
github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc=
|
||||
github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA=
|
||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
@@ -48,34 +79,21 @@ github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPh
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
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=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
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/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
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/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
@@ -130,7 +148,12 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -146,10 +169,14 @@ github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/loveuer/esgo2dump v0.3.3 h1:/AidoaFV7bDRyT1ycyBKs4XGmyVs2ShaUKrpEBiUWkM=
|
||||
github.com/loveuer/esgo2dump v0.3.3/go.mod h1:thZvfsO0kd7Ck3TA0jc9rRc4CuIa4Iuiq6tF3tCqXEY=
|
||||
github.com/loveuer/nf v0.2.7 h1:p17Y2yvO6u1qnSvYawQsMzBb2Xw7EzkV87r6BZzhdfA=
|
||||
github.com/loveuer/nf v0.2.7/go.mod h1:M6reF17/kJBis30H4DxR5hrtgo/oJL4AV4cBe4HzJLw=
|
||||
github.com/loveuer/nf v0.3.1 h1:FTmyAC9LQF06BVGeGwrwaYfbC6MIQMqr+GoZUQQPvXU=
|
||||
github.com/loveuer/nf v0.3.1/go.mod h1:aApO+2cSP0ULczkfS4OVw8zfWM3rY8gQrzc5PnVV7lY=
|
||||
github.com/loveuer/ngorm/v2 v2.1.1 h1:v+ut5BjeSBFU87o800pI8Q3fXEOUAkvk5+btMw2oOEc=
|
||||
github.com/loveuer/ngorm/v2 v2.1.1/go.mod h1:BVhFGQsRMdcf08MtmwwRihwCR/x7wDd0Fzy8Xj+edM0=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
@@ -162,15 +189,22 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
|
||||
github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
@@ -183,9 +217,16 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA=
|
||||
github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
|
||||
github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
@@ -193,12 +234,24 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
|
||||
github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
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.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
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/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
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=
|
||||
@@ -206,8 +259,11 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tdewolff/minify/v2 v2.20.16 h1:/C8dtRkxLTIyUlKlBz46gDiktCrE8a6+c1gTrnPFz+U=
|
||||
github.com/tdewolff/minify/v2 v2.20.16/go.mod h1:/FvxV9KaTrFu35J9I2FhRvWSBxcHj8sDSdwBFh5voxM=
|
||||
github.com/tdewolff/parse/v2 v2.7.11 h1:v+W45LnzmjndVlfqPCT5gGjAAZKd1GJGOPJveTIkBY8=
|
||||
@@ -216,16 +272,26 @@ github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZli
|
||||
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
|
||||
github.com/vesoft-inc/nebula-go/v3 v3.5.0 h1:2ZSkoBxtIfs15AXJXqrAPDPd0Z9HrzKR7YKXPqlJcR0=
|
||||
github.com/vesoft-inc/nebula-go/v3 v3.5.0/go.mod h1:+sXv05jYQBARdTbTcIEsWVXCnF/6ttOlDK35xQ6m54s=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
@@ -239,38 +305,33 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/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-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
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/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.4.2/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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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-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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
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/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/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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-20180905080454-ebe1bf3edb33/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=
|
||||
@@ -282,77 +343,68 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210615035016-665e8c7367d1/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
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/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
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/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
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-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.2/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-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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=
|
||||
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=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.50.0 h1:fPVVDxY9w++VjTZsYvXWqEf9Rqar/e+9zYfxKK+W+YU=
|
||||
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
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=
|
||||
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/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
|
||||
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
|
||||
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
||||
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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
@@ -365,10 +417,8 @@ gorm.io/driver/postgres v1.4.4 h1:zt1fxJ+C+ajparn0SteEnkoPg0BQ6wOWXEQ99bteAmw=
|
||||
gorm.io/driver/postgres v1.4.4/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw=
|
||||
gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
|
||||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
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=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
|
||||
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
|
||||
|
||||
35
httptest/user.http
Normal file
35
httptest/user.http
Normal file
@@ -0,0 +1,35 @@
|
||||
### login
|
||||
POST http://127.0.0.1:8080/api/user/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "123456"
|
||||
}
|
||||
|
||||
### logout
|
||||
POST http://127.0.0.1:8080/api/user/auth/logout
|
||||
Content-Type: application/json
|
||||
|
||||
{}
|
||||
|
||||
### verify login state
|
||||
GET http://127.0.0.1:8080/api/user/auth/login
|
||||
|
||||
### change self password
|
||||
POST http://127.0.0.1:8080/api/user/update
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"old_password": "123456",
|
||||
"new_password": "654321@AaBbCc"
|
||||
}
|
||||
|
||||
### relogin with new password
|
||||
POST http://127.0.0.1:8080/api/user/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "654321@AaBbCc"
|
||||
}
|
||||
@@ -24,10 +24,9 @@ func initApp(ctx context.Context) *nf.App {
|
||||
// for example: app := engine.Group("/api/{project}")
|
||||
app := engine.Group("/api")
|
||||
app.Get("/available", func() nf.HandlerFunc {
|
||||
start := time.Now()
|
||||
return func(c *nf.Ctx) error {
|
||||
now := time.Now()
|
||||
return resp.Resp200(c, nf.Map{"ok": true, "start": start, "now": now, "duration": fmt.Sprint(now.Sub(start))})
|
||||
return resp.Resp200(c, nf.Map{"ok": opt.OK, "start": opt.Start, "now": now, "duration": fmt.Sprint(now.Sub(opt.Start))})
|
||||
}
|
||||
}())
|
||||
|
||||
@@ -37,6 +36,8 @@ func initApp(ctx context.Context) *nf.App {
|
||||
api.Get("/auth/login", auth.NewAuth(), handler.AuthVerify)
|
||||
api.Post("/auth/logout", auth.NewAuth(), oplog.NewOpLog(ctx), handler.AuthLogout)
|
||||
|
||||
api.Post("/update", auth.NewAuth(), handler.UserUpdate)
|
||||
|
||||
mng := api.Group("/manage")
|
||||
mng.Use(auth.NewAuth(), privilege.Verify(
|
||||
privilege.RelationAnd,
|
||||
|
||||
80
internal/cmd/cli.go
Normal file
80
internal/cmd/cli.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"net/rpc"
|
||||
"net/url"
|
||||
"ultone/internal/log"
|
||||
"ultone/internal/opt"
|
||||
"ultone/internal/unix"
|
||||
)
|
||||
|
||||
var ()
|
||||
|
||||
func initCli() *cobra.Command {
|
||||
var (
|
||||
svc string
|
||||
cliClient *rpc.Client
|
||||
)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "cli",
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
log.Debug(cmd.Context(), "[cmd.cli] svc address: %s", svc)
|
||||
|
||||
uri, err := url.Parse(svc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cliClient, err = rpc.Dial(uri.Scheme, uri.Host+uri.Path); err != nil {
|
||||
return fmt.Errorf("rpc dial [%s] [%s] err: %w", uri.Scheme, uri.Host+uri.Path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
log.Debug(cmd.Context(), "[cli] start run cli... all args: %v", args)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.PersistentFlags().StringVar(&svc, "svc", opt.RpcAddress, "server unix listen address")
|
||||
cmd.AddCommand(&cobra.Command{
|
||||
Use: "set",
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
log.Debug(cmd.Context(), "[cli.set] all args: %v", args)
|
||||
|
||||
if len(args) < 2 {
|
||||
return fmt.Errorf("at least 2 args required")
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case "debug":
|
||||
out := &unix.Resp[bool]{}
|
||||
in := &unix.SettingReq{Debug: false}
|
||||
switch args[1] {
|
||||
case "true":
|
||||
in.Debug = true
|
||||
case "false":
|
||||
default:
|
||||
return fmt.Errorf("unknown debug value")
|
||||
}
|
||||
|
||||
if err = cliClient.Call("svc.Setting", in, out); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info(cmd.Context(), out.Msg)
|
||||
default:
|
||||
return fmt.Errorf("unknown set variable(debug is available now)")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -2,36 +2,47 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ultone/internal/api"
|
||||
"ultone/internal/controller"
|
||||
"ultone/internal/database/cache"
|
||||
"ultone/internal/database/db"
|
||||
"ultone/internal/log"
|
||||
"ultone/internal/model"
|
||||
"ultone/internal/opt"
|
||||
"ultone/internal/tool"
|
||||
)
|
||||
|
||||
var (
|
||||
filename string
|
||||
)
|
||||
|
||||
func Execute(ctx context.Context) error {
|
||||
var filename string
|
||||
|
||||
func execute(ctx context.Context) error {
|
||||
tool.Must(opt.Init(filename))
|
||||
tool.Must(db.Init())
|
||||
tool.Must(cache.Init())
|
||||
tool.Must(db.Init(ctx, opt.Cfg.DB.Uri))
|
||||
tool.Must(cache.Init(ctx, opt.Cfg.Cache.Uri))
|
||||
|
||||
// todo: if elastic search required
|
||||
// tool.Must(es.Init())
|
||||
// tool.Must(es.Init(ctx, opt.Cfg.ES.Uri))
|
||||
// 或者使用 https://github.com/olivere/elastic
|
||||
// tool.Must(elastic.Init(ctx, opt.Cfg.ES.Uri))
|
||||
|
||||
// todo: if nebula required
|
||||
// tool.Must(nebula.Init(ctx, opt.Cfg.Nebula))
|
||||
|
||||
tool.Must(model.Init(db.New()))
|
||||
tool.Must(model.Init(db.Default.Session()))
|
||||
tool.Must(controller.Init(ctx))
|
||||
tool.Must(api.Start(ctx))
|
||||
|
||||
// todo: if need some cli operation, should start local unix rpc svc
|
||||
// tool.Must(unix.Start(ctx))
|
||||
|
||||
<-ctx.Done()
|
||||
|
||||
log.Warn(ctx, "received quit signal...(2s)")
|
||||
<-tool.Timeout(2).Done()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Execute(ctx context.Context) error {
|
||||
return rootCommand.ExecuteContext(ctx)
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"time"
|
||||
"ultone/internal/opt"
|
||||
)
|
||||
|
||||
func init() {
|
||||
time.Local = time.FixedZone("CST", 8*3600)
|
||||
|
||||
flag.StringVar(&filename, "c", "etc/config.json", "config json file path")
|
||||
flag.BoolVar(&opt.Debug, "debug", false, "")
|
||||
|
||||
flag.Parse()
|
||||
initRoot(initCli())
|
||||
}
|
||||
|
||||
29
internal/cmd/root.go
Normal file
29
internal/cmd/root.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
"github.com/spf13/cobra"
|
||||
"ultone/internal/opt"
|
||||
)
|
||||
|
||||
func initRoot(cmds ...*cobra.Command) {
|
||||
rootCommand.PersistentFlags().BoolVar(&opt.Cfg.Debug, "debug", false, "debug mode")
|
||||
rootCommand.PersistentFlags().StringVarP(&filename, "config", "c", "etc/config.json", "config json file path")
|
||||
rootCommand.PersistentPreRun = func(cmd *cobra.Command, args []string) {
|
||||
if opt.Cfg.Debug {
|
||||
log.SetLogLevel(log.LogLevelDebug)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rootCommand.AddCommand(cmds...)
|
||||
}
|
||||
|
||||
var (
|
||||
rootCommand = &cobra.Command{
|
||||
Use: "nf-app",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return execute(cmd.Context())
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -5,17 +5,19 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/loveuer/nf/nft/resp"
|
||||
"github.com/spf13/cast"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ultone/internal/database/cache"
|
||||
"ultone/internal/database/db"
|
||||
"ultone/internal/log"
|
||||
"ultone/internal/model"
|
||||
"ultone/internal/opt"
|
||||
"ultone/internal/tool"
|
||||
|
||||
"github.com/loveuer/nf/nft/resp"
|
||||
"github.com/spf13/cast"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type userController interface {
|
||||
@@ -23,8 +25,9 @@ type userController interface {
|
||||
GetUserByToken(ctx context.Context, token string) (*model.User, error)
|
||||
CacheUser(ctx context.Context, user *model.User) error
|
||||
CacheToken(ctx context.Context, token string, user *model.User) error
|
||||
RmToken(ctx context.Context, token string) error
|
||||
RmUserCache(ctx context.Context, id uint64) error
|
||||
DeleteUser(ctx context.Context, id uint64) error
|
||||
DeleteUser(ctx context.Context, target *model.User) error
|
||||
}
|
||||
|
||||
type uc struct{}
|
||||
@@ -54,7 +57,7 @@ func (u uc) GetUser(ctx context.Context, id uint64) (*model.User, error) {
|
||||
}
|
||||
|
||||
ByDB:
|
||||
if err = db.New(tool.Timeout(3)).
|
||||
if err = db.Default.Session(tool.Timeout(3)).
|
||||
Model(&model.User{}).
|
||||
Where("id = ?", id).
|
||||
Take(target).
|
||||
@@ -118,35 +121,42 @@ func (u uc) CacheToken(ctx context.Context, token string, user *model.User) erro
|
||||
key := fmt.Sprintf("%s:user:token:%s", opt.CachePrefix, strs[2])
|
||||
return cache.Client.SetEx(tool.Timeout(3), key, user.Id, opt.TokenTimeout)
|
||||
}
|
||||
|
||||
func (u uc) RmToken(ctx context.Context, token string) error {
|
||||
strs := strings.Split(token, ".")
|
||||
if len(strs) != 3 {
|
||||
return fmt.Errorf("controller.CacheToken: jwt token invalid")
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("%s:user:token:%s", opt.CachePrefix, strs[2])
|
||||
return cache.Client.Del(tool.Timeout(3), key)
|
||||
}
|
||||
|
||||
func (u uc) RmUserCache(ctx context.Context, id uint64) error {
|
||||
key := fmt.Sprintf("%s:user:id:%d", opt.CachePrefix, id)
|
||||
return cache.Client.Del(tool.Timeout(3), key)
|
||||
}
|
||||
|
||||
func (u uc) DeleteUser(ctx context.Context, id uint64) error {
|
||||
func (u uc) DeleteUser(ctx context.Context, target *model.User) error {
|
||||
var (
|
||||
err error
|
||||
now = time.Now()
|
||||
username = "CONCAT(username, '@del')"
|
||||
username = fmt.Sprintf("%s@%d", target.Username, now.UnixMilli())
|
||||
)
|
||||
|
||||
if opt.Cfg.DB.Type == "sqlite" {
|
||||
username = "username || '@del'"
|
||||
}
|
||||
|
||||
if err = db.New(tool.Timeout(5)).
|
||||
if err = db.Default.Session(tool.Timeout(5)).
|
||||
Model(&model.User{}).
|
||||
Where("id = ?", id).
|
||||
Where("id = ?", target.Id).
|
||||
Updates(map[string]any{
|
||||
"deleted_at": now.UnixMilli(),
|
||||
"username": gorm.Expr(username),
|
||||
"username": username,
|
||||
}).Error; err != nil {
|
||||
return resp.NewError(500, "", err, nil)
|
||||
}
|
||||
|
||||
if opt.EnableUserCache {
|
||||
if err = u.RmUserCache(ctx, id); err != nil {
|
||||
log.Warn(ctx, "controller.DeleteUser: rm user=%d cache err=%v", id, err)
|
||||
if err = u.RmUserCache(ctx, target.Id); err != nil {
|
||||
log.Warn(ctx, "controller.DeleteUser: rm user=%d cache err=%v", target.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
63
internal/database/cache/cache.go
vendored
Normal file
63
internal/database/cache/cache.go
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cache interface {
|
||||
Get(ctx context.Context, key string) ([]byte, error)
|
||||
Gets(ctx context.Context, keys ...string) ([][]byte, error)
|
||||
GetScan(ctx context.Context, key string) Scanner
|
||||
GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error)
|
||||
GetExScan(ctx context.Context, key string, duration time.Duration) Scanner
|
||||
// Set value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
|
||||
Set(ctx context.Context, key string, value any) error
|
||||
Sets(ctx context.Context, vm map[string]any) error
|
||||
// SetEx value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
|
||||
SetEx(ctx context.Context, key string, value any, duration time.Duration) error
|
||||
Del(ctx context.Context, keys ...string) error
|
||||
Close() error
|
||||
}
|
||||
|
||||
var Client Cache
|
||||
|
||||
type Scanner interface {
|
||||
Scan(model any) error
|
||||
}
|
||||
|
||||
type encoded_value interface {
|
||||
MarshalBinary() ([]byte, error)
|
||||
}
|
||||
|
||||
type decoded_value interface {
|
||||
UnmarshalBinary(bs []byte) error
|
||||
}
|
||||
|
||||
const (
|
||||
Prefix = "upp:"
|
||||
)
|
||||
|
||||
var ErrorKeyNotFound = errors.New("key not found")
|
||||
|
||||
func handleValue(value any) ([]byte, error) {
|
||||
var (
|
||||
bs []byte
|
||||
err error
|
||||
)
|
||||
|
||||
switch value.(type) {
|
||||
case []byte:
|
||||
return value.([]byte), nil
|
||||
}
|
||||
|
||||
if imp, ok := value.(encoded_value); ok {
|
||||
bs, err = imp.MarshalBinary()
|
||||
} else {
|
||||
bs, err = json.Marshal(value)
|
||||
}
|
||||
|
||||
return bs, err
|
||||
}
|
||||
@@ -2,13 +2,13 @@ package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/golang-lru/v2/expirable"
|
||||
_ "github.com/hashicorp/golang-lru/v2/expirable"
|
||||
"time"
|
||||
"ultone/internal/interfaces"
|
||||
)
|
||||
|
||||
var _ interfaces.Cacher = (*_lru)(nil)
|
||||
var _ Cache = (*_lru)(nil)
|
||||
|
||||
type _lru struct {
|
||||
client *expirable.LRU[string, *_lru_value]
|
||||
@@ -38,6 +38,24 @@ func (l *_lru) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
return v.bs, nil
|
||||
}
|
||||
|
||||
func (l *_lru) Gets(ctx context.Context, keys ...string) ([][]byte, error) {
|
||||
bss := make([][]byte, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
bs, err := l.Get(ctx, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bss = append(bss, bs)
|
||||
}
|
||||
|
||||
return bss, nil
|
||||
}
|
||||
|
||||
func (l *_lru) GetScan(ctx context.Context, key string) Scanner {
|
||||
return newScanner(l.Get(ctx, key))
|
||||
}
|
||||
|
||||
func (l *_lru) GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error) {
|
||||
v, ok := l.client.Get(key)
|
||||
if !ok {
|
||||
@@ -64,6 +82,10 @@ func (l *_lru) GetEx(ctx context.Context, key string, duration time.Duration) ([
|
||||
return v.bs, nil
|
||||
}
|
||||
|
||||
func (l *_lru) GetExScan(ctx context.Context, key string, duration time.Duration) Scanner {
|
||||
return newScanner(l.GetEx(ctx, key, duration))
|
||||
}
|
||||
|
||||
func (l *_lru) Set(ctx context.Context, key string, value any) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
@@ -94,6 +116,16 @@ func (l *_lru) SetEx(ctx context.Context, key string, value any, duration time.D
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *_lru) Sets(ctx context.Context, m map[string]any) error {
|
||||
for k, v := range m {
|
||||
if err := l.Set(ctx, k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *_lru) Del(ctx context.Context, keys ...string) error {
|
||||
for _, key := range keys {
|
||||
l.client.Remove(key)
|
||||
@@ -102,8 +134,13 @@ func (l *_lru) Del(ctx context.Context, keys ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newLRUCache() (interfaces.Cacher, error) {
|
||||
client := expirable.NewLRU[string, *_lru_value](0, nil, 0)
|
||||
func (l *_lru) Close() error {
|
||||
l.client = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func newLRUCache() (Cache, error) {
|
||||
client := expirable.NewLRU[string, *_lru_value](1024*1024, nil, 0)
|
||||
|
||||
return &_lru{client: client}, nil
|
||||
}
|
||||
@@ -5,17 +5,24 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"ultone/internal/interfaces"
|
||||
|
||||
"gitea.com/taozitaozi/gredis"
|
||||
)
|
||||
|
||||
var _ interfaces.Cacher = (*_mem)(nil)
|
||||
var _ Cache = (*_mem)(nil)
|
||||
|
||||
type _mem struct {
|
||||
client *gredis.Gredis
|
||||
}
|
||||
|
||||
func (m *_mem) GetScan(ctx context.Context, key string) Scanner {
|
||||
return newScanner(m.Get(ctx, key))
|
||||
}
|
||||
|
||||
func (m *_mem) GetExScan(ctx context.Context, key string, duration time.Duration) Scanner {
|
||||
return newScanner(m.GetEx(ctx, key, duration))
|
||||
}
|
||||
|
||||
func (m *_mem) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
v, err := m.client.Get(key)
|
||||
if err != nil {
|
||||
@@ -34,6 +41,20 @@ func (m *_mem) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func (m *_mem) Gets(ctx context.Context, keys ...string) ([][]byte, error) {
|
||||
bss := make([][]byte, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
bs, err := m.Get(ctx, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bss = append(bss, bs)
|
||||
}
|
||||
|
||||
return bss, nil
|
||||
}
|
||||
|
||||
func (m *_mem) GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error) {
|
||||
v, err := m.client.GetEx(key, duration)
|
||||
if err != nil {
|
||||
@@ -60,6 +81,16 @@ func (m *_mem) Set(ctx context.Context, key string, value any) error {
|
||||
return m.client.Set(key, bs)
|
||||
}
|
||||
|
||||
func (m *_mem) Sets(ctx context.Context, vm map[string]any) error {
|
||||
for k, v := range vm {
|
||||
if err := m.Set(ctx, k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *_mem) SetEx(ctx context.Context, key string, value any, duration time.Duration) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
@@ -72,3 +103,9 @@ func (m *_mem) Del(ctx context.Context, keys ...string) error {
|
||||
m.client.Delete(keys...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *_mem) Close() error {
|
||||
m.client = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -3,8 +3,11 @@ package cache
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type _redis struct {
|
||||
@@ -24,6 +27,28 @@ func (r *_redis) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
return []byte(result), nil
|
||||
}
|
||||
|
||||
func (r *_redis) Gets(ctx context.Context, keys ...string) ([][]byte, error) {
|
||||
result, err := r.client.MGet(ctx, keys...).Result()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, ErrorKeyNotFound
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return lo.Map(
|
||||
result,
|
||||
func(item any, index int) []byte {
|
||||
return []byte(cast.ToString(item))
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
func (r *_redis) GetScan(ctx context.Context, key string) Scanner {
|
||||
return newScanner(r.Get(ctx, key))
|
||||
}
|
||||
|
||||
func (r *_redis) GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error) {
|
||||
result, err := r.client.GetEx(ctx, key, duration).Result()
|
||||
if err != nil {
|
||||
@@ -37,6 +62,10 @@ func (r *_redis) GetEx(ctx context.Context, key string, duration time.Duration)
|
||||
return []byte(result), nil
|
||||
}
|
||||
|
||||
func (r *_redis) GetExScan(ctx context.Context, key string, duration time.Duration) Scanner {
|
||||
return newScanner(r.GetEx(ctx, key, duration))
|
||||
}
|
||||
|
||||
func (r *_redis) Set(ctx context.Context, key string, value any) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
@@ -47,6 +76,20 @@ func (r *_redis) Set(ctx context.Context, key string, value any) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *_redis) Sets(ctx context.Context, values map[string]any) error {
|
||||
vm := make(map[string]any)
|
||||
for k, v := range values {
|
||||
bs, err := handleValue(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm[k] = bs
|
||||
}
|
||||
|
||||
return r.client.MSet(ctx, vm).Err()
|
||||
}
|
||||
|
||||
func (r *_redis) SetEx(ctx context.Context, key string, value any, duration time.Duration) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
@@ -61,3 +104,7 @@ func (r *_redis) SetEx(ctx context.Context, key string, value any, duration time
|
||||
func (r *_redis) Del(ctx context.Context, keys ...string) error {
|
||||
return r.client.Del(ctx, keys...).Err()
|
||||
}
|
||||
|
||||
func (r *_redis) Close() error {
|
||||
return r.client.Close()
|
||||
}
|
||||
33
internal/database/cache/client.go
vendored
33
internal/database/cache/client.go
vendored
@@ -1,33 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"ultone/internal/interfaces"
|
||||
)
|
||||
|
||||
var (
|
||||
Client interfaces.Cacher
|
||||
)
|
||||
|
||||
type encoded_value interface {
|
||||
MarshalBinary() ([]byte, error)
|
||||
}
|
||||
|
||||
type decoded_value interface {
|
||||
UnmarshalBinary(bs []byte) error
|
||||
}
|
||||
|
||||
func handleValue(value any) ([]byte, error) {
|
||||
var (
|
||||
bs []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if imp, ok := value.(encoded_value); ok {
|
||||
bs, err = imp.MarshalBinary()
|
||||
} else {
|
||||
bs, err = json.Marshal(value)
|
||||
}
|
||||
|
||||
return bs, err
|
||||
}
|
||||
7
internal/database/cache/error.go
vendored
7
internal/database/cache/error.go
vendored
@@ -1,7 +0,0 @@
|
||||
package cache
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrorKeyNotFound = errors.New("key not found")
|
||||
)
|
||||
@@ -1,30 +1,31 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"gitea.com/taozitaozi/gredis"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"net/url"
|
||||
"strings"
|
||||
"ultone/internal/opt"
|
||||
|
||||
"ultone/internal/tool"
|
||||
|
||||
"gitea.com/taozitaozi/gredis"
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
func Init() error {
|
||||
|
||||
func New(ctx context.Context, uri string) (Cache, error) {
|
||||
var (
|
||||
err error
|
||||
err error
|
||||
newClient Cache
|
||||
strs = strings.Split(uri, "::")
|
||||
)
|
||||
|
||||
strs := strings.Split(opt.Cfg.Cache.Uri, "::")
|
||||
|
||||
switch strs[0] {
|
||||
case "memory":
|
||||
gc := gredis.NewGredis(1024 * 1024)
|
||||
Client = &_mem{client: gc}
|
||||
newClient = &_mem{client: gc}
|
||||
case "lru":
|
||||
if Client, err = newLRUCache(); err != nil {
|
||||
return err
|
||||
if newClient, err = newLRUCache(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "redis":
|
||||
var (
|
||||
@@ -33,7 +34,7 @@ func Init() error {
|
||||
)
|
||||
|
||||
if len(strs) != 2 {
|
||||
return fmt.Errorf("cache.Init: invalid cache uri: %s", opt.Cfg.Cache.Uri)
|
||||
return nil, fmt.Errorf("cache.Init: invalid cache uri: %s", uri)
|
||||
}
|
||||
|
||||
uri := strs[1]
|
||||
@@ -43,7 +44,7 @@ func Init() error {
|
||||
}
|
||||
|
||||
if ins, err = url.Parse(uri); err != nil {
|
||||
return fmt.Errorf("cache.Init: url parse cache uri: %s, err: %s", opt.Cfg.Cache.Uri, err.Error())
|
||||
return nil, fmt.Errorf("cache.Init: url parse cache uri: %s, err: %s", uri, err.Error())
|
||||
}
|
||||
|
||||
addr := ins.Host
|
||||
@@ -58,13 +59,18 @@ func Init() error {
|
||||
})
|
||||
|
||||
if err = rc.Ping(tool.Timeout(5)).Err(); err != nil {
|
||||
return fmt.Errorf("cache.Init: redis ping err: %s", err.Error())
|
||||
return nil, fmt.Errorf("cache.Init: redis ping err: %s", err.Error())
|
||||
}
|
||||
|
||||
Client = &_redis{client: rc}
|
||||
newClient = &_redis{client: rc}
|
||||
default:
|
||||
return fmt.Errorf("cache type %s not support", strs[0])
|
||||
return nil, fmt.Errorf("cache type %s not support", strs[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
return newClient, nil
|
||||
}
|
||||
|
||||
func Init(ctx context.Context, uri string) (err error) {
|
||||
Client, err = New(ctx, uri)
|
||||
return
|
||||
}
|
||||
20
internal/database/cache/scan.go
vendored
Normal file
20
internal/database/cache/scan.go
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package cache
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type scanner struct {
|
||||
err error
|
||||
bs []byte
|
||||
}
|
||||
|
||||
func (s *scanner) Scan(model any) error {
|
||||
if s.err != nil {
|
||||
return s.err
|
||||
}
|
||||
|
||||
return json.Unmarshal(s.bs, model)
|
||||
}
|
||||
|
||||
func newScanner(bs []byte, err error) *scanner {
|
||||
return &scanner{bs: bs, err: err}
|
||||
}
|
||||
@@ -2,25 +2,34 @@ package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"ultone/internal/opt"
|
||||
"ultone/internal/tool"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
cli = &client{}
|
||||
var Default *Client
|
||||
|
||||
type DBType string
|
||||
|
||||
const (
|
||||
DBTypeSqlite = "sqlite"
|
||||
DBTypeMysql = "mysql"
|
||||
DBTypePostgres = "postgres"
|
||||
)
|
||||
|
||||
type client struct {
|
||||
cli *gorm.DB
|
||||
ttype string
|
||||
type Client struct {
|
||||
ctx context.Context
|
||||
cli *gorm.DB
|
||||
dbType DBType
|
||||
}
|
||||
|
||||
func Type() string {
|
||||
return cli.ttype
|
||||
func (c *Client) Type() DBType {
|
||||
return c.dbType
|
||||
}
|
||||
|
||||
func New(ctxs ...context.Context) *gorm.DB {
|
||||
func (c *Client) Session(ctxs ...context.Context) *gorm.DB {
|
||||
var ctx context.Context
|
||||
if len(ctxs) > 0 && ctxs[0] != nil {
|
||||
ctx = ctxs[0]
|
||||
@@ -28,11 +37,16 @@ func New(ctxs ...context.Context) *gorm.DB {
|
||||
ctx = tool.Timeout(30)
|
||||
}
|
||||
|
||||
session := cli.cli.Session(&gorm.Session{Context: ctx})
|
||||
session := c.cli.Session(&gorm.Session{Context: ctx})
|
||||
|
||||
if opt.Debug {
|
||||
if opt.Cfg.Debug {
|
||||
session = session.Debug()
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
func (c *Client) Close() {
|
||||
d, _ := c.cli.DB()
|
||||
d.Close()
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
"ultone/internal/opt"
|
||||
)
|
||||
|
||||
func Init() error {
|
||||
strs := strings.Split(opt.Cfg.DB.Uri, "::")
|
||||
|
||||
if len(strs) != 2 {
|
||||
return fmt.Errorf("db.Init: opt db uri invalid: %s", opt.Cfg.DB.Uri)
|
||||
}
|
||||
|
||||
cli.ttype = strs[0]
|
||||
|
||||
var (
|
||||
err error
|
||||
dsn = strs[1]
|
||||
)
|
||||
|
||||
switch strs[0] {
|
||||
case "sqlite":
|
||||
opt.Cfg.DB.Type = "sqlite"
|
||||
cli.cli, err = gorm.Open(sqlite.Open(dsn))
|
||||
case "mysql":
|
||||
opt.Cfg.DB.Type = "mysql"
|
||||
cli.cli, err = gorm.Open(mysql.Open(dsn))
|
||||
case "postgres":
|
||||
opt.Cfg.DB.Type = "postgres"
|
||||
cli.cli, err = gorm.Open(postgres.Open(dsn))
|
||||
default:
|
||||
return fmt.Errorf("db type only support: [sqlite, mysql, postgres], unsupported db type: %s", strs[0])
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("db.Init: open %s with dsn:%s, err: %w", strs[0], dsn, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
65
internal/database/db/new.go
Normal file
65
internal/database/db/new.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const tip = `example:
|
||||
for sqlite -> sqlite::<filepath>
|
||||
sqlite::data.sqlite
|
||||
sqlite::/data/data.db
|
||||
for mysql -> mysql::<gorm_dsn>
|
||||
mysql::user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
|
||||
for postgres -> postgres::<gorm_dsn>
|
||||
postgres::host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai
|
||||
`
|
||||
|
||||
func New(ctx context.Context, uri string) (*Client, error) {
|
||||
parts := strings.SplitN(uri, "::", 2)
|
||||
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("db.Init: db uri invalid\n%s", tip)
|
||||
}
|
||||
|
||||
c := &Client{}
|
||||
|
||||
var (
|
||||
err error
|
||||
dsn = parts[1]
|
||||
)
|
||||
|
||||
switch parts[0] {
|
||||
case "sqlite":
|
||||
c.dbType = DBTypeSqlite
|
||||
c.cli, err = gorm.Open(sqlite.Open(dsn))
|
||||
case "mysql":
|
||||
c.dbType = DBTypeMysql
|
||||
c.cli, err = gorm.Open(mysql.Open(dsn))
|
||||
case "postgres":
|
||||
c.dbType = DBTypePostgres
|
||||
c.cli, err = gorm.Open(postgres.Open(dsn))
|
||||
default:
|
||||
return nil, fmt.Errorf("db type only support: [sqlite, mysql, postgres], unsupported db type: %s", parts[0])
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("db.Init: open %s with dsn:%s, err: %w", parts[0], dsn, err)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func Init(ctx context.Context, uri string) (err error) {
|
||||
if Default, err = New(ctx, uri); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
119
internal/database/elastic/client.go
Normal file
119
internal/database/elastic/client.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package elastic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
es "github.com/olivere/elastic/v7"
|
||||
"github.com/spf13/cast"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
Client *es.Client
|
||||
)
|
||||
|
||||
const (
|
||||
ExampleUri = "https://username:password@ip1:9200,ip2:9200?disable_sniff=false&health=false"
|
||||
)
|
||||
|
||||
func New(ctx context.Context, uri string) (*es.Client, error) {
|
||||
var (
|
||||
err error
|
||||
ins *url.URL
|
||||
client *es.Client
|
||||
version string
|
||||
)
|
||||
|
||||
if ins, err = url.Parse(uri); err != nil {
|
||||
return nil, fmt.Errorf("invalid uri: %v\nexample uri: %s", err, ExampleUri)
|
||||
}
|
||||
|
||||
if !(ins.Scheme == "http" || ins.Scheme == "https") {
|
||||
return nil, fmt.Errorf("invalid uri scheme: %v\nexample uri: %s", err, ExampleUri)
|
||||
}
|
||||
|
||||
hosts := strings.Split(ins.Host, ",")
|
||||
if len(hosts) == 0 {
|
||||
return nil, fmt.Errorf("invalid uri hosts: %v\nexample uri: %s", err, ExampleUri)
|
||||
}
|
||||
|
||||
opts := make([]es.ClientOptionFunc, 0)
|
||||
shouldHosts := make([]string, 0)
|
||||
oks := make([]string, 0)
|
||||
bads := make([]string, 0)
|
||||
|
||||
for idx := range hosts {
|
||||
if len(hosts[idx]) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
opts = append(opts, es.SetURL(hosts[idx]))
|
||||
shouldHosts = append(shouldHosts, hosts[idx])
|
||||
}
|
||||
|
||||
if len(opts) == 0 {
|
||||
return nil, fmt.Errorf("invalid uri hosts: %v\nexample uri: %s", err, ExampleUri)
|
||||
}
|
||||
|
||||
if ins.Scheme == "https" {
|
||||
opts = append(opts, es.SetScheme("https"))
|
||||
opts = append(opts, es.SetHttpClient(
|
||||
&http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
if ins.User != nil {
|
||||
username := ins.User.Username()
|
||||
password, _ := ins.User.Password()
|
||||
opts = append(opts, es.SetBasicAuth(username, password))
|
||||
}
|
||||
|
||||
if cast.ToBool(ins.Query().Get("disable_sniff")) {
|
||||
opts = append(opts, es.SetSniff(false))
|
||||
}
|
||||
|
||||
if cast.ToBool(ins.Query().Get("health")) {
|
||||
opts = append(opts, es.SetHealthcheckInterval(time.Minute))
|
||||
opts = append(opts, es.SetHealthcheckTimeout(5*time.Second))
|
||||
} else {
|
||||
opts = append(opts, es.SetHealthcheck(false))
|
||||
}
|
||||
|
||||
client, err = es.NewClient(opts...)
|
||||
|
||||
for idx := range shouldHosts {
|
||||
if version, err = client.ElasticsearchVersion(shouldHosts[idx]); err != nil {
|
||||
bads = append(bads, shouldHosts[idx])
|
||||
continue
|
||||
}
|
||||
|
||||
oks = append(oks, shouldHosts[idx])
|
||||
}
|
||||
|
||||
switch len(oks) {
|
||||
case 0:
|
||||
return nil, fmt.Errorf("all nodes: %+v unavailable", shouldHosts)
|
||||
case len(shouldHosts):
|
||||
log.Info("connect to elastic[version: %s] success, all nodes: %+v available", version, shouldHosts)
|
||||
default:
|
||||
log.Warn("connect to elastic all nodes: %+v, err nodes: %v", shouldHosts, bads)
|
||||
}
|
||||
|
||||
return client, err
|
||||
}
|
||||
|
||||
func Init(ctx context.Context, uri string) (err error) {
|
||||
Client, err = New(ctx, uri)
|
||||
return err
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package es
|
||||
|
||||
import (
|
||||
"context"
|
||||
elastic "github.com/elastic/go-elasticsearch/v7"
|
||||
"github.com/loveuer/esgo2dump/xes/es7"
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
@@ -13,17 +14,27 @@ var (
|
||||
Client *elastic.Client
|
||||
)
|
||||
|
||||
func Init() error {
|
||||
ins, err := url.Parse(opt.Cfg.ES.Uri)
|
||||
if err != nil {
|
||||
return err
|
||||
func New(ctx context.Context, uri string) (*elastic.Client, error) {
|
||||
var (
|
||||
err error
|
||||
client *elastic.Client
|
||||
ins *url.URL
|
||||
)
|
||||
|
||||
if ins, err = url.Parse(uri); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("es.InitClient url parse uri: %s, result: %+v", opt.Cfg.ES.Uri, ins)
|
||||
|
||||
if Client, err = es7.NewClient(tool.Timeout(10), ins); err != nil {
|
||||
return err
|
||||
if client, err = es7.NewClient(tool.Timeout(10), ins); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func Init(ctx context.Context, uri string) (err error) {
|
||||
Client, err = New(ctx, uri)
|
||||
return err
|
||||
}
|
||||
|
||||
67
internal/database/kafka/client.go
Normal file
67
internal/database/kafka/client.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"ultone/internal/interfaces"
|
||||
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
kfkgo "github.com/segmentio/kafka-go"
|
||||
"github.com/segmentio/kafka-go/sasl"
|
||||
)
|
||||
|
||||
var Client *client
|
||||
|
||||
type client struct {
|
||||
sync.Mutex
|
||||
ctx context.Context
|
||||
d *kfkgo.Dialer
|
||||
topic string
|
||||
partition int
|
||||
reconnection bool
|
||||
mechanism sasl.Mechanism
|
||||
address string
|
||||
logger interfaces.Logger
|
||||
writer *kfkgo.Writer
|
||||
tls *tls.Config
|
||||
}
|
||||
|
||||
func Init(address string, opts ...OptionFn) error {
|
||||
c, err := New(address, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Client = c
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func New(address string, opts ...OptionFn) (*client, error) {
|
||||
c := &client{
|
||||
ctx: context.Background(),
|
||||
d: &kfkgo.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
DualStack: false,
|
||||
},
|
||||
tls: nil,
|
||||
mechanism: nil,
|
||||
logger: log.New(),
|
||||
}
|
||||
|
||||
if address == "" {
|
||||
return nil, fmt.Errorf("address required")
|
||||
}
|
||||
|
||||
for _, fn := range opts {
|
||||
fn(c)
|
||||
}
|
||||
|
||||
c.address = address
|
||||
|
||||
return c, nil
|
||||
}
|
||||
98
internal/database/kafka/client_test.go
Normal file
98
internal/database/kafka/client_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"ultone/internal/tool"
|
||||
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
)
|
||||
|
||||
func TestKafka(t *testing.T) {
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
defer cancel()
|
||||
|
||||
address := os.Getenv("TARGET")
|
||||
password := os.Getenv("PASSWORD")
|
||||
|
||||
t.Logf("address = %s, password = %s", address, password)
|
||||
|
||||
client, err := New(address,
|
||||
WithTopic("test_zyp"),
|
||||
WithPlainAuth("admin", password),
|
||||
WithReconnection(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(1, err)
|
||||
}
|
||||
|
||||
ch, err := client.ReadMessage(ctx, ReadConfig{})
|
||||
if err != nil {
|
||||
t.Fatal(2, err)
|
||||
}
|
||||
|
||||
for msg := range ch {
|
||||
if msg.err != nil {
|
||||
t.Logf("[Error] [TestKafka] msg.err = %v", msg.err)
|
||||
continue
|
||||
}
|
||||
|
||||
t.Logf("[Info ] [TestKafka] [time = %s] [msg.topic = %s] [msg.key = %s] [msg.value = %s]", time.Now().Format("060102T150405"), msg.Topic, string(msg.Key), string(msg.Value))
|
||||
}
|
||||
}
|
||||
|
||||
func TestKafkaWrite(t *testing.T) {
|
||||
log.SetLogLevel(log.LogLevelDebug)
|
||||
address := os.Getenv("TARGET")
|
||||
password := os.Getenv("PASSWORD")
|
||||
|
||||
t.Logf("address = %s, password = %s", address, password)
|
||||
|
||||
client, err := New(address,
|
||||
WithTopic("test_zyp"),
|
||||
WithPlainAuth("admin", password),
|
||||
WithReconnection(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(1, err)
|
||||
}
|
||||
|
||||
if err = client.WriteMessages(tool.Timeout(5),
|
||||
&Payload{
|
||||
Key: []byte(time.Now().Format("2006/01/02 15:04:05")),
|
||||
Value: []byte(tool.RandomString(16)),
|
||||
},
|
||||
&Payload{
|
||||
Key: []byte(time.Now().Format("2006/01/02 15:04:05")),
|
||||
Value: []byte(tool.RandomString(16)),
|
||||
},
|
||||
&Payload{
|
||||
Key: []byte(time.Now().Format("2006/01/02 15:04:05")),
|
||||
Value: []byte(tool.RandomString(16)),
|
||||
},
|
||||
); err != nil {
|
||||
t.Log(2, err)
|
||||
}
|
||||
|
||||
if err = client.WriteMessages(context.Background(),
|
||||
&Payload{
|
||||
Key: []byte(time.Now().Format("2006/01/02 15:04:05")),
|
||||
Value: []byte(tool.RandomString(16)),
|
||||
},
|
||||
&Payload{
|
||||
Key: []byte(time.Now().Format("2006/01/02 15:04:05")),
|
||||
Value: []byte(tool.RandomString(16)),
|
||||
},
|
||||
&Payload{
|
||||
Key: []byte(time.Now().Format("2006/01/02 15:04:05")),
|
||||
Value: []byte(tool.RandomString(16)),
|
||||
},
|
||||
); err != nil {
|
||||
t.Log(3, err)
|
||||
}
|
||||
}
|
||||
158
internal/database/kafka/consumer.go
Normal file
158
internal/database/kafka/consumer.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"ultone/internal/tool"
|
||||
|
||||
kfkgo "github.com/segmentio/kafka-go"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
kfkgo.Message
|
||||
err error
|
||||
}
|
||||
|
||||
type ReadConfig struct {
|
||||
// MaxBytes: read buffer max bytes
|
||||
/*
|
||||
- default 1MB
|
||||
*/
|
||||
MaxBytes int
|
||||
|
||||
// FirstOffset
|
||||
/*
|
||||
- false: use last offset(-1)
|
||||
- true: use first offset(-2)
|
||||
- default: false
|
||||
- more: [about group offset](https://github.com/segmentio/kafka-go/blob/main/reader.go#L16)
|
||||
*/
|
||||
FirstOffset bool
|
||||
|
||||
Topic string
|
||||
Group string
|
||||
|
||||
// Timeout: every read max duration
|
||||
/*
|
||||
- default: 30 seconds (same with kafka-go default)
|
||||
*/
|
||||
Timeout int
|
||||
}
|
||||
|
||||
var defaultReadConfig = ReadConfig{
|
||||
// 1 MB
|
||||
MaxBytes: 1e6,
|
||||
Group: "default",
|
||||
Timeout: 30,
|
||||
}
|
||||
|
||||
func (c *client) ReadMessage(ctx context.Context, configs ...ReadConfig) (<-chan *Message, error) {
|
||||
var (
|
||||
err error
|
||||
cfg = ReadConfig{}
|
||||
ch = make(chan *Message, 1)
|
||||
retry = 0
|
||||
)
|
||||
|
||||
if len(configs) > 0 {
|
||||
cfg = configs[0]
|
||||
}
|
||||
|
||||
if cfg.Group == "" {
|
||||
cfg.Group = defaultReadConfig.Group
|
||||
}
|
||||
|
||||
if cfg.MaxBytes <= 0 {
|
||||
cfg.MaxBytes = defaultReadConfig.MaxBytes
|
||||
}
|
||||
|
||||
if cfg.Timeout <= 0 {
|
||||
cfg.Timeout = defaultReadConfig.Timeout
|
||||
}
|
||||
|
||||
offset := kfkgo.LastOffset
|
||||
if cfg.FirstOffset {
|
||||
offset = kfkgo.FirstOffset
|
||||
}
|
||||
|
||||
rc := kfkgo.ReaderConfig{
|
||||
Brokers: []string{c.address},
|
||||
GroupID: cfg.Group,
|
||||
Topic: c.topic,
|
||||
Partition: c.partition,
|
||||
Dialer: c.d,
|
||||
MaxBytes: cfg.MaxBytes,
|
||||
StartOffset: offset,
|
||||
}
|
||||
|
||||
if err = rc.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := kfkgo.NewReader(rc)
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
close(ch)
|
||||
_ = r.Close()
|
||||
}()
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
close(ch)
|
||||
_ = r.Close()
|
||||
return
|
||||
default:
|
||||
msg, err := r.ReadMessage(tool.TimeoutCtx(ctx, cfg.Timeout))
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
continue Loop
|
||||
}
|
||||
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
|
||||
c.logger.Debug("kafka.ReadMessage: err = %s", err.Error())
|
||||
|
||||
if errors.Is(err, io.EOF) {
|
||||
return
|
||||
}
|
||||
|
||||
if errors.Is(err, io.ErrShortBuffer) {
|
||||
ch <- &Message{
|
||||
Message: msg,
|
||||
err: err,
|
||||
}
|
||||
continue Loop
|
||||
}
|
||||
|
||||
if c.reconnection {
|
||||
retry++
|
||||
c.logger.Warn("kafka.ReadMessage: reconnection after 30 seconds, times = %d, err = %s", retry, err.Error())
|
||||
time.Sleep(30 * time.Second)
|
||||
continue Loop
|
||||
}
|
||||
|
||||
ch <- &Message{
|
||||
Message: msg,
|
||||
err: err,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
ch <- &Message{
|
||||
Message: msg,
|
||||
err: nil,
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return ch, nil
|
||||
}
|
||||
51
internal/database/kafka/option.go
Normal file
51
internal/database/kafka/option.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"ultone/internal/interfaces"
|
||||
|
||||
"github.com/segmentio/kafka-go/sasl/plain"
|
||||
)
|
||||
|
||||
type OptionFn func(*client)
|
||||
|
||||
func WithPlainAuth(username, password string) OptionFn {
|
||||
return func(c *client) {
|
||||
c.mechanism = plain.Mechanism{
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
c.d.SASLMechanism = c.mechanism
|
||||
}
|
||||
}
|
||||
|
||||
func WithTLS(config *tls.Config) OptionFn {
|
||||
return func(c *client) {
|
||||
c.tls = config
|
||||
c.d.TLS = config
|
||||
}
|
||||
}
|
||||
|
||||
func WithTopic(topic string) OptionFn {
|
||||
return func(c *client) {
|
||||
c.topic = topic
|
||||
}
|
||||
}
|
||||
|
||||
func WithPartition(partition int) OptionFn {
|
||||
return func(c *client) {
|
||||
c.partition = partition
|
||||
}
|
||||
}
|
||||
|
||||
func WithReconnection() OptionFn {
|
||||
return func(c *client) {
|
||||
c.reconnection = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithLogger(logger interfaces.Logger) OptionFn {
|
||||
return func(c *client) {
|
||||
c.logger = logger
|
||||
}
|
||||
}
|
||||
81
internal/database/kafka/writer.go
Normal file
81
internal/database/kafka/writer.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
kfkgo "github.com/segmentio/kafka-go"
|
||||
)
|
||||
|
||||
type Payload struct {
|
||||
Key []byte
|
||||
Value []byte
|
||||
Headers []kfkgo.Header
|
||||
WriterData any
|
||||
}
|
||||
|
||||
func (c *client) WriteMessages(ctx context.Context, payloads ...*Payload) error {
|
||||
if len(payloads) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
times := 0
|
||||
Retry:
|
||||
if c.writer == nil {
|
||||
c.Lock()
|
||||
c.writer = &kfkgo.Writer{
|
||||
Addr: kfkgo.TCP(c.address),
|
||||
Topic: c.topic,
|
||||
Balancer: &kfkgo.Hash{},
|
||||
WriteTimeout: 0,
|
||||
RequiredAcks: 0,
|
||||
Async: false,
|
||||
Transport: &kfkgo.Transport{
|
||||
DialTimeout: 30 * time.Second,
|
||||
TLS: c.tls, // todo
|
||||
SASL: c.mechanism,
|
||||
Context: c.ctx,
|
||||
},
|
||||
AllowAutoTopicCreation: true,
|
||||
}
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
msgs := make([]kfkgo.Message, 0, len(payloads))
|
||||
|
||||
for _, item := range payloads {
|
||||
msgs = append(msgs, kfkgo.Message{
|
||||
Key: item.Key,
|
||||
Value: item.Value,
|
||||
Headers: item.Headers,
|
||||
WriterData: item.WriterData,
|
||||
Time: now,
|
||||
})
|
||||
}
|
||||
|
||||
context.WithoutCancel(ctx)
|
||||
if err := c.writer.WriteMessages(ctx, msgs...); err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
goto HandleError
|
||||
}
|
||||
|
||||
if c.reconnection {
|
||||
times++
|
||||
c.logger.Warn("kafka.WriteMessage: reconnection after 30 seconds, times = %d, err = %s", times, err.Error())
|
||||
time.Sleep(30 * time.Second)
|
||||
c.Lock()
|
||||
c.writer = nil
|
||||
c.Unlock()
|
||||
goto Retry
|
||||
}
|
||||
|
||||
HandleError:
|
||||
c.logger.Warn("kafka.WriteMessage: err = %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
193
internal/database/s3/by_dir.go
Normal file
193
internal/database/s3/by_dir.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"ultone/internal/log"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type s3_dir struct {
|
||||
ctx context.Context
|
||||
dir string
|
||||
}
|
||||
|
||||
func (s *s3_dir) clean() {
|
||||
now := time.Now()
|
||||
|
||||
filepath.Walk(s.dir, func(p string, info fs.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(info.Name(), ".meta_") {
|
||||
bs, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
log.Warn(s.ctx, "s3.by_dir: read meta err, err = %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
nm := new(meta)
|
||||
if err = json.Unmarshal(bs, nm); err != nil {
|
||||
log.Warn(s.ctx, "s3.by_dir: unmarshal meta err, err = %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
if nm.ExpireAt > 0 && time.UnixMilli(nm.ExpireAt).Before(now) {
|
||||
os.Remove(p)
|
||||
base := strings.TrimPrefix(info.Name(), ".meta_")
|
||||
dir := filepath.Dir(p)
|
||||
os.Remove(path.Join(dir, base))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Delete implements S3.
|
||||
func (s *s3_dir) Delete(ctx context.Context, bucket string, key string) error {
|
||||
location := path.Join(s.dir, bucket, key)
|
||||
info, err := os.Stat(location)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return fmt.Errorf("target is dir")
|
||||
}
|
||||
|
||||
os.Remove(path.Join(s.dir, bucket, ".meta_"+key))
|
||||
|
||||
return os.Remove(location)
|
||||
}
|
||||
|
||||
// Get implements S3.
|
||||
func (s *s3_dir) Get(ctx context.Context, bucket string, key string) (*Object, error) {
|
||||
location := path.Join(s.dir, bucket, key)
|
||||
info, err := os.Stat(location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return nil, fmt.Errorf("target is dir")
|
||||
}
|
||||
|
||||
var (
|
||||
f io.ReadCloser
|
||||
bs []byte
|
||||
obj = &Object{}
|
||||
)
|
||||
|
||||
if f, err = os.Open(location); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj.Body = f
|
||||
|
||||
if bs, err = os.ReadFile(path.Join(s.dir, bucket, ".meta_"+key)); err != nil {
|
||||
log.Warn(ctx, "s3.dir: open file meta err, err = %v", err)
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
m := new(meta)
|
||||
if err = json.Unmarshal(bs, m); err != nil {
|
||||
log.Warn(ctx, "s3.dir: unmarshal meta err, err = %v", err)
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
obj.ContentType = m.ContentType
|
||||
obj.Size = m.Size
|
||||
obj.ExpireAt = m.ExpireAt
|
||||
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// Put implements S3.
|
||||
func (s *s3_dir) Put(ctx context.Context, bucket string, key string, obj *Object) error {
|
||||
if bucket != "" {
|
||||
os.MkdirAll(path.Join(s.dir, bucket), 0o755)
|
||||
}
|
||||
|
||||
location := path.Join(s.dir, bucket, key)
|
||||
ml := path.Join(s.dir, bucket, ".meta_"+key)
|
||||
|
||||
bs, err := io.ReadAll(obj.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if obj.Size != 0 && obj.Size != int64(len(bs)) {
|
||||
return fmt.Errorf("object size mismatch")
|
||||
}
|
||||
|
||||
obj.Size = int64(len(bs))
|
||||
|
||||
if obj.ContentType == "" {
|
||||
obj.ContentType = http.DetectContentType(lo.If(len(bs) >= 128, bs[:128]).Else(bs))
|
||||
}
|
||||
|
||||
if err = os.WriteFile(location, bs, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := &meta{
|
||||
ContentType: obj.ContentType,
|
||||
Size: obj.Size,
|
||||
ExpireAt: obj.ExpireAt,
|
||||
}
|
||||
|
||||
ms, _ := json.Marshal(m)
|
||||
os.WriteFile(ml, ms, 0o644)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newDirClient(ctx context.Context, dir string) (S3, error) {
|
||||
dir = filepath.ToSlash(dir)
|
||||
info, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
if err = os.MkdirAll(dir, 0o755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
return nil, fmt.Errorf("target dir exist but not dir")
|
||||
}
|
||||
|
||||
c := &s3_dir{ctx: ctx, dir: dir}
|
||||
|
||||
// todo: expire files
|
||||
go func() {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case t := <-ticker.C:
|
||||
log.Debug(ctx, "s3.by_dir: start clean up s3 dir @%s", t.Format("2006-01-02T15:04:05"))
|
||||
c.clean()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return c, nil
|
||||
}
|
||||
112
internal/database/s3/by_s3.go
Normal file
112
internal/database/s3/by_s3.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"ultone/internal/log"
|
||||
"ultone/internal/tool"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
)
|
||||
|
||||
type s3_client struct {
|
||||
client *s3.Client
|
||||
}
|
||||
|
||||
// Delete implements S3.
|
||||
func (s *s3_client) Delete(ctx context.Context, bucket string, key string) error {
|
||||
var err error
|
||||
|
||||
if _, err = s.client.DeleteObject(ctx, &s3.DeleteObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(key),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get implements S3.
|
||||
func (s *s3_client) Get(ctx context.Context, bucket string, key string) (*Object, error) {
|
||||
var (
|
||||
err error
|
||||
res *s3.GetObjectOutput
|
||||
)
|
||||
|
||||
if res, err = s.client.GetObject(ctx, &s3.GetObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(key),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Object{
|
||||
ContentType: *res.ContentType,
|
||||
Body: res.Body,
|
||||
ExpireAt: res.Expires.UnixMilli(),
|
||||
Size: *res.ContentLength,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Put implements S3.
|
||||
func (s *s3_client) Put(ctx context.Context, bucket string, key string, obj *Object) error {
|
||||
var err error
|
||||
|
||||
if _, err = s.client.PutObject(ctx, &s3.PutObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(key),
|
||||
ACL: types.ObjectCannedACLPublicRead,
|
||||
Body: obj.Body,
|
||||
ContentType: aws.String(obj.ContentType),
|
||||
Expires: aws.Time(time.UnixMilli(obj.ExpireAt)),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newS3Client(ctx context.Context, endpoint, access, key string) (S3, error) {
|
||||
var (
|
||||
err error
|
||||
sdkConfig aws.Config
|
||||
output *s3.ListBucketsOutput
|
||||
)
|
||||
|
||||
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
|
||||
return aws.Endpoint{
|
||||
URL: endpoint,
|
||||
}, nil
|
||||
})
|
||||
|
||||
if sdkConfig, err = config.LoadDefaultConfig(
|
||||
ctx,
|
||||
config.WithEndpointResolverWithOptions(customResolver),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s3Client := s3.NewFromConfig(sdkConfig, func(o *s3.Options) {
|
||||
// o.BaseEndpoint = aws.String(endpoint)
|
||||
// o.EndpointResolverV2 = &resolverV2{}
|
||||
o.Credentials = aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(access, key, ""))
|
||||
o.UsePathStyle = true
|
||||
o.Region = "auto"
|
||||
})
|
||||
|
||||
if output, err = s3Client.ListBuckets(tool.Timeout(5), &s3.ListBucketsInput{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, item := range output.Buckets {
|
||||
log.Debug(ctx, "s3.New: list bucket name = %s", *item.Name)
|
||||
}
|
||||
|
||||
return &s3_client{client: s3Client}, nil
|
||||
}
|
||||
35
internal/database/s3/new.go
Normal file
35
internal/database/s3/new.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
var Default S3
|
||||
|
||||
func New(ctx context.Context, uri string) (S3, error) {
|
||||
ins, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch ins.Scheme {
|
||||
case "http", "https":
|
||||
if ins.User == nil {
|
||||
return nil, fmt.Errorf("missing access or key")
|
||||
}
|
||||
access := ins.User.Username()
|
||||
key, _ := ins.User.Password()
|
||||
return newS3Client(ctx, fmt.Sprintf("%s://%s", ins.Scheme, ins.Host), access, key)
|
||||
case "dir":
|
||||
return newDirClient(ctx, ins.Host)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid new s3 uri scheme: %s", ins.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
func Init(ctx context.Context, uri string) (err error) {
|
||||
Default, err = New(ctx, uri)
|
||||
return err
|
||||
}
|
||||
25
internal/database/s3/s3.go
Normal file
25
internal/database/s3/s3.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
type meta struct {
|
||||
ContentType string `json:"content_type"`
|
||||
Size int64 `json:"size"`
|
||||
ExpireAt int64 `json:"expire_at"`
|
||||
}
|
||||
|
||||
type Object struct {
|
||||
ContentType string
|
||||
Body io.ReadCloser
|
||||
Size int64
|
||||
ExpireAt int64
|
||||
}
|
||||
|
||||
type S3 interface {
|
||||
Get(ctx context.Context, bucket, key string) (*Object, error)
|
||||
Put(ctx context.Context, bucket, key string, obj *Object) error
|
||||
Delete(ctx context.Context, bucket, key string) error
|
||||
}
|
||||
@@ -50,11 +50,11 @@ func LogList(c *nf.Ctx) error {
|
||||
return resp.Resp400(c, req, "参数过大")
|
||||
}
|
||||
|
||||
txCount := op.Role.Where(db.New(tool.Timeout(3)).
|
||||
txCount := op.Role.Where(db.Default.Session(tool.Timeout(3)).
|
||||
Model(&model.OpLog{}).
|
||||
Select("COUNT(`op_logs`.`id`)").
|
||||
Joins("LEFT JOIN users ON `users`.`id` = `op_logs`.`user_id`"))
|
||||
txGet := op.Role.Where(db.New(tool.Timeout(10)).
|
||||
txGet := op.Role.Where(db.Default.Session(tool.Timeout(10)).
|
||||
Model(&model.OpLog{}).
|
||||
Joins("LEFT JOIN users ON `users`.`id` = `op_logs`.`user_id`"))
|
||||
|
||||
|
||||
@@ -3,20 +3,24 @@ package handler
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/loveuer/nf"
|
||||
"github.com/loveuer/nf/nft/resp"
|
||||
"github.com/samber/lo"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"ultone/internal/controller"
|
||||
"ultone/internal/database/cache"
|
||||
"ultone/internal/database/db"
|
||||
"ultone/internal/log"
|
||||
"ultone/internal/middleware/oplog"
|
||||
"ultone/internal/model"
|
||||
"ultone/internal/opt"
|
||||
"ultone/internal/sqlType"
|
||||
"ultone/internal/tool"
|
||||
|
||||
"github.com/loveuer/nf"
|
||||
"github.com/loveuer/nf/nft/resp"
|
||||
"github.com/samber/lo"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
func AuthLogin(c *nf.Ctx) error {
|
||||
@@ -37,7 +41,7 @@ func AuthLogin(c *nf.Ctx) error {
|
||||
return resp.Resp400(c, err.Error())
|
||||
}
|
||||
|
||||
if err = db.New(tool.Timeout(3)).
|
||||
if err = db.Default.Session(tool.Timeout(3)).
|
||||
Model(&model.User{}).
|
||||
Where("username = ?", req.Username).
|
||||
Where("deleted_at = 0").
|
||||
@@ -72,19 +76,27 @@ func AuthLogin(c *nf.Ctx) error {
|
||||
|
||||
if !opt.MultiLogin {
|
||||
var (
|
||||
last = fmt.Sprintf("%s:user:last_token:%d", opt.CachePrefix, target.Id)
|
||||
bs []byte
|
||||
lastKey = fmt.Sprintf("%s:user:last_token:%d", opt.CachePrefix, target.Id)
|
||||
lastToken string
|
||||
)
|
||||
|
||||
if bs, err = cache.Client.Get(tool.Timeout(3), last); err == nil {
|
||||
key := fmt.Sprintf("%s:user:token:%s", opt.CachePrefix, string(bs))
|
||||
_ = cache.Client.Del(tool.Timeout(3), key)
|
||||
// 获取之前的 token
|
||||
if err = cache.Client.GetScan(tool.Timeout(3), lastKey).Scan(&lastToken); err != nil {
|
||||
if !errors.Is(err, cache.ErrorKeyNotFound) {
|
||||
log.Warn(c.Context(), "handler.AuthLogin: get last token err = %v", err)
|
||||
goto HandleMultiEnd
|
||||
}
|
||||
}
|
||||
|
||||
if err = cache.Client.Set(tool.Timeout(3), last, token); err != nil {
|
||||
// 删掉之前的 token
|
||||
controller.UserController.RmToken(c.Context(), lastToken)
|
||||
|
||||
// 将当前的 token 存入 last_token
|
||||
if err = cache.Client.Set(tool.Timeout(3), lastKey, token); err != nil {
|
||||
return resp.Resp500(c, err.Error())
|
||||
}
|
||||
}
|
||||
HandleMultiEnd:
|
||||
|
||||
c.Set("Set-Cookie", fmt.Sprintf("%s=%s; Path=/", opt.CookieName, token))
|
||||
c.Locals("user", target)
|
||||
@@ -111,12 +123,28 @@ func AuthVerify(c *nf.Ctx) error {
|
||||
}
|
||||
|
||||
func AuthLogout(c *nf.Ctx) error {
|
||||
defer func() {
|
||||
c.Set("Set-Cookie", fmt.Sprintf("%s=; Path=/; Max-Age=0", opt.CookieName))
|
||||
}()
|
||||
|
||||
op, ok := c.Locals("user").(*model.User)
|
||||
if !ok {
|
||||
return resp.Resp401(c, nil)
|
||||
}
|
||||
|
||||
_ = controller.UserController.RmUserCache(c.Context(), op.Id)
|
||||
token, ok := c.Locals("token").(string)
|
||||
if !ok {
|
||||
return resp.Resp401(c, nil)
|
||||
}
|
||||
|
||||
if !opt.MultiLogin {
|
||||
_ = controller.UserController.RmUserCache(c.Context(), op.Id)
|
||||
lastKey := fmt.Sprintf("%s:user:last_token:%d", opt.CachePrefix, op.Id)
|
||||
cache.Client.Del(c.Context(), lastKey)
|
||||
}
|
||||
|
||||
// 删掉之前的 token
|
||||
controller.UserController.RmToken(c.Context(), token)
|
||||
|
||||
c.Locals(opt.OpLogLocalKey, &oplog.OpLog{
|
||||
Type: model.OpLogTypeLogout,
|
||||
@@ -129,6 +157,86 @@ func AuthLogout(c *nf.Ctx) error {
|
||||
return resp.Resp200(c, nil)
|
||||
}
|
||||
|
||||
func UserUpdate(c *nf.Ctx) error {
|
||||
type Req struct {
|
||||
OldPassword string `json:"old_password"`
|
||||
NewPassword string `json:"new_password"`
|
||||
Nickname string `json:"nickname"`
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
Password string `gorm:"column:password"`
|
||||
}
|
||||
|
||||
var (
|
||||
ok bool
|
||||
err error
|
||||
req = new(Req)
|
||||
user *model.User
|
||||
m = new(Model)
|
||||
updates = make(map[string]any)
|
||||
changes = make(map[string]any)
|
||||
)
|
||||
|
||||
if user, ok = c.Locals("user").(*model.User); !ok {
|
||||
return resp.Resp401(c, nil)
|
||||
}
|
||||
|
||||
if err = c.BodyParser(req); err != nil {
|
||||
return resp.Resp400(c, err)
|
||||
}
|
||||
|
||||
if err = c.BodyParser(&changes); err != nil {
|
||||
return resp.Resp400(c, err)
|
||||
}
|
||||
|
||||
if _, ok = changes["nickname"]; ok {
|
||||
updates["nickname"] = req.Nickname
|
||||
}
|
||||
|
||||
if req.OldPassword != "" && req.NewPassword != "" {
|
||||
if err = tool.CheckPassword(req.NewPassword); err != nil {
|
||||
return resp.Resp400(c, req, err.Error())
|
||||
}
|
||||
|
||||
if err = db.Default.Session(tool.Timeout(3)).
|
||||
Select("password").
|
||||
Model(&model.User{}).
|
||||
Where("username = ?", user.Username).
|
||||
Where("deleted_at = 0").
|
||||
Take(m).
|
||||
Error; err != nil {
|
||||
return resp.Resp500(c, err.Error())
|
||||
}
|
||||
|
||||
if !tool.ComparePassword(req.OldPassword, m.Password) {
|
||||
return resp.Resp400(c, nil, "原密码错误")
|
||||
}
|
||||
|
||||
updates["password"] = tool.NewPassword(req.NewPassword)
|
||||
}
|
||||
|
||||
if len(updates) == 0 {
|
||||
return resp.Resp400(c, nf.Map{"req": req, "reason": "nothing to update"}, "没有需要更新的内容")
|
||||
}
|
||||
|
||||
if err = db.Default.Session(tool.Timeout(5)).
|
||||
Model(&model.User{}).
|
||||
Where("id = ?", user.Id).
|
||||
Updates(updates).
|
||||
Error; err != nil {
|
||||
return resp.Resp500(c, err.Error())
|
||||
}
|
||||
|
||||
if _, ok = updates["password"]; ok {
|
||||
_ = controller.UserController.RmUserCache(c.Context(), user.Id)
|
||||
c.SetHeader("Set-Cookie", fmt.Sprintf("%s=;Path=/", opt.CookieName))
|
||||
return c.Redirect(opt.LoginURL, http.StatusFound)
|
||||
}
|
||||
|
||||
return resp.Resp200(c, nil, "修改成功")
|
||||
}
|
||||
|
||||
func ManageUserList(c *nf.Ctx) error {
|
||||
type Req struct {
|
||||
Page int `query:"page"`
|
||||
@@ -161,10 +269,10 @@ func ManageUserList(c *nf.Ctx) error {
|
||||
return resp.Resp400(c, nf.Map{"msg": "size over max", "max": opt.MaxSize})
|
||||
}
|
||||
|
||||
txList := op.Role.Where(db.New(tool.Timeout(10)).
|
||||
txList := op.Role.Where(db.Default.Session(tool.Timeout(10)).
|
||||
Model(&model.User{}).
|
||||
Where("deleted_at = 0"))
|
||||
txCount := op.Role.Where(db.New(tool.Timeout(5)).
|
||||
txCount := op.Role.Where(db.Default.Session(tool.Timeout(5)).
|
||||
Model(&model.User{}).
|
||||
Select("COUNT(id)").
|
||||
Where("deleted_at = 0"))
|
||||
@@ -274,7 +382,7 @@ func ManageUserCreate(c *nf.Ctx) error {
|
||||
return resp.Resp403(c, newUser, "角色不符合")
|
||||
}
|
||||
|
||||
if err = db.New(tool.Timeout(5)).
|
||||
if err = db.Default.Session(tool.Timeout(5)).
|
||||
Create(newUser).
|
||||
Error; err != nil {
|
||||
return resp.Resp500(c, err.Error())
|
||||
@@ -423,7 +531,7 @@ func ManageUserUpdate(c *nf.Ctx) error {
|
||||
}
|
||||
|
||||
updated := new(model.User)
|
||||
if err = db.New(tool.Timeout(5)).
|
||||
if err = db.Default.Session(tool.Timeout(5)).
|
||||
Model(updated).
|
||||
Clauses(clause.Returning{}).
|
||||
Where("id = ?", req.Id).
|
||||
@@ -482,7 +590,7 @@ func ManageUserDelete(c *nf.Ctx) error {
|
||||
return resp.Resp403(c, nil)
|
||||
}
|
||||
|
||||
if err = controller.UserController.DeleteUser(c.Context(), target.Id); err != nil {
|
||||
if err = controller.UserController.DeleteUser(c.Context(), target); err != nil {
|
||||
return resp.RespError(c, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package interfaces
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cacher interface {
|
||||
Get(ctx context.Context, key string) ([]byte, error)
|
||||
GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error)
|
||||
// Set value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
|
||||
Set(ctx context.Context, key string, value any) error
|
||||
// SetEx value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
|
||||
SetEx(ctx context.Context, key string, value any, duration time.Duration) error
|
||||
Del(ctx context.Context, keys ...string) error
|
||||
}
|
||||
@@ -5,3 +5,10 @@ type OpLogger interface {
|
||||
Render(content map[string]any) (string, error)
|
||||
Template() string
|
||||
}
|
||||
|
||||
type Logger interface {
|
||||
Debug(msg string, data ...any)
|
||||
Info(msg string, data ...any)
|
||||
Warn(msg string, data ...any)
|
||||
Error(msg string, data ...any)
|
||||
}
|
||||
|
||||
@@ -2,16 +2,18 @@ package invoke
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"ultone/internal/tool"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"sync"
|
||||
"time"
|
||||
"ultone/internal/tool"
|
||||
)
|
||||
|
||||
const (
|
||||
SCHEME = "sonar"
|
||||
SCHEME = "ult"
|
||||
)
|
||||
|
||||
type Client[T any] struct {
|
||||
@@ -27,9 +29,7 @@ func (c *Client[T]) Session() T {
|
||||
return c.fn(c.cc)
|
||||
}
|
||||
|
||||
var (
|
||||
clients = &sync.Map{}
|
||||
)
|
||||
var clients = &sync.Map{}
|
||||
|
||||
// NewClient
|
||||
/*
|
||||
@@ -44,7 +44,6 @@ func NewClient[T any](
|
||||
fn func(grpc.ClientConnInterface) T,
|
||||
opts ...grpc.DialOption,
|
||||
) (*Client[T], error) {
|
||||
|
||||
cached, ok := clients.Load(domain)
|
||||
if ok {
|
||||
if client, ok := cached.(*Client[T]); ok {
|
||||
@@ -68,6 +67,7 @@ func NewClient[T any](
|
||||
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
|
||||
grpc.WithChainUnaryInterceptor(retryInterceptor(3, 3*time.Second)),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithAuthority(SCHEME),
|
||||
)
|
||||
|
||||
conn, err := grpc.DialContext(
|
||||
@@ -75,7 +75,6 @@ func NewClient[T any](
|
||||
fullAddress,
|
||||
opts...,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package invoke
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc/resolver"
|
||||
@@ -30,7 +29,6 @@ type Resolver struct {
|
||||
}
|
||||
|
||||
func (r *Resolver) ResolveNow(o resolver.ResolveNowOptions) {
|
||||
logrus.Tracef("resolve_v2 ResolveNow => target: %s, %v", r.target.URL.Host, ips)
|
||||
_ = r.cc.UpdateState(ips[r.target.URL.Host])
|
||||
}
|
||||
|
||||
|
||||
129
internal/middleware/cache/cache.go
vendored
Normal file
129
internal/middleware/cache/cache.go
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/loveuer/nf"
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
"ultone/internal/database/cache"
|
||||
"ultone/internal/model"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultKeyFn = func(c *nf.Ctx) string {
|
||||
return c.Request.URL.String()
|
||||
}
|
||||
defaultTimeout = 3600
|
||||
defaultPrefix = "midd:cache"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// if return "" (won't cache)
|
||||
KeyFn func(c *nf.Ctx) string
|
||||
|
||||
// cache timeout(seconds)
|
||||
Timeout int
|
||||
|
||||
Prefix string
|
||||
Refresh bool
|
||||
}
|
||||
|
||||
type store struct {
|
||||
Body []byte `json:"body"`
|
||||
Header http.Header `json:"header"`
|
||||
When int64 `json:"when"`
|
||||
}
|
||||
|
||||
func New(cfgs ...Config) nf.HandlerFunc {
|
||||
if cache.Client == nil {
|
||||
log.Panic("[middleware.cache] database cache client is nil")
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
if len(cfgs) > 0 {
|
||||
cfg = cfgs[0]
|
||||
}
|
||||
|
||||
if cfg.KeyFn == nil {
|
||||
cfg.KeyFn = defaultKeyFn
|
||||
}
|
||||
|
||||
if cfg.Timeout <= 0 {
|
||||
cfg.Timeout = defaultTimeout
|
||||
}
|
||||
|
||||
if cfg.Prefix == "" {
|
||||
cfg.Prefix = defaultPrefix
|
||||
}
|
||||
|
||||
return func(c *nf.Ctx) error {
|
||||
var (
|
||||
key string
|
||||
err error
|
||||
bs []byte
|
||||
res = new(store)
|
||||
)
|
||||
|
||||
if key = cfg.KeyFn(c); key == "" {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
key = cfg.Prefix + ":" + key
|
||||
duration := time.Duration(cfg.Timeout) * time.Second
|
||||
|
||||
if cfg.Refresh {
|
||||
if bs, err = cache.Client.GetEx(c.Context(), key, duration); err != nil {
|
||||
if !errors.Is(err, cache.ErrorKeyNotFound) {
|
||||
log.Warn("[middleware.cache] cache get err: %s", err.Error())
|
||||
}
|
||||
goto FromNext
|
||||
}
|
||||
} else {
|
||||
if bs, err = cache.Client.Get(c.Context(), key); err != nil {
|
||||
if !errors.Is(err, cache.ErrorKeyNotFound) {
|
||||
log.Warn("[middleware.cache] cache get err: %s", err.Error())
|
||||
}
|
||||
goto FromNext
|
||||
}
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(bs, res); err != nil {
|
||||
log.Warn("[middleware.cache] cache data unamrshal err: %s", err.Error())
|
||||
goto FromNext
|
||||
}
|
||||
|
||||
for key := range res.Header {
|
||||
for idx := range res.Header[key] {
|
||||
c.SetHeader(key, res.Header[key][idx])
|
||||
}
|
||||
}
|
||||
|
||||
c.SetHeader("X-Nf-Cache-At", strconv.Itoa(int(res.When)))
|
||||
|
||||
_, err = c.Write(res.Body)
|
||||
return err
|
||||
|
||||
FromNext:
|
||||
|
||||
blw := &model.CustomResponseWriter{Body: bytes.NewBuffer(make([]byte, 0, 256)), ResponseWriter: c.Writer}
|
||||
c.Writer = blw
|
||||
|
||||
rerr := c.Next()
|
||||
|
||||
resp, _ := io.ReadAll(blw.Body)
|
||||
|
||||
data := &store{Body: resp, Header: blw.Header().Clone(), When: time.Now().UnixMilli()}
|
||||
cbs, _ := json.Marshal(data)
|
||||
|
||||
if err = cache.Client.SetEx(c.Context(), key, cbs, duration); err != nil {
|
||||
log.Warn("[middleware.cache] cache client setex err: %s", err.Error())
|
||||
}
|
||||
|
||||
return rerr
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/loveuer/nf/nft/resp"
|
||||
"strconv"
|
||||
"time"
|
||||
"ultone/internal/opt"
|
||||
"ultone/internal/tool"
|
||||
)
|
||||
|
||||
@@ -24,7 +25,8 @@ func New() nf.HandlerFunc {
|
||||
|
||||
err := c.Next()
|
||||
|
||||
c.Writer.Header().Add(nf.TraceKey, fmt.Sprint(traceId))
|
||||
c.Writer.Header().Set(nf.TraceKey, fmt.Sprint(traceId))
|
||||
c.Writer.Header().Add("X-NF-Module", opt.Cfg.Name)
|
||||
|
||||
status, _ := strconv.Atoi(c.Writer.Header().Get(resp.RealStatusHeader))
|
||||
duration := time.Since(now)
|
||||
|
||||
@@ -45,7 +45,7 @@ func NewOpLog(ctx context.Context) nf.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if err = db.New(tool.Timeout(10)).
|
||||
if err = db.Default.Session(tool.Timeout(10)).
|
||||
Model(&model.OpLog{}).
|
||||
Create(&list).
|
||||
Error; err != nil {
|
||||
|
||||
27
internal/model/es.go
Normal file
27
internal/model/es.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package model
|
||||
|
||||
type ESSource[T any] struct {
|
||||
DocId string `json:"_id"`
|
||||
Index string `json:"_index"`
|
||||
Content T `json:"_source"`
|
||||
Sort []any `json:"sort"`
|
||||
}
|
||||
|
||||
type ESSearchResponse[T any] struct {
|
||||
Took int `json:"took"`
|
||||
TimedOut bool `json:"timed_out"`
|
||||
Shards struct {
|
||||
Total int `json:"total"`
|
||||
Successful int `json:"successful"`
|
||||
Skipped int `json:"skipped"`
|
||||
Failed int `json:"failed"`
|
||||
} `json:"_shards"`
|
||||
Hits struct {
|
||||
Total struct {
|
||||
Value int `json:"value"`
|
||||
Relation string `json:"relation"`
|
||||
} `json:"total"`
|
||||
MaxScore float64 `json:"max_score"`
|
||||
Hits []*ESSource[T] `json:"hits"`
|
||||
} `json:"hits"`
|
||||
}
|
||||
@@ -288,7 +288,7 @@ type OpLog struct {
|
||||
|
||||
UserId uint64 `json:"user_id" gorm:"column:user_id"`
|
||||
Username string `json:"username" gorm:"column:username;varchar(128)"`
|
||||
Type OpLogType `json:"type" gorm:"column:type;type:varchar(128)"`
|
||||
Type OpLogType `json:"type" gorm:"column:type"`
|
||||
Content sqlType.JSONB `json:"content" gorm:"column:content;type:jsonb"`
|
||||
HTML string `json:"html" gorm:"-"`
|
||||
}
|
||||
|
||||
21
internal/model/writer.go
Normal file
21
internal/model/writer.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/loveuer/nf"
|
||||
)
|
||||
|
||||
type CustomResponseWriter struct {
|
||||
nf.ResponseWriter
|
||||
Body *bytes.Buffer
|
||||
}
|
||||
|
||||
func (w CustomResponseWriter) Write(b []byte) (int, error) {
|
||||
w.Body.Write(b)
|
||||
return w.ResponseWriter.Write(b)
|
||||
}
|
||||
|
||||
func (w CustomResponseWriter) WriteString(s string) (int, error) {
|
||||
w.Body.WriteString(s)
|
||||
return w.ResponseWriter.WriteString(s)
|
||||
}
|
||||
@@ -1,75 +1,69 @@
|
||||
package opt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
"os"
|
||||
"github.com/spf13/viper"
|
||||
"ultone/internal/tool"
|
||||
)
|
||||
|
||||
type listen struct {
|
||||
Http string `json:"http"`
|
||||
Grpc string `json:"grpc"`
|
||||
Unix string `json:"unix"`
|
||||
Http string `mapstructure:"http"`
|
||||
Grpc string `mapstructure:"grpc"`
|
||||
}
|
||||
|
||||
type db struct {
|
||||
Type string `json:"-"` // postgres, mysql, sqlite
|
||||
Uri string `json:"uri"`
|
||||
Type string `mapstructure:"-"` // postgres, mysql, sqlite
|
||||
Uri string `mapstructure:"uri"`
|
||||
}
|
||||
|
||||
type cache struct {
|
||||
Uri string `json:"uri"`
|
||||
Uri string `mapstructure:"uri"`
|
||||
}
|
||||
|
||||
type es struct {
|
||||
Uri string `json:"uri"`
|
||||
Uri string `mapstructure:"uri"`
|
||||
Index struct {
|
||||
Staff string `json:"staff"`
|
||||
} `json:"index"`
|
||||
Staff string `mapstructure:"staff"`
|
||||
} `mapstructure:"index"`
|
||||
}
|
||||
|
||||
type Nebula struct {
|
||||
Uri string `json:"uri"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Space string `json:"space"`
|
||||
Uri string `mapstructure:"uri"`
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
Space string `mapstructure:"space"`
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Name string `json:"name"`
|
||||
Listen listen `json:"listen"`
|
||||
DB db `json:"db"`
|
||||
Cache cache `json:"cache"`
|
||||
ES es `json:"es"`
|
||||
Nebula Nebula `json:"nebula"`
|
||||
Name string `mapstructure:"name"`
|
||||
Debug bool `mapstructure:"-"`
|
||||
Listen listen `mapstructure:"listen"`
|
||||
DB db `mapstructure:"db"`
|
||||
Cache cache `mapstructure:"cache"`
|
||||
ES es `mapstructure:"es"`
|
||||
Nebula Nebula `mapstructure:"nebula"`
|
||||
}
|
||||
|
||||
var (
|
||||
Debug bool
|
||||
Cfg = &config{}
|
||||
Cfg = &config{}
|
||||
)
|
||||
|
||||
func Init(filename string) error {
|
||||
|
||||
var (
|
||||
err error
|
||||
bs []byte
|
||||
)
|
||||
|
||||
log.Info("opt.Init: start reading config file: %s", filename)
|
||||
|
||||
if bs, err = os.ReadFile(filename); err != nil {
|
||||
return fmt.Errorf("opt.Init: read config file=%s err=%v", filename, err)
|
||||
viper.SetConfigFile(filename)
|
||||
if err = viper.ReadInConfig(); err != nil {
|
||||
return fmt.Errorf("opt.Init: readin config failed, err = %s", err.Error())
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(bs, Cfg); err != nil {
|
||||
return fmt.Errorf("opt.Init: json marshal config=%s err=%v", string(bs), err)
|
||||
}
|
||||
|
||||
if Debug {
|
||||
log.SetLogLevel(log.LogLevelDebug)
|
||||
if err = viper.Unmarshal(Cfg); err != nil {
|
||||
return fmt.Errorf("opt.Init: unmarshal config failed, err = %s", err.Error())
|
||||
}
|
||||
|
||||
tool.TablePrinter(Cfg)
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package opt
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
RpcAddress = "tcp://127.0.0.1:8081" // unix:///tmp/xxx.sock
|
||||
// todo: 可以替换自己生生成的 secret
|
||||
JwtTokenSecret = "7^D+UW3BPB2Mnz)bY3uVrAUyv&dj8Kdz"
|
||||
|
||||
@@ -37,9 +41,15 @@ const (
|
||||
OpLogWriteDurationSecond = 5
|
||||
|
||||
LocalTraceKey = "X-Trace-Id"
|
||||
|
||||
LoginURL = "/login"
|
||||
)
|
||||
|
||||
var (
|
||||
Locker = &sync.Mutex{}
|
||||
// todo: 颁发的 token, (cookie) 在缓存中存在的时间 (每次请求该时间也会被刷新)
|
||||
TokenTimeout = time.Duration(3600*12) * time.Second
|
||||
|
||||
Start = time.Now()
|
||||
OK bool
|
||||
)
|
||||
|
||||
@@ -22,3 +22,29 @@ func HumanDuration(nano int64) string {
|
||||
|
||||
return fmt.Sprintf("%6.2f%s", duration, unit)
|
||||
}
|
||||
|
||||
func HumanSize(size int64) string {
|
||||
const (
|
||||
_ = iota
|
||||
KB = 1 << (10 * iota) // 1 KB = 1024 bytes
|
||||
MB // 1 MB = 1024 KB
|
||||
GB // 1 GB = 1024 MB
|
||||
TB // 1 TB = 1024 GB
|
||||
PB // 1 PB = 1024 TB
|
||||
)
|
||||
|
||||
switch {
|
||||
case size >= PB:
|
||||
return fmt.Sprintf("%.2f PB", float64(size)/PB)
|
||||
case size >= TB:
|
||||
return fmt.Sprintf("%.2f TB", float64(size)/TB)
|
||||
case size >= GB:
|
||||
return fmt.Sprintf("%.2f GB", float64(size)/GB)
|
||||
case size >= MB:
|
||||
return fmt.Sprintf("%.2f MB", float64(size)/MB)
|
||||
case size >= KB:
|
||||
return fmt.Sprintf("%.2f KB", float64(size)/KB)
|
||||
default:
|
||||
return fmt.Sprintf("%d bytes", size)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package tool
|
||||
|
||||
import "cmp"
|
||||
|
||||
func Min[T cmp.Ordered](a, b T) T {
|
||||
func Min[T ~int | ~uint | ~int8 | ~uint8 | ~int16 | ~uint16 | ~int32 | ~uint32 | ~int64 | ~uint64 | ~float32 | ~float64](a, b T) T {
|
||||
if a <= b {
|
||||
return a
|
||||
}
|
||||
@@ -10,7 +8,7 @@ func Min[T cmp.Ordered](a, b T) T {
|
||||
return b
|
||||
}
|
||||
|
||||
func Max[T cmp.Ordered](a, b T) T {
|
||||
func Max[T ~int | ~uint | ~int8 | ~uint8 | ~int16 | ~uint16 | ~int32 | ~uint32 | ~int64 | ~uint64 | ~float32 | ~float64](a, b T) T {
|
||||
if a >= b {
|
||||
return a
|
||||
}
|
||||
|
||||
56
internal/unix/handler.go
Normal file
56
internal/unix/handler.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package unix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
"ultone/internal/log"
|
||||
"ultone/internal/opt"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
type AvailableReq struct{}
|
||||
type AvailableResp struct {
|
||||
OK bool
|
||||
Now time.Time
|
||||
Start time.Time
|
||||
Duration string
|
||||
}
|
||||
|
||||
func (*Handler) Available(_ *AvailableReq, out *AvailableResp) error {
|
||||
now := time.Now()
|
||||
out.OK, out.Now = opt.OK, now
|
||||
out.Start = opt.Start
|
||||
out.Duration = fmt.Sprint(now.Sub(opt.Start))
|
||||
return nil
|
||||
}
|
||||
|
||||
type SettingReq struct {
|
||||
Debug bool
|
||||
}
|
||||
type Resp[T any] struct {
|
||||
Status uint32
|
||||
Msg string
|
||||
Data T
|
||||
}
|
||||
|
||||
func (h *Handler) Setting(in *SettingReq, out *Resp[bool]) error {
|
||||
opt.Locker.Lock()
|
||||
defer opt.Locker.Unlock()
|
||||
|
||||
if in.Debug {
|
||||
opt.Cfg.Debug = true
|
||||
log.Info(h.Ctx, "set global debug[true]")
|
||||
} else {
|
||||
opt.Cfg.Debug = false
|
||||
log.Info(h.Ctx, "set global debug[false]")
|
||||
}
|
||||
|
||||
out.Status = 200
|
||||
out.Msg = "操作成功"
|
||||
|
||||
return nil
|
||||
}
|
||||
51
internal/unix/start.go
Normal file
51
internal/unix/start.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package unix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/rpc"
|
||||
"net/url"
|
||||
"ultone/internal/log"
|
||||
"ultone/internal/opt"
|
||||
)
|
||||
|
||||
func Start(ctx context.Context) error {
|
||||
ready := make(chan bool)
|
||||
defer close(ready)
|
||||
|
||||
uri, err := url.Parse(opt.RpcAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
address := uri.Host + uri.Path
|
||||
log.Debug(ctx, "[rpc-svc] listen at [%s] [%s]", uri.Scheme, address)
|
||||
|
||||
ln, err := net.Listen(uri.Scheme, address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
ready <- true
|
||||
<-ctx.Done()
|
||||
_ = ln.Close()
|
||||
}()
|
||||
|
||||
<-ready
|
||||
|
||||
svc := rpc.NewServer()
|
||||
if err = svc.RegisterName("svc", &Handler{Ctx: ctx}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Info(ctx, "[rpc-svc] start at: [%s] [%s]", uri.Scheme, address)
|
||||
ready <- true
|
||||
svc.Accept(ln)
|
||||
}()
|
||||
|
||||
<-ready
|
||||
|
||||
return nil
|
||||
}
|
||||
8
main.go
8
main.go
@@ -2,11 +2,12 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"ultone/internal/cmd"
|
||||
"ultone/internal/tool"
|
||||
|
||||
"github.com/loveuer/nf/nft/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -16,7 +17,4 @@ func main() {
|
||||
if err := cmd.Execute(ctx); err != nil {
|
||||
log.Error("cmd.Execute: err=%v", err)
|
||||
}
|
||||
|
||||
log.Warn("received quit signal...(2s)")
|
||||
<-tool.Timeout(2).Done()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user