init
This commit is contained in:
parent
19999919d2
commit
39ec698bef
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build
|
||||||
|
config.yaml
|
97
.gitea_old/workflows/build.yaml
Normal file
97
.gitea_old/workflows/build.yaml
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- id: commit
|
||||||
|
uses: prompt/actions-commit-hash@v3
|
||||||
|
- name: Setup go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: '^1.22'
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go env -w GO111MODULE=on && go env -w GOPROXY=https://goproxy.cn,direct
|
||||||
|
go mod download
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
CGO_ENABLED=0 go build -ldflags "-w -s" -gcflags "-N -l" -o main .
|
||||||
|
- name: 'Login to Container Registry'
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: leafdev.top
|
||||||
|
username: ${{ gitea.actor }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
- name: 'Build Inventory Image'
|
||||||
|
run: |
|
||||||
|
docker build . -f Dockerfile2 --tag leafdev.top/leaf/rag-new:${{ steps.commit.outputs.short }}
|
||||||
|
docker push leafdev.top/leaf/rag-new:${{ steps.commit.outputs.short }}
|
||||||
|
docker tag leafdev.top/leaf/rag-new:${{ steps.commit.outputs.short }} leafdev.top/leaf/rag-new:latest
|
||||||
|
- name: 'Checkout Manifests branch'
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: manifests
|
||||||
|
|
||||||
|
- name: 'Patch API Manifest'
|
||||||
|
uses: fjogeleit/yaml-update-action@main
|
||||||
|
with:
|
||||||
|
valueFile: 'manifests/deployment-api.yaml'
|
||||||
|
propertyPath: 'spec.template.spec.containers[0].image'
|
||||||
|
value: 'leafdev.top/leaf/rag-new:${{ steps.commit.outputs.short }}'
|
||||||
|
commitChange: false
|
||||||
|
- name: 'Patch Schedule Manifest'
|
||||||
|
uses: fjogeleit/yaml-update-action@main
|
||||||
|
with:
|
||||||
|
valueFile: 'manifests/deployment-schedule.yaml'
|
||||||
|
propertyPath: 'spec.template.spec.containers[0].image'
|
||||||
|
value: 'leafdev.top/leaf/rag-new:${{ steps.commit.outputs.short }}'
|
||||||
|
commitChange: false
|
||||||
|
- name: Push
|
||||||
|
run: |
|
||||||
|
git config user.name ${{ gitea.actor }}
|
||||||
|
git config user.email ${{ gitea.actor }}@users.noreply.leafdev.top
|
||||||
|
git add manifests/deployment-api.yaml
|
||||||
|
git add manifests/deployment-schedule.yaml
|
||||||
|
git commit -m "Update manifests"
|
||||||
|
git push origin manifests
|
||||||
|
# - name: docker
|
||||||
|
# run: |
|
||||||
|
# - name: Build Docker Image
|
||||||
|
# run: |
|
||||||
|
# docker build -t ${{ env.REGISTRY }}/${{ steps.meta.outputs.tags }} -f ./docker/nginx/Dockerfile .
|
||||||
|
# - name: Push Docker Image
|
||||||
|
# run: |
|
||||||
|
# docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }} ${{ env.REGISTRY }}
|
||||||
|
# docker push ${{ env.REGISTRY }}/${{ steps.meta.outputs.tags }}
|
||||||
|
# - name: Artifact
|
||||||
|
# uses: christopherhx/gitea-upload-artifact@v4
|
||||||
|
# with:
|
||||||
|
# name: artifact
|
||||||
|
# path: cmd/main
|
||||||
|
# push:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
## needs: [build]
|
||||||
|
# steps:
|
||||||
|
# - uses: https://github.com/actions/checkout@v4
|
||||||
|
# - name: Set up Docker Buildx
|
||||||
|
# uses: https://github.com/docker/setup-buildx-action@v3
|
||||||
|
# with:
|
||||||
|
# config-inline: |
|
||||||
|
# [registry."<my-private-unsecure-git-repository-ip-address>:5000"]
|
||||||
|
# http = true
|
||||||
|
# insecure = true
|
||||||
|
# - name: Build and push Docker image
|
||||||
|
# uses: https://github.com/docker/build-push-action@v5
|
||||||
|
# with:
|
||||||
|
# context: .
|
||||||
|
# file: ./Dockerfile
|
||||||
|
# push: true
|
||||||
|
# tags: "<my-private-unsecure-git-repository-ip-address>:5000/<my-docker-image>:${{gitea.sha}},<my-private-unsecure-git-repository-ip-address>:5000/<my-docker-image>:latest"
|
25
.gitea_old/workflows/deploy.yaml
Normal file
25
.gitea_old/workflows/deploy.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: Deploy
|
||||||
|
|
||||||
|
on: [release]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Set output
|
||||||
|
id: vars
|
||||||
|
run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
|
||||||
|
- name: Check output
|
||||||
|
env:
|
||||||
|
GITHUB_RELEASE_VERSION: ${{ steps.vars.outputs.tag }}
|
||||||
|
run: |
|
||||||
|
# check if GITHUB_RELEASE_VERSION is not empty
|
||||||
|
- name: Deploy
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: leafdev.top/rag-new:latest
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/build
|
||||||
|
/config.yaml
|
||||||
|
.idea
|
||||||
|
.vscode
|
15
Dockerfile
Normal file
15
Dockerfile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# docker build -t registry.leafdev.top/leaf/rag-new:v0.0.1-fix .
|
||||||
|
FROM golang:latest as builder
|
||||||
|
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
RUN go env -w GO111MODULE=on && go env -w GOPROXY=https://goproxy.cn,direct && go mod download
|
||||||
|
RUN CGO_ENABLED=0 go build -ldflags "-w -s" -gcflags "-N -l" -o main .
|
||||||
|
|
||||||
|
# RUN
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /app/main /app/main
|
||||||
|
ENTRYPOINT ["/app/main"]
|
8
Dockerfile2
Normal file
8
Dockerfile2
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# docker build -t registry.leafdev.top/leaf/rag-new:v0.0.1-fix . -f Dockerfile2
|
||||||
|
# RUN
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY ./main /app/main
|
||||||
|
ENTRYPOINT ["/app/main"]
|
22
Makefile
Normal file
22
Makefile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.PHONY: install-deps generate swag gorm proto buf
|
||||||
|
|
||||||
|
install-deps:
|
||||||
|
go install github.com/google/wire/cmd/wire@latest
|
||||||
|
go install github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
go install github.com/pressly/goose/v3/cmd/goose@latest
|
||||||
|
echo "You need install buf manually, https://github.com/bufbuild/buf"
|
||||||
|
|
||||||
|
generate:
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
swag:
|
||||||
|
swag init -g main.go --parseDependency
|
||||||
|
|
||||||
|
gorm:
|
||||||
|
cd hack/gorm-gen && go run .
|
||||||
|
|
||||||
|
buf:
|
||||||
|
buf dep update
|
||||||
|
|
||||||
|
proto:
|
||||||
|
buf generate
|
21
buf.gen.yaml
Normal file
21
buf.gen.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
version: v2
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- remote: buf.build/grpc/go:v1.5.1
|
||||||
|
out: proto/gen
|
||||||
|
opt:
|
||||||
|
- paths=source_relative
|
||||||
|
- remote: buf.build/protocolbuffers/go:v1.34.2
|
||||||
|
out: proto/gen
|
||||||
|
opt:
|
||||||
|
- paths=source_relative
|
||||||
|
- remote: buf.build/grpc-ecosystem/gateway:v2.23.0
|
||||||
|
out: proto/gen
|
||||||
|
opt:
|
||||||
|
- paths=source_relative
|
||||||
|
- generate_unbound_methods=true
|
||||||
|
- remote: buf.build/grpc-ecosystem/openapiv2:v2.23.0
|
||||||
|
out: proto/gen
|
||||||
|
opt:
|
||||||
|
- allow_merge
|
||||||
|
# - merge_file_name=mce-spider
|
96
cmd/grpc.go
Normal file
96
cmd/grpc.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
|
||||||
|
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
"google.golang.org/grpc/reflection"
|
||||||
|
v1 "leafdev.top/Leaf/leaf-library-3/proto/gen/proto/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RootCmd.AddCommand(documentServiceCommand)
|
||||||
|
}
|
||||||
|
|
||||||
|
var documentServiceCommand = &cobra.Command{
|
||||||
|
Use: "grpc",
|
||||||
|
Short: "Start gRPC",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
app, err := CreateApp()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lis, err := net.Listen("tcp", app.Config.Grpc.Address)
|
||||||
|
if err != nil {
|
||||||
|
app.Logger.Sugar.Fatal(err)
|
||||||
|
}
|
||||||
|
var opts = []grpc.ServerOption{
|
||||||
|
grpc.ChainUnaryInterceptor(
|
||||||
|
logging.UnaryServerInterceptor(app.Api.GRPC.Interceptor.Logger.ZapLogInterceptor()),
|
||||||
|
|
||||||
|
app.Api.GRPC.Interceptor.Auth.UnaryJWTAuth(),
|
||||||
|
),
|
||||||
|
grpc.ChainStreamInterceptor(
|
||||||
|
logging.StreamServerInterceptor(app.Api.GRPC.Interceptor.Logger.ZapLogInterceptor()),
|
||||||
|
app.Api.GRPC.Interceptor.Auth.StreamJWTAuth(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
grpcServer := grpc.NewServer(opts...)
|
||||||
|
|
||||||
|
// 注册服务
|
||||||
|
v1.RegisterDocumentServiceServer(grpcServer, app.Api.GRPC.DocumentApi)
|
||||||
|
|
||||||
|
// 反射
|
||||||
|
reflection.Register(grpcServer)
|
||||||
|
|
||||||
|
app.Logger.Sugar.Infof("gRPC listening on %s, http gateway listening on %s",
|
||||||
|
app.Config.Grpc.Address, app.Config.Grpc.AddressGateway)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
if err := grpcServer.Serve(lis); err != nil {
|
||||||
|
app.Logger.Sugar.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var dialOption = []grpc.DialOption{
|
||||||
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
|
}
|
||||||
|
|
||||||
|
mux := runtime.NewServeMux()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// 注册服务到网关并转为 Http 请求
|
||||||
|
err = v1.RegisterDocumentServiceHandlerFromEndpoint(ctx, mux, app.Config.Grpc.Address, dialOption)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
app.Logger.Sugar.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := http.ListenAndServe(app.Config.Grpc.AddressGateway, mux); err != nil {
|
||||||
|
app.Logger.Sugar.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
102
cmd/http.go
Normal file
102
cmd/http.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/adaptor"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RootCmd.AddCommand(httpCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpCmd = &cobra.Command{
|
||||||
|
Use: "http",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
initHttpServer()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func initHttpServer() {
|
||||||
|
app, err := CreateApp()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if app.Config.Http.Host == "" {
|
||||||
|
app.Config.Http.Host = "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
if app.Config.Http.Port == 0 {
|
||||||
|
app.Config.Http.Port = 8000
|
||||||
|
}
|
||||||
|
|
||||||
|
var bizServer *http.Server
|
||||||
|
var metricServer *http.Server
|
||||||
|
|
||||||
|
bizServer = &http.Server{
|
||||||
|
Addr: ":8080",
|
||||||
|
}
|
||||||
|
|
||||||
|
bizServer.Addr = app.Config.Http.Host + ":" + strconv.Itoa(app.Config.Http.Port)
|
||||||
|
bizServer.Handler = adaptor.FiberApp(app.HttpServer.BizRouter())
|
||||||
|
|
||||||
|
// 启动 http
|
||||||
|
go func() {
|
||||||
|
// refresh
|
||||||
|
app.Service.Jwks.SetupAuthRefresh()
|
||||||
|
|
||||||
|
app.Logger.Sugar.Info("Listening and serving HTTP on ", bizServer.Addr)
|
||||||
|
err = bizServer.ListenAndServe()
|
||||||
|
if err != nil && !errors.Is(http.ErrServerClosed, err) {
|
||||||
|
panic(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 启动 metrics
|
||||||
|
if app.Config.Metrics.Enabled {
|
||||||
|
metricServer = &http.Server{
|
||||||
|
Addr: ":8080",
|
||||||
|
}
|
||||||
|
metricServer.Addr = app.Config.Metrics.Host + ":" + strconv.Itoa(app.Config.Metrics.Port)
|
||||||
|
go func() {
|
||||||
|
app.Logger.Sugar.Info("Metrics and serving HTTP on ", metricServer.Addr)
|
||||||
|
|
||||||
|
metricServer.Handler = adaptor.FiberApp(app.HttpServer.MetricRouter())
|
||||||
|
|
||||||
|
err = metricServer.ListenAndServe()
|
||||||
|
if err != nil && !errors.Is(http.ErrServerClosed, err) {
|
||||||
|
panic(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
quit := make(chan os.Signal)
|
||||||
|
|
||||||
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
<-quit
|
||||||
|
|
||||||
|
app.Logger.Sugar.Info("Shutdown http server")
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := bizServer.Shutdown(ctx); err != nil {
|
||||||
|
app.Logger.Sugar.Fatalf("Biz Server Shutdown Error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := metricServer.Shutdown(ctx); err != nil {
|
||||||
|
app.Logger.Sugar.Fatalf("Metric Server Shutdown Error: %s", err)
|
||||||
|
}
|
||||||
|
}
|
158
cmd/migrate.go
Normal file
158
cmd/migrate.go
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/database/migrations"
|
||||||
|
|
||||||
|
"github.com/pressly/goose/v3"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RootCmd.AddCommand(migrateCommand, createGoMigrateCommand)
|
||||||
|
}
|
||||||
|
|
||||||
|
var migrateCommand = &cobra.Command{
|
||||||
|
Use: "goose [command]",
|
||||||
|
Short: "goose <command>",
|
||||||
|
Long: "Run goose",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
_ = cmd.Help()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
RunMigrate(args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var createGoMigrateCommand = &cobra.Command{
|
||||||
|
Use: "create-migrate",
|
||||||
|
Short: "create go migration",
|
||||||
|
Long: "create go migration using goose.",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
_ = cmd.Help()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
createGooseMigration(name)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunMigrate 为数据库函数
|
||||||
|
func RunMigrate(args []string) {
|
||||||
|
app, err := CreateApp()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
migrations.Config = app.Config
|
||||||
|
|
||||||
|
goose.SetBaseFS(migrations.MigrationFS)
|
||||||
|
|
||||||
|
err = goose.SetDialect("postgres")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := app.GORM.DB()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
command := args[0]
|
||||||
|
|
||||||
|
var arguments []string
|
||||||
|
if len(args) > 3 {
|
||||||
|
arguments = append(arguments, args[3:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = goose.RunContext(context.Background(), command, db, ".", arguments...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := db.Close(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func createGooseMigration(name string) {
|
||||||
|
// 在 internal/database/migrations 目录下新建一个迁移文件
|
||||||
|
// 文件名为 yyyy-mm-dd-hh-mm-ss-<name>.go
|
||||||
|
month := int(time.Now().Month())
|
||||||
|
monthString := fmt.Sprintf("%d", month)
|
||||||
|
if month < 10 {
|
||||||
|
// 转 string
|
||||||
|
monthString = "0" + monthString
|
||||||
|
}
|
||||||
|
|
||||||
|
day := time.Now().Day()
|
||||||
|
dayString := fmt.Sprintf("%d", day)
|
||||||
|
if day < 10 {
|
||||||
|
dayString = "0" + dayString
|
||||||
|
}
|
||||||
|
|
||||||
|
hour := time.Now().Hour()
|
||||||
|
hourString := fmt.Sprintf("%d", hour)
|
||||||
|
if hour < 10 {
|
||||||
|
hourString = "0" + hourString
|
||||||
|
}
|
||||||
|
|
||||||
|
minute := time.Now().Minute()
|
||||||
|
minuteString := fmt.Sprintf("%d", minute)
|
||||||
|
if minute < 10 {
|
||||||
|
minuteString = "0" + minuteString
|
||||||
|
}
|
||||||
|
|
||||||
|
// 秒
|
||||||
|
second := time.Now().Second()
|
||||||
|
secondString := fmt.Sprintf("%d", second)
|
||||||
|
if second < 10 {
|
||||||
|
secondString = "0" + secondString
|
||||||
|
}
|
||||||
|
|
||||||
|
funcName := fmt.Sprintf("%d%s%s%s%s%s", time.Now().Year(), monthString, dayString, hourString, minuteString, secondString)
|
||||||
|
fileName := fmt.Sprintf("%s_%s.go", funcName, name)
|
||||||
|
|
||||||
|
// 模板内容
|
||||||
|
var template = `package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"github.com/pressly/goose/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
goose.AddMigrationContext(Up<FuncName>, Down<FuncName>)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Up<FuncName>(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
_, err := tx.ExecContext(ctx, "UPDATE users SET username='admin' WHERE username='root';")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Down<FuncName>(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
_, err := tx.ExecContext(ctx, "UPDATE users SET username='root' WHERE username='admin';")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
template = strings.ReplaceAll(template, "<FuncName>", funcName+name)
|
||||||
|
err := os.WriteFile("internal/database/migrations/"+fileName, []byte(template), 0644)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed creating migration file: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
cmd/root.go
Normal file
14
cmd/root.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import "github.com/spf13/cobra"
|
||||||
|
|
||||||
|
var RootCmd = &cobra.Command{
|
||||||
|
Use: "app",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := cmd.Help()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
39
cmd/schedule.go
Normal file
39
cmd/schedule.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RootCmd.AddCommand(scheduleCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var scheduleCmd = &cobra.Command{
|
||||||
|
Use: "schedule",
|
||||||
|
Short: "Schedule commands",
|
||||||
|
Long: `Schedule commands`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
app, err := CreateApp()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
runSchedule(app)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func runSchedule(app *base.Application) {
|
||||||
|
// var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// var ctx = context.Background()
|
||||||
|
|
||||||
|
// wg.Add(1)
|
||||||
|
// // 启动一个定时器
|
||||||
|
// go func() {
|
||||||
|
|
||||||
|
// }()
|
||||||
|
|
||||||
|
// wg.Wait()
|
||||||
|
}
|
44
cmd/wire.go
Normal file
44
cmd/wire.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
//go:build wireinject
|
||||||
|
// +build wireinject
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/milvus"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/orm"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/redis"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/s3"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/server"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/batch"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/dao"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/router"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service"
|
||||||
|
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ProviderSet = wire.NewSet(
|
||||||
|
conf.NewConfig,
|
||||||
|
logger.NewZapLogger,
|
||||||
|
orm.NewGORM,
|
||||||
|
dao.NewQuery,
|
||||||
|
redis.NewRedis,
|
||||||
|
s3.NewS3,
|
||||||
|
milvus.NewService,
|
||||||
|
batch.NewBatch,
|
||||||
|
service.Provide,
|
||||||
|
api.Provide,
|
||||||
|
router.Provide,
|
||||||
|
server.NewHTTPServer,
|
||||||
|
base.NewApplication,
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateApp() (*base.Application, error) {
|
||||||
|
wire.Build(ProviderSet)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
67
cmd/wire_gen.go
Normal file
67
cmd/wire_gen.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Code generated by Wire. DO NOT EDIT.
|
||||||
|
|
||||||
|
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
|
||||||
|
//go:build !wireinject
|
||||||
|
// +build !wireinject
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/wire"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/grpc"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/grpc/interceptor"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/grpc/v1/documents"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http/v1"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/milvus"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/orm"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/redis"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/s3"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/server"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/batch"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/dao"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/router"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/auth"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/jwks"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/stream"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Injectors from wire.go:
|
||||||
|
|
||||||
|
func CreateApp() (*base.Application, error) {
|
||||||
|
config := conf.NewConfig()
|
||||||
|
loggerLogger := logger.NewZapLogger(config)
|
||||||
|
jwksJWKS := jwks.NewJWKS(config, loggerLogger)
|
||||||
|
authService := auth.NewService(config, jwksJWKS, loggerLogger)
|
||||||
|
userController := v1.NewUserController(authService)
|
||||||
|
handlers := http.NewHandler(userController)
|
||||||
|
middleware := http.NewMiddleware(config, loggerLogger, authService)
|
||||||
|
routerApi := router.NewApiRoute(handlers, middleware)
|
||||||
|
swaggerRouter := router.NewSwaggerRoute()
|
||||||
|
httpServer := server.NewHTTPServer(config, routerApi, swaggerRouter, middleware, loggerLogger)
|
||||||
|
db := orm.NewGORM(config, loggerLogger)
|
||||||
|
query := dao.NewQuery(db)
|
||||||
|
handler := documents.NewHandler(query)
|
||||||
|
interceptorAuth := interceptor.NewAuth(authService, loggerLogger, config)
|
||||||
|
interceptorLogger := interceptor.NewLogger(loggerLogger)
|
||||||
|
grpcInterceptor := grpc.NewInterceptor(interceptorAuth, interceptorLogger)
|
||||||
|
grpcHandlers := grpc.NewHandler(handler, grpcInterceptor)
|
||||||
|
apiApi := api.NewApi(grpcHandlers, handlers)
|
||||||
|
streamService := stream.NewService(config)
|
||||||
|
serviceService := service.NewService(loggerLogger, jwksJWKS, authService, streamService)
|
||||||
|
redisRedis := redis.NewRedis(config)
|
||||||
|
batchBatch := batch.NewBatch(loggerLogger)
|
||||||
|
s3S3 := s3.NewS3(config)
|
||||||
|
client := milvus.NewService(config, loggerLogger)
|
||||||
|
application := base.NewApplication(config, httpServer, apiApi, loggerLogger, serviceService, redisRedis, batchBatch, s3S3, db, query, client)
|
||||||
|
return application, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// wire.go:
|
||||||
|
|
||||||
|
var ProviderSet = wire.NewSet(conf.NewConfig, logger.NewZapLogger, orm.NewGORM, dao.NewQuery, redis.NewRedis, s3.NewS3, milvus.NewService, batch.NewBatch, service.Provide, api.Provide, router.Provide, server.NewHTTPServer, base.NewApplication)
|
9
configs/config.go
Normal file
9
configs/config.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package configs
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed config.yaml
|
||||||
|
var Config []byte
|
||||||
|
|
||||||
|
//go:embed rbac_model.conf
|
||||||
|
var RBACModel []byte
|
90
configs/config.yaml
Normal file
90
configs/config.yaml
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
app:
|
||||||
|
name: template
|
||||||
|
allowed_audiences:
|
||||||
|
- "1" # UserLand Personal Access Client
|
||||||
|
|
||||||
|
http:
|
||||||
|
port: 8080
|
||||||
|
host: 0.0.0.0
|
||||||
|
# the production url
|
||||||
|
url: http://127.0.0.1:8080
|
||||||
|
cors:
|
||||||
|
enabled: true
|
||||||
|
allow_origins:
|
||||||
|
- "http://localhost:8080"
|
||||||
|
allow_methods:
|
||||||
|
- "GET"
|
||||||
|
- "HEAD"
|
||||||
|
- "PUT"
|
||||||
|
- "PATCH"
|
||||||
|
- "POST"
|
||||||
|
- "DELETE"
|
||||||
|
allow_headers:
|
||||||
|
- "Origin"
|
||||||
|
- "Content-Length"
|
||||||
|
- "Content-Type"
|
||||||
|
- "X-Requested-With"
|
||||||
|
- "Authorization"
|
||||||
|
allow_credentials: true
|
||||||
|
expose_headers: [ ]
|
||||||
|
max_age: 720
|
||||||
|
|
||||||
|
grpc:
|
||||||
|
address: 0.0.0.0:9090
|
||||||
|
address_gateway: 0.0.0.0:9091
|
||||||
|
|
||||||
|
debug:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
database:
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: 5432
|
||||||
|
user: root
|
||||||
|
password: root
|
||||||
|
name: db_name
|
||||||
|
sslmode: disable
|
||||||
|
timezone: "Asia/Shanghai"
|
||||||
|
|
||||||
|
redis:
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: 6379
|
||||||
|
password: ""
|
||||||
|
db: 0
|
||||||
|
|
||||||
|
jwks:
|
||||||
|
url: "https://auth.leaflow.cn/.well-known/jwks"
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
port: 8081
|
||||||
|
host: 0.0.0.0
|
||||||
|
|
||||||
|
s3:
|
||||||
|
endpoint: 127.0.0.1:9000
|
||||||
|
external_endpoint: 127.0.0.1:9000
|
||||||
|
access_key: minio
|
||||||
|
secret_key: minio123
|
||||||
|
bucket: amber
|
||||||
|
use_ssl: false
|
||||||
|
region:
|
||||||
|
|
||||||
|
|
||||||
|
kafka:
|
||||||
|
bootstrap_servers:
|
||||||
|
- 127.0.0.1:9092
|
||||||
|
topic: "amber"
|
||||||
|
group_id: ""
|
||||||
|
# Plain
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
|
||||||
|
milvus:
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: 19530
|
||||||
|
db_name: library
|
||||||
|
document_collection: documents
|
||||||
|
user:
|
||||||
|
password:
|
||||||
|
|
||||||
|
third_party:
|
||||||
|
openai_api_key: ""
|
19
configs/rbac_model.conf
Normal file
19
configs/rbac_model.conf
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Request definition 即为请求定义,代表了可以传入什么样的参数来确定权限
|
||||||
|
[request_definition]
|
||||||
|
r = sub, obj, act
|
||||||
|
|
||||||
|
# Policy definition 代表了规则的组成
|
||||||
|
[policy_definition]
|
||||||
|
p = sub, obj, act
|
||||||
|
|
||||||
|
# g 是一个 RBAC系统, _, _表示角色继承关系的前项和后项,即前项继承后项角色的权限
|
||||||
|
[role_definition]
|
||||||
|
g = _, _
|
||||||
|
|
||||||
|
# Policy effect 则表示什么样的规则可以被允许, e = some(where (p.eft == allow)) 这句就表示当前请求中包含的任何一个规则被允许的话,这个权限就会被允许
|
||||||
|
[policy_effect]
|
||||||
|
e = some(where (p.eft == allow))
|
||||||
|
|
||||||
|
# 是策略匹配程序的定义。表示请求与规则是如何起作用的
|
||||||
|
[matchers]
|
||||||
|
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
|
128
docs/docs.go
Normal file
128
docs/docs.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// Package docs Code generated by swaggo/swag. DO NOT EDIT
|
||||||
|
package docs
|
||||||
|
|
||||||
|
import "github.com/swaggo/swag"
|
||||||
|
|
||||||
|
const docTemplate = `{
|
||||||
|
"schemes": {{ marshal .Schemes }},
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"description": "{{escape .Description}}",
|
||||||
|
"title": "{{.Title}}",
|
||||||
|
"contact": {},
|
||||||
|
"version": "{{.Version}}"
|
||||||
|
},
|
||||||
|
"host": "{{.Host}}",
|
||||||
|
"basePath": "{{.BasePath}}",
|
||||||
|
"paths": {
|
||||||
|
"/api/v1/ping": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "测试接口,将会返回当前用户的信息",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"ping"
|
||||||
|
],
|
||||||
|
"summary": "Greet",
|
||||||
|
"deprecated": true,
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/response.Body"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/definitions/schema.CurrentUserResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Body"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"response.Body": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {},
|
||||||
|
"error": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema.CurrentUserResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ip": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userEmail": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"valid": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"ApiKeyAuth": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||||
|
var SwaggerInfo = &swag.Spec{
|
||||||
|
Version: "1.0",
|
||||||
|
Host: "",
|
||||||
|
BasePath: "",
|
||||||
|
Schemes: []string{},
|
||||||
|
Title: "API Docs",
|
||||||
|
Description: "",
|
||||||
|
InfoInstanceName: "swagger",
|
||||||
|
SwaggerTemplate: docTemplate,
|
||||||
|
LeftDelim: "{{",
|
||||||
|
RightDelim: "}}",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||||
|
}
|
101
docs/swagger.json
Normal file
101
docs/swagger.json
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"title": "API Docs",
|
||||||
|
"contact": {},
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"/api/v1/ping": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "测试接口,将会返回当前用户的信息",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"ping"
|
||||||
|
],
|
||||||
|
"summary": "Greet",
|
||||||
|
"deprecated": true,
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/response.Body"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/definitions/schema.CurrentUserResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.Body"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"response.Body": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {},
|
||||||
|
"error": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema.CurrentUserResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ip": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userEmail": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"userName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"valid": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securityDefinitions": {
|
||||||
|
"ApiKeyAuth": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
docs/swagger.yaml
Normal file
62
docs/swagger.yaml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
definitions:
|
||||||
|
response.Body:
|
||||||
|
properties:
|
||||||
|
data: {}
|
||||||
|
error:
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
success:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
schema.CurrentUserResponse:
|
||||||
|
properties:
|
||||||
|
ip:
|
||||||
|
type: string
|
||||||
|
userEmail:
|
||||||
|
type: string
|
||||||
|
userId:
|
||||||
|
type: string
|
||||||
|
userName:
|
||||||
|
type: string
|
||||||
|
valid:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
info:
|
||||||
|
contact: {}
|
||||||
|
title: API Docs
|
||||||
|
version: "1.0"
|
||||||
|
paths:
|
||||||
|
/api/v1/ping:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
deprecated: true
|
||||||
|
description: 测试接口,将会返回当前用户的信息
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/definitions/response.Body'
|
||||||
|
- properties:
|
||||||
|
data:
|
||||||
|
$ref: '#/definitions/schema.CurrentUserResponse'
|
||||||
|
type: object
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.Body'
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Greet
|
||||||
|
tags:
|
||||||
|
- ping
|
||||||
|
securityDefinitions:
|
||||||
|
ApiKeyAuth:
|
||||||
|
in: header
|
||||||
|
name: Authorization
|
||||||
|
type: apiKey
|
||||||
|
swagger: "2.0"
|
133
go.mod
Normal file
133
go.mod
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
module leafdev.top/Leaf/leaf-library-3
|
||||||
|
|
||||||
|
go 1.23.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/MicahParks/keyfunc/v3 v3.3.5
|
||||||
|
github.com/ansrivas/fiberprometheus/v2 v2.7.0
|
||||||
|
github.com/bsm/redislock v0.9.4
|
||||||
|
github.com/bytedance/sonic v1.12.5
|
||||||
|
github.com/gofiber/contrib/fiberzap/v2 v2.1.4
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.5
|
||||||
|
github.com/gofiber/swagger v1.1.0
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
|
github.com/google/wire v0.6.0
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0
|
||||||
|
github.com/milvus-io/milvus-sdk-go/v2 v2.4.2
|
||||||
|
github.com/minio/minio-go/v7 v7.0.80
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
|
github.com/pressly/goose/v3 v3.22.1
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0
|
||||||
|
github.com/segmentio/kafka-go v0.4.47
|
||||||
|
github.com/spf13/cobra v1.8.1
|
||||||
|
github.com/spf13/viper v1.19.0
|
||||||
|
github.com/swaggo/swag v1.16.4
|
||||||
|
go.uber.org/zap v1.27.0
|
||||||
|
google.golang.org/grpc v1.68.0
|
||||||
|
google.golang.org/protobuf v1.35.2
|
||||||
|
gorm.io/driver/postgres v1.5.10
|
||||||
|
gorm.io/gen v0.3.26
|
||||||
|
gorm.io/gorm v1.25.12
|
||||||
|
gorm.io/plugin/dbresolver v1.5.3
|
||||||
|
moul.io/zapgorm2 v1.3.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
|
github.com/MicahParks/jwkset v0.5.20 // indirect
|
||||||
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.2.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/cockroachdb/errors v1.11.3 // indirect
|
||||||
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||||
|
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||||
|
github.com/getsentry/sentry-go v0.29.1 // indirect
|
||||||
|
github.com/go-ini/ini v1.67.0 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/spec v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/swag v0.23.0 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.3 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.7.1 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.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.11 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||||
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.7 // 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.16 // indirect
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.17 // indirect
|
||||||
|
github.com/mfridman/interpolate v0.0.2 // indirect
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.4.16 // indirect
|
||||||
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.60.1 // indirect
|
||||||
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||||
|
github.com/rs/xid v1.6.0 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.6.0 // indirect
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
|
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
|
github.com/spf13/cast v1.7.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
github.com/swaggo/files/v2 v2.0.1 // indirect
|
||||||
|
github.com/tidwall/gjson v1.18.0 // indirect
|
||||||
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
github.com/valyala/fasthttp v1.57.0 // indirect
|
||||||
|
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||||
|
golang.org/x/crypto v0.29.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
|
||||||
|
golang.org/x/mod v0.22.0 // indirect
|
||||||
|
golang.org/x/net v0.31.0 // indirect
|
||||||
|
golang.org/x/sync v0.9.0 // indirect
|
||||||
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
|
golang.org/x/text v0.20.0 // indirect
|
||||||
|
golang.org/x/time v0.8.0 // indirect
|
||||||
|
golang.org/x/tools v0.27.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gorm.io/datatypes v1.2.4 // indirect
|
||||||
|
gorm.io/driver/mysql v1.5.7 // indirect
|
||||||
|
gorm.io/driver/sqlserver v1.5.3 // indirect
|
||||||
|
gorm.io/hints v1.1.2 // indirect
|
||||||
|
modernc.org/sqlite v1.34.2 // indirect
|
||||||
|
)
|
568
go.sum
Normal file
568
go.sum
Normal file
@ -0,0 +1,568 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
|
||||||
|
cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
|
||||||
|
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
|
||||||
|
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY=
|
||||||
|
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA=
|
||||||
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
|
||||||
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||||
|
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||||
|
github.com/MicahParks/jwkset v0.5.20 h1:gTIKx9AofTqQJ0srd8AL7ty9NeadP5WUXSPOZadTpOI=
|
||||||
|
github.com/MicahParks/jwkset v0.5.20/go.mod h1:q8ptTGn/Z9c4MwbcfeCDssADeVQb3Pk7PnVxrvi+2QY=
|
||||||
|
github.com/MicahParks/keyfunc/v3 v3.3.5 h1:7ceAJLUAldnoueHDNzF8Bx06oVcQ5CfJnYwNt1U3YYo=
|
||||||
|
github.com/MicahParks/keyfunc/v3 v3.3.5/go.mod h1:SdCCyMJn/bYqWDvARspC6nCT8Sk74MjuAY22C7dCST8=
|
||||||
|
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||||
|
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||||
|
github.com/ansrivas/fiberprometheus/v2 v2.7.0 h1:09XiSzG0J7aZp7RviklngdWdDbSybKjhuWAstp003Gg=
|
||||||
|
github.com/ansrivas/fiberprometheus/v2 v2.7.0/go.mod h1:hSJdO65lfnWW70Qn9uGdXXsUUSkckbhuw5r/KesygpU=
|
||||||
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
|
github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw=
|
||||||
|
github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk=
|
||||||
|
github.com/bytedance/sonic v1.12.5 h1:hoZxY8uW+mT+OpkcUWw4k0fDINtOcVavEsGfzwzFU/w=
|
||||||
|
github.com/bytedance/sonic v1.12.5/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
|
||||||
|
github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
|
||||||
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
||||||
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
|
||||||
|
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
|
||||||
|
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||||
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
|
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/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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||||
|
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
|
github.com/getsentry/sentry-go v0.29.1 h1:DyZuChN8Hz3ARxGVV8ePaNXh1dQ7d76AiB117xcREwA=
|
||||||
|
github.com/getsentry/sentry-go v0.29.1/go.mod h1:x3AtIzN01d6SiWkderzaH28Tm0lgkafpJ5Bm3li39O0=
|
||||||
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
|
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
|
github.com/go-faker/faker/v4 v4.1.0 h1:ffuWmpDrducIUOO0QSKSF5Q2dxAht+dhsT9FvVHhPEI=
|
||||||
|
github.com/go-faker/faker/v4 v4.1.0/go.mod h1:uuNc0PSRxF8nMgjGrrrU4Nw5cF30Jc6Kd0/FUTTYbhg=
|
||||||
|
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||||
|
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
|
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-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||||
|
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||||
|
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||||
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||||
|
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/gofiber/contrib/fiberzap/v2 v2.1.4 h1:GCtCQnT4Cr9az4qab2Ozmqsomkxm4Ei86MfKk/1p5+0=
|
||||||
|
github.com/gofiber/contrib/fiberzap/v2 v2.1.4/go.mod h1:PkdXgUzw+oj4m6ksfKJ0Hs3H7iPhwvhfI4b2LSA9hhA=
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||||
|
github.com/gofiber/swagger v1.1.0 h1:ff3rg1fB+Rp5JN/N8jfxTiZtMKe/9tB9QDc79fPiJKQ=
|
||||||
|
github.com/gofiber/swagger v1.1.0/go.mod h1:pRZL0Np35sd+lTODTE5The0G+TMHfNY+oC4hM2/i5m8=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
|
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.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
|
github.com/google/uuid v1.3.0/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/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
|
||||||
|
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
|
||||||
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||||
|
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/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
|
||||||
|
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||||
|
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||||
|
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
|
||||||
|
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||||
|
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||||
|
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
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.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
|
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
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.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
|
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
|
||||||
|
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
|
||||||
|
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
|
||||||
|
github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA=
|
||||||
|
github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.4.16 h1:XcdubT6Vy0PvNrWDJZ4cy6ytXWRENEYgYBCLkI+YpTE=
|
||||||
|
github.com/milvus-io/milvus-proto/go-api/v2 v2.4.16/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||||
|
github.com/milvus-io/milvus-sdk-go/v2 v2.4.2 h1:Xqf+S7iicElwYoS2Zly8Nf/zKHuZsNy1xQajfdtygVY=
|
||||||
|
github.com/milvus-io/milvus-sdk-go/v2 v2.4.2/go.mod h1:ulO1YUXKH0PGg50q27grw048GDY9ayB4FPmh7D+FFTA=
|
||||||
|
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||||
|
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||||
|
github.com/minio/minio-go/v7 v7.0.80 h1:2mdUHXEykRdY/BigLt3Iuu1otL0JTogT0Nmltg0wujk=
|
||||||
|
github.com/minio/minio-go/v7 v7.0.80/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0=
|
||||||
|
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/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||||
|
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||||
|
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
|
||||||
|
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
|
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||||
|
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc=
|
||||||
|
github.com/pressly/goose/v3 v3.22.1/go.mod h1:xtMpbstWyCpyH+0cxLTMCENWBG+0CSxvTsXhW95d5eo=
|
||||||
|
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||||
|
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
|
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
|
||||||
|
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||||
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
|
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||||
|
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
|
||||||
|
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
||||||
|
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/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
|
||||||
|
github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
|
||||||
|
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
|
||||||
|
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
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.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||||
|
github.com/spf13/cast v1.7.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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
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=
|
||||||
|
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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
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/swaggo/files/v2 v2.0.1 h1:XCVJO/i/VosCDsJu1YLpdejGsGnBE9deRMpjN4pJLHk=
|
||||||
|
github.com/swaggo/files/v2 v2.0.1/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
|
||||||
|
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
|
||||||
|
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
|
||||||
|
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||||
|
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tinylib/msgp v1.1.9 h1:SHf3yoO2sGA0veCJeCBYLHuttAVFHGm2RHgNodW7wQU=
|
||||||
|
github.com/tinylib/msgp v1.1.9/go.mod h1:BCXGB54lDD8qUEPmiG0cQQUANC4IUQyB2ItS2UDlO/k=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasthttp v1.57.0 h1:Xw8SjWGEP/+wAAgyy5XTvgrWlOD1+TxbbvNADYCm1Tg=
|
||||||
|
github.com/valyala/fasthttp v1.57.0/go.mod h1:h6ZBaPRlzpZ6O3H5t2gEk1Qi33+TmLvfwgLLp0t9CpE=
|
||||||
|
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||||
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
|
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/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
|
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||||
|
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
|
||||||
|
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
|
||||||
|
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/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
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/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||||
|
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
|
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/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-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
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-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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
|
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||||
|
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||||
|
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||||
|
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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-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-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
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.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
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.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||||
|
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||||
|
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||||
|
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/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-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||||
|
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
|
||||||
|
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
|
||||||
|
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-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f h1:M65LEviCfuZTfrfzwwEoxVtgvfkFkBUbFnRbxCXuXhU=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f/go.mod h1:Yo94eF2nj7igQt+TiJ49KxjIH8ndLYPZMIRSiRcEbg0=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f h1:C1QccEa9kUwvMgEUORqQD9S17QesQijxjZ84sO82mfo=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113202542-65e8d215514f/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||||
|
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.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
|
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
|
||||||
|
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
|
||||||
|
google.golang.org/grpc/examples v0.0.0-20220617181431-3e7b97febc7f h1:rqzndB2lIQGivcXdTuY3Y9NBvr70X+y77woofSRluec=
|
||||||
|
google.golang.org/grpc/examples v0.0.0-20220617181431-3e7b97febc7f/go.mod h1:gxndsbNG1n4TZcHGgsYEfVGnTxqfEdfiDv6/DADXX9o=
|
||||||
|
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
|
||||||
|
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
|
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/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
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/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/datatypes v1.2.4 h1:uZmGAcK/QZ0uyfCuVg0VQY1ZmV9h1fuG0tMwKByO1z4=
|
||||||
|
gorm.io/datatypes v1.2.4/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/driver/postgres v1.5.10 h1:7Lggqempgy496c0WfHXsYWxk3Th+ZcW66/21QhVFdeE=
|
||||||
|
gorm.io/driver/postgres v1.5.10/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||||
|
gorm.io/driver/sqlite v1.5.0 h1:zKYbzRCpBrT1bNijRnxLDJWPjVfImGEn0lSnUY5gZ+c=
|
||||||
|
gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I=
|
||||||
|
gorm.io/driver/sqlserver v1.5.3 h1:rjupPS4PVw+rjJkfvr8jn2lJ8BMhT4UW5FwuJY0P3Z0=
|
||||||
|
gorm.io/driver/sqlserver v1.5.3/go.mod h1:B+CZ0/7oFJ6tAlefsKoyxdgDCXJKSgwS2bMOQZT0I00=
|
||||||
|
gorm.io/gen v0.3.26 h1:sFf1j7vNStimPRRAtH4zz5NiHM+1dr6eA9aaRdplyhY=
|
||||||
|
gorm.io/gen v0.3.26/go.mod h1:a5lq5y3w4g5LMxBcw0wnO6tYUCdNutWODq5LrIt75LE=
|
||||||
|
gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||||
|
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||||
|
gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||||
|
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
|
gorm.io/hints v1.1.2 h1:b5j0kwk5p4+3BtDtYqqfY+ATSxjj+6ptPgVveuynn9o=
|
||||||
|
gorm.io/hints v1.1.2/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg=
|
||||||
|
gorm.io/plugin/dbresolver v1.5.3 h1:wFwINGZZmttuu9h7XpvbDHd8Lf9bb8GNzp/NpAMV2wU=
|
||||||
|
gorm.io/plugin/dbresolver v1.5.3/go.mod h1:TSrVhaUg2DZAWP3PrHlDlITEJmNOkL0tFTjvTEsQ4XE=
|
||||||
|
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=
|
||||||
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
|
||||||
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||||
|
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
|
||||||
|
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
|
||||||
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
|
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||||
|
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||||
|
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||||
|
modernc.org/sqlite v1.34.2 h1:J9n76TPsfYYkFkZ9Uy1QphILYifiVEwwOT7yP5b++2Y=
|
||||||
|
modernc.org/sqlite v1.34.2/go.mod h1:dnR723UrTtjKpoHCAMN0Q/gZ9MT4r+iRvIBb9umWFkU=
|
||||||
|
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||||
|
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||||
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
moul.io/zapgorm2 v1.3.0 h1:+CzUTMIcnafd0d/BvBce8T4uPn6DQnpIrz64cyixlkk=
|
||||||
|
moul.io/zapgorm2 v1.3.0/go.mod h1:nPVy6U9goFKHR4s+zfSo1xVFaoU7Qgd5DoCdOfzoCqs=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
1
hack/gorm-gen/.gitignore
vendored
Normal file
1
hack/gorm-gen/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
dao
|
35
hack/gorm-gen/gorm.go
Normal file
35
hack/gorm-gen/gorm.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/entity"
|
||||||
|
|
||||||
|
"gorm.io/gen"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Dynamic SQL
|
||||||
|
//type Querier interface {
|
||||||
|
// // SELECT * FROM @@table WHERE name = @name{{if role !=""}} AND role = @role{{end}}
|
||||||
|
// FilterWithNameAndRole(name, role string) ([]gen.T, error)
|
||||||
|
//}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
//app, err := cmd.CreateApp()
|
||||||
|
//if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
//}
|
||||||
|
g := gen.NewGenerator(gen.Config{
|
||||||
|
OutPath: "../../internal/dao",
|
||||||
|
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface, // generate mode
|
||||||
|
})
|
||||||
|
|
||||||
|
//g.UseDB(app.GORM)
|
||||||
|
|
||||||
|
g.ApplyBasic(
|
||||||
|
entity.User{},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generate Type Safe API with Dynamic SQL defined on Querier interface for `model.User` and `model.Company`
|
||||||
|
//g.ApplyInterface(func(Querier) {}, model.User{}, model.Company{})
|
||||||
|
|
||||||
|
g.Execute()
|
||||||
|
}
|
135
hack/rename/rename.go
Normal file
135
hack/rename/rename.go
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const frameworkModuleName = "leafdev.top/Leaf/leaf-library-3"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 输入新的 go.mod module
|
||||||
|
var newModName string
|
||||||
|
fmt.Printf("Enter new module name(eg: github.com/<your-username>/<your-project-name>): ")
|
||||||
|
_, err := fmt.Scanln(&newModName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Unable get new module name: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Do you want to setup the project to %s? (y/n)", newModName)
|
||||||
|
var answer string
|
||||||
|
_, err = fmt.Scanln(&answer)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error reading user input: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if answer != "y" {
|
||||||
|
fmt.Printf("Aborting setup.\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改 go.mod 文件中的 module 名称
|
||||||
|
err = replaceInFile("../../go.mod", frameworkModuleName, newModName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error replacing module name in go.mod: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取 go.mod 中的 module 名称
|
||||||
|
modName, err := getModuleName("../../go.mod")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error reading go.mod: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if modName == frameworkModuleName {
|
||||||
|
fmt.Printf("Please update go.mod module to a different name.\n")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Module name found: %s\n", modName)
|
||||||
|
// 遍历当前文件夹(排除 vendor、setup.go 和版本控制文件夹)
|
||||||
|
err = filepath.Walk("../../", func(path string, info fs.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 条件排除
|
||||||
|
if info.IsDir() && (info.Name() == "vendor" || info.Name() == ".git") {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
if !info.IsDir() && info.Name() == "setup.go" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理文件
|
||||||
|
if !info.IsDir() {
|
||||||
|
err := replaceInFile(path, `"`+frameworkModuleName, fmt.Sprintf(`"%s`, modName))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error replacing in file %s: %v\n", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error walking the path: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run go mod tidy
|
||||||
|
fmt.Println("Running go mod tidy...")
|
||||||
|
var aCmd = exec.Command("go", "mod", "tidy")
|
||||||
|
if err := aCmd.Run(); err != nil {
|
||||||
|
fmt.Printf("Error running go mod tidy: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取 go.mod 文件中的 module 名称
|
||||||
|
func getModuleName(modFilePath string) (string, error) {
|
||||||
|
file, err := os.Open(modFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer func(file *os.File) {
|
||||||
|
err := file.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error closing file: %v\n", err)
|
||||||
|
}
|
||||||
|
}(file)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if strings.HasPrefix(line, "module ") {
|
||||||
|
return strings.TrimSpace(strings.TrimPrefix(line, "module ")), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("module name not found in go.mod")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在文件中替换指定的字符串
|
||||||
|
func replaceInFile(filePath string, old string, new string) error {
|
||||||
|
input, err := os.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
output := strings.ReplaceAll(string(input), old, new)
|
||||||
|
if err = os.WriteFile(filePath, []byte(output), 0666); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
28
internal/api/api.go
Normal file
28
internal/api/api.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/wire"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/grpc"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Provide = wire.NewSet(
|
||||||
|
grpc.ProviderSet,
|
||||||
|
http.ProviderSet,
|
||||||
|
NewApi,
|
||||||
|
)
|
||||||
|
|
||||||
|
type Api struct {
|
||||||
|
GRPC *grpc.Handlers
|
||||||
|
HTTP *http.Handlers
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApi(
|
||||||
|
grpcHandlers *grpc.Handlers,
|
||||||
|
httpHandlers *http.Handlers,
|
||||||
|
) *Api {
|
||||||
|
return &Api{
|
||||||
|
GRPC: grpcHandlers,
|
||||||
|
HTTP: httpHandlers,
|
||||||
|
}
|
||||||
|
}
|
149
internal/api/grpc/interceptor/auth.go
Normal file
149
internal/api/grpc/interceptor/auth.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package interceptor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
|
||||||
|
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/consts"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/schema"
|
||||||
|
auth2 "leafdev.top/Leaf/leaf-library-3/internal/service/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ignoreAuthApis = map[string]bool{
|
||||||
|
// 反射
|
||||||
|
"/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": true,
|
||||||
|
|
||||||
|
// 业务 API
|
||||||
|
"/api.v1.WorkspaceService/List": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
authService *auth2.Service
|
||||||
|
logger *logger.Logger
|
||||||
|
config *conf.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuth(
|
||||||
|
authService *auth2.Service,
|
||||||
|
logger *logger.Logger,
|
||||||
|
config *conf.Config,
|
||||||
|
) *Auth {
|
||||||
|
return &Auth{
|
||||||
|
authService: authService,
|
||||||
|
logger: logger,
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) notRequireAuth(fullMethodName string) bool {
|
||||||
|
var b = ignoreAuthApis[fullMethodName]
|
||||||
|
|
||||||
|
if a.config.Debug.Enabled {
|
||||||
|
if b {
|
||||||
|
a.logger.Sugar.Debugf("[GRPC Auth] Ignore auth for Method: %s", fullMethodName)
|
||||||
|
} else {
|
||||||
|
a.logger.Sugar.Debugf("[GRPC Auth] Require auth for Method: %s", fullMethodName)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) authCtx(ctx context.Context) (context.Context, error) {
|
||||||
|
var tokenString string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
tokenString, err = auth.AuthFromMD(ctx, "bearer")
|
||||||
|
if err != nil {
|
||||||
|
// 如果是调试模式,就不处理报错,并且继续执行
|
||||||
|
if a.config.Debug.Enabled {
|
||||||
|
tokenString = ""
|
||||||
|
a.logger.Sugar.Debugf("[GRPC Auth] error, %s", err)
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := a.authService.AuthFromToken(schema.JWTIDToken, tokenString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !token.Valid {
|
||||||
|
return nil, consts.ErrNotValidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = logging.InjectFields(ctx, logging.Fields{consts.AuthMiddlewareKey, token.Token.Sub})
|
||||||
|
ctx = context.WithValue(ctx, consts.AuthMiddlewareKey, token)
|
||||||
|
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) UnaryJWTAuth() grpc.UnaryServerInterceptor {
|
||||||
|
return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||||
|
if a.notRequireAuth(info.FullMethod) {
|
||||||
|
return handler(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, err := a.authCtx(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := handler(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) StreamJWTAuth() grpc.StreamServerInterceptor {
|
||||||
|
return func(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||||
|
var ctx = ss.Context()
|
||||||
|
|
||||||
|
if a.notRequireAuth(info.FullMethod) {
|
||||||
|
return handler(srv, ss)
|
||||||
|
}
|
||||||
|
ctx, err := a.authCtx(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = handler(srv, ss)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//func (a *Auth) JwtAuth(ctx context.Context) (context.Context, error) {
|
||||||
|
// tokenString, err := auth.AuthFromMD(ctx, "bearer")
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// token, err := a.authService.AuthFromToken(schema.JWTIDToken, tokenString)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !token.Valid {
|
||||||
|
// return nil, consts.ErrNotValidToken
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ctx = logging.InjectFields(ctx, logging.Fields{consts.AuthMiddlewareKey, token.Token.Sub})
|
||||||
|
//
|
||||||
|
// return context.WithValue(ctx, consts.AuthMiddlewareKey, token), nil
|
||||||
|
//}
|
57
internal/api/grpc/interceptor/zap_logger.go
Normal file
57
internal/api/grpc/interceptor/zap_logger.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package interceptor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
Logger *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogger(logger *logger.Logger) *Logger {
|
||||||
|
return &Logger{
|
||||||
|
Logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) ZapLogInterceptor() logging.Logger {
|
||||||
|
return logging.LoggerFunc(func(ctx context.Context, lvl logging.Level, msg string, fields ...any) {
|
||||||
|
f := make([]zap.Field, 0, len(fields)/2)
|
||||||
|
|
||||||
|
for i := 0; i < len(fields); i += 2 {
|
||||||
|
key := fields[i]
|
||||||
|
value := fields[i+1]
|
||||||
|
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
f = append(f, zap.String(key.(string), v))
|
||||||
|
case int:
|
||||||
|
f = append(f, zap.Int(key.(string), v))
|
||||||
|
case bool:
|
||||||
|
f = append(f, zap.Bool(key.(string), v))
|
||||||
|
default:
|
||||||
|
f = append(f, zap.Any(key.(string), v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger2 := l.Logger.Logger.WithOptions(zap.AddCallerSkip(1)).With(f...)
|
||||||
|
|
||||||
|
switch lvl {
|
||||||
|
case logging.LevelDebug:
|
||||||
|
logger2.Debug(msg)
|
||||||
|
case logging.LevelInfo:
|
||||||
|
logger2.Info(msg)
|
||||||
|
case logging.LevelWarn:
|
||||||
|
logger2.Warn(msg)
|
||||||
|
case logging.LevelError:
|
||||||
|
logger2.Error(msg)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unknown level %v", lvl))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
46
internal/api/grpc/provider.go
Normal file
46
internal/api/grpc/provider.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/wire"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/grpc/interceptor"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/grpc/v1/documents"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ProviderSet = wire.NewSet(
|
||||||
|
interceptor.NewAuth,
|
||||||
|
interceptor.NewLogger,
|
||||||
|
documents.NewHandler,
|
||||||
|
|
||||||
|
NewInterceptor,
|
||||||
|
NewHandler,
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewHandler(
|
||||||
|
documentApi *documents.Handler,
|
||||||
|
interceptor2 *Interceptor,
|
||||||
|
) *Handlers {
|
||||||
|
return &Handlers{
|
||||||
|
DocumentApi: documentApi,
|
||||||
|
Interceptor: interceptor2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Handlers struct {
|
||||||
|
DocumentApi *documents.Handler
|
||||||
|
Interceptor *Interceptor
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interceptor struct {
|
||||||
|
Auth *interceptor.Auth
|
||||||
|
Logger *interceptor.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInterceptor(
|
||||||
|
Auth *interceptor.Auth,
|
||||||
|
Logger *interceptor.Logger,
|
||||||
|
) *Interceptor {
|
||||||
|
return &Interceptor{
|
||||||
|
Auth: Auth,
|
||||||
|
Logger: Logger,
|
||||||
|
}
|
||||||
|
}
|
11
internal/api/grpc/v1/documents/document.go
Normal file
11
internal/api/grpc/v1/documents/document.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package documents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
v1 "leafdev.top/Leaf/leaf-library-3/proto/gen/proto/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *Handler) ListDocuments(ctx context.Context, req *v1.ListDocumentsRequest) (*v1.ListDocumentsResponse, error) {
|
||||||
|
return &v1.ListDocumentsResponse{}, nil
|
||||||
|
}
|
18
internal/api/grpc/v1/documents/provider.go
Normal file
18
internal/api/grpc/v1/documents/provider.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package documents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/dao"
|
||||||
|
v1 "leafdev.top/Leaf/leaf-library-3/proto/gen/proto/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
v1.UnimplementedDocumentServiceServer
|
||||||
|
dao *dao.Query
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(dao *dao.Query) *Handler {
|
||||||
|
return &Handler{
|
||||||
|
v1.UnimplementedDocumentServiceServer{},
|
||||||
|
dao,
|
||||||
|
}
|
||||||
|
}
|
87
internal/api/http/middleware/auth.go
Normal file
87
internal/api/http/middleware/auth.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http/response"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/consts"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/pkg/user"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/schema"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
config *conf.Config
|
||||||
|
authService *auth.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
var audienceLength int
|
||||||
|
|
||||||
|
func NewAuth(config *conf.Config, authService *auth.Service) *Auth {
|
||||||
|
audienceLength = len(config.App.AllowedAudiences)
|
||||||
|
|
||||||
|
return &Auth{
|
||||||
|
config,
|
||||||
|
authService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) Handler() fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var r = response.Ctx(c)
|
||||||
|
var err error
|
||||||
|
var token = new(user.User)
|
||||||
|
|
||||||
|
if a.config.Debug.Enabled {
|
||||||
|
token, err = a.authService.AuthFromToken(schema.JWTAccessToken, "")
|
||||||
|
if err != nil {
|
||||||
|
return r.Error(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Locals(consts.AuthMiddlewareKey, token)
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
authorization := c.Get(consts.AuthHeader)
|
||||||
|
|
||||||
|
if authorization == "" {
|
||||||
|
return r.Error(consts.ErrJWTFormatError).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
authSplit := strings.Split(authorization, " ")
|
||||||
|
if len(authSplit) != 2 {
|
||||||
|
return r.Error(consts.ErrJWTFormatError).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
if authSplit[0] != consts.AuthPrefix {
|
||||||
|
return r.Error(consts.ErrNotBearerType).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err = a.authService.AuthFromToken(schema.JWTIDToken, authSplit[1])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return r.Error(err).Status(http.StatusUnauthorized).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
if token == nil {
|
||||||
|
return r.Error(err).Status(http.StatusUnauthorized).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
if audienceLength > 0 {
|
||||||
|
// 检测 aud
|
||||||
|
if !slices.Contains(a.config.App.AllowedAudiences, token.Token.Aud) {
|
||||||
|
return r.Error(consts.ErrNotValidToken).Send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Locals(consts.AuthMiddlewareKey, token)
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
internal/api/http/middleware/json_response.go
Normal file
20
internal/api/http/middleware/json_response.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JSONResponse struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*JSONResponse) Handler() fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
c.Response().Header.Set("Content-Type", "application/json")
|
||||||
|
return c.Next()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJSONResponse() *JSONResponse {
|
||||||
|
return &JSONResponse{}
|
||||||
|
}
|
140
internal/api/http/middleware/rbac.go
Normal file
140
internal/api/http/middleware/rbac.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http/response"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
userPkg "leafdev.top/Leaf/leaf-library-3/internal/pkg/user"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RBAC struct {
|
||||||
|
authService *auth.Service
|
||||||
|
config *conf.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RBAC) RoutePermission() fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
user, ok := m.authService.GetUserSafe(c)
|
||||||
|
if !ok {
|
||||||
|
return response.Ctx(c).Error(nil).Status(http.StatusUnauthorized).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.Valid {
|
||||||
|
return response.Ctx(c).Error(nil).Status(http.StatusUnauthorized).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = cleanPath(c.Path())
|
||||||
|
act := strings.ToLower(c.Method())
|
||||||
|
|
||||||
|
permissionName := userPkg.Permission(m.config.App.Name + ":" + path + ":" + act)
|
||||||
|
pass := user.HasPermissions(permissionName)
|
||||||
|
|
||||||
|
if !pass {
|
||||||
|
return response.Ctx(c).
|
||||||
|
Message(fmt.Sprintf("permission denied, permission name: %s", permissionName)).
|
||||||
|
Error(nil).
|
||||||
|
Status(http.StatusForbidden).
|
||||||
|
Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RBAC) RequirePermissions(permissions ...string) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
user, ok := m.authService.GetUserSafe(c)
|
||||||
|
if !ok {
|
||||||
|
return response.Ctx(c).Error(nil).Status(http.StatusUnauthorized).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.Valid {
|
||||||
|
return response.Ctx(c).Error(nil).Status(http.StatusUnauthorized).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
var pass = true
|
||||||
|
var failedPermissionName string
|
||||||
|
|
||||||
|
for _, permission := range permissions {
|
||||||
|
permissionName := userPkg.Permission(m.config.App.Name + ":" + permission)
|
||||||
|
|
||||||
|
has := user.HasPermissions(permissionName)
|
||||||
|
if !has {
|
||||||
|
failedPermissionName = permissionName.String()
|
||||||
|
pass = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pass {
|
||||||
|
return response.Ctx(c).
|
||||||
|
Message(fmt.Sprintf("permission denied, required permissions: %s, failed permission: %s",
|
||||||
|
permissions, failedPermissionName)).
|
||||||
|
Error(nil).
|
||||||
|
Status(http.StatusForbidden).
|
||||||
|
Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RBAC) RequireRoles(roles ...string) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
user, ok := m.authService.GetUserSafe(c)
|
||||||
|
if !ok {
|
||||||
|
return response.Ctx(c).Error(nil).Status(http.StatusUnauthorized).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.Valid {
|
||||||
|
return response.Ctx(c).Error(nil).Status(http.StatusUnauthorized).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
var pass = true
|
||||||
|
var failedRoleName string
|
||||||
|
|
||||||
|
for _, role := range roles {
|
||||||
|
roleName := userPkg.Role(m.config.App.Name + ":" + role)
|
||||||
|
pass = user.HasRoles(roleName)
|
||||||
|
|
||||||
|
if !pass {
|
||||||
|
failedRoleName = roleName.String()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pass {
|
||||||
|
return response.Ctx(c).
|
||||||
|
Message(fmt.Sprintf("permission denied, required roles: %s, failed role %s", roles, failedRoleName)).
|
||||||
|
Error(nil).
|
||||||
|
Status(http.StatusForbidden).
|
||||||
|
Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRBAC(authService *auth.Service, config *conf.Config) *RBAC {
|
||||||
|
return &RBAC{
|
||||||
|
authService: authService,
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanPath(path string) string {
|
||||||
|
// 如果第一个字符是 /,则删掉
|
||||||
|
if path[0] == '/' {
|
||||||
|
path = path[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将所有的 / 转为 :
|
||||||
|
return strings.ReplaceAll(path, "/", ":")
|
||||||
|
|
||||||
|
}
|
25
internal/api/http/middleware/zap_logger.go
Normal file
25
internal/api/http/middleware/zap_logger.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/contrib/fiberzap/v2"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogger(logger *zap.Logger) *Logger {
|
||||||
|
return &Logger{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Handler() fiber.Handler {
|
||||||
|
var config = fiberzap.Config{
|
||||||
|
Logger: l.logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
return fiberzap.New(config)
|
||||||
|
}
|
58
internal/api/http/provider.go
Normal file
58
internal/api/http/provider.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/google/wire"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http/middleware"
|
||||||
|
v1 "leafdev.top/Leaf/leaf-library-3/internal/api/http/v1"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IMiddleware interface {
|
||||||
|
Handler() fiber.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
type Middleware struct {
|
||||||
|
Logger IMiddleware
|
||||||
|
Auth IMiddleware
|
||||||
|
JSONResponse IMiddleware
|
||||||
|
RBAC *middleware.RBAC
|
||||||
|
}
|
||||||
|
|
||||||
|
type Handlers struct {
|
||||||
|
User *v1.UserController
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(
|
||||||
|
user *v1.UserController,
|
||||||
|
) *Handlers {
|
||||||
|
return &Handlers{
|
||||||
|
User: user,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMiddleware(config *conf.Config, logger *logger.Logger, authService *auth.Service) *Middleware {
|
||||||
|
return &Middleware{
|
||||||
|
Logger: middleware.NewLogger(logger.Logger),
|
||||||
|
Auth: middleware.NewAuth(config, authService),
|
||||||
|
JSONResponse: middleware.NewJSONResponse(),
|
||||||
|
RBAC: middleware.NewRBAC(authService, config),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ProviderSet = wire.NewSet(
|
||||||
|
// Init Middleware
|
||||||
|
middleware.NewAuth,
|
||||||
|
middleware.NewLogger,
|
||||||
|
middleware.NewJSONResponse,
|
||||||
|
middleware.NewRBAC,
|
||||||
|
NewMiddleware,
|
||||||
|
|
||||||
|
// Init Controller
|
||||||
|
v1.NewUserController,
|
||||||
|
|
||||||
|
// Init Handler
|
||||||
|
NewHandler,
|
||||||
|
)
|
134
internal/api/http/response/http.go
Normal file
134
internal/api/http/response/http.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Body struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Data any `json:"data,omitempty"`
|
||||||
|
Wrap bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpResponse struct {
|
||||||
|
body *Body
|
||||||
|
httpStatus int
|
||||||
|
ctx *fiber.Ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ctx(c *fiber.Ctx) *HttpResponse {
|
||||||
|
return &HttpResponse{
|
||||||
|
body: &Body{
|
||||||
|
Wrap: true,
|
||||||
|
},
|
||||||
|
ctx: c,
|
||||||
|
httpStatus: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpResponse) Message(message string) *HttpResponse {
|
||||||
|
r.body.Message = message
|
||||||
|
|
||||||
|
if r.httpStatus == 0 {
|
||||||
|
r.httpStatus = http.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithoutWrap 将不在 body 中包裹 data
|
||||||
|
func (r *HttpResponse) WithoutWrap() *HttpResponse {
|
||||||
|
r.body.Wrap = false
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpResponse) Wrap() *HttpResponse {
|
||||||
|
r.body.Wrap = true
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpResponse) Data(data any) *HttpResponse {
|
||||||
|
r.body.Data = data
|
||||||
|
return r
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpResponse) Error(err error) *HttpResponse {
|
||||||
|
if err != nil {
|
||||||
|
var errMsg = err.Error()
|
||||||
|
|
||||||
|
if errMsg == "EOF" {
|
||||||
|
errMsg = "Request body is empty or missing some fields, make sure you have provided all the required fields"
|
||||||
|
}
|
||||||
|
|
||||||
|
r.body.Error = errMsg
|
||||||
|
|
||||||
|
if r.httpStatus == 0 {
|
||||||
|
r.httpStatus = http.StatusBadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.body.Message == "" {
|
||||||
|
r.Message("Something went wrong")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.body.Success = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpResponse) Status(status int) *HttpResponse {
|
||||||
|
r.httpStatus = status
|
||||||
|
return r
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpResponse) Send() error {
|
||||||
|
if r.httpStatus == 0 {
|
||||||
|
r.httpStatus = http.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// if 20x or 20x, set success
|
||||||
|
r.body.Success = r.httpStatus >= http.StatusOK && r.httpStatus < http.StatusMultipleChoices
|
||||||
|
|
||||||
|
// if 403 or 401 but not have message
|
||||||
|
if r.httpStatus == http.StatusForbidden || r.httpStatus == http.StatusUnauthorized {
|
||||||
|
if r.body.Message == "" {
|
||||||
|
r.Message("Unauthorized")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.body.Wrap {
|
||||||
|
return r.ctx.Status(r.httpStatus).JSON(r.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.ctx.Status(r.httpStatus).JSON(r.body.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//func ResponseMessage(c *gin.Context, code int, message string, data interface{}) {
|
||||||
|
// c.JSON(code, &Body{
|
||||||
|
// Message: message,
|
||||||
|
// Data: data,
|
||||||
|
// })
|
||||||
|
// c.Abort()
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func ResponseError(c *gin.Context, code int, err error) {
|
||||||
|
// c.JSON(code, &Body{
|
||||||
|
// Error: err.Error(),
|
||||||
|
// })
|
||||||
|
// c.Abort()
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func Response(c *gin.Context, code int, data interface{}) {
|
||||||
|
// c.JSON(code, &Body{
|
||||||
|
// Data: data,
|
||||||
|
// })
|
||||||
|
// c.Abort()
|
||||||
|
//}
|
43
internal/api/http/v1/test.go
Normal file
43
internal/api/http/v1/test.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http/response"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/schema"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserController struct {
|
||||||
|
authService *auth.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserController(authService *auth.Service) *UserController {
|
||||||
|
return &UserController{authService}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test godoc
|
||||||
|
// @Summary Greet
|
||||||
|
// @Description 测试接口,将会返回当前用户的信息
|
||||||
|
// @Tags ping
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @deprecated true
|
||||||
|
// @Success 200 {object} response.Body{data=schema.CurrentUserResponse}
|
||||||
|
// @Failure 400 {object} response.Body
|
||||||
|
// @Router /api/v1/ping [get]
|
||||||
|
func (u *UserController) Test(c *fiber.Ctx) error {
|
||||||
|
user := u.authService.GetUser(c)
|
||||||
|
|
||||||
|
var currentUserResponse = &schema.CurrentUserResponse{
|
||||||
|
IP: c.IP(),
|
||||||
|
Valid: user.Valid,
|
||||||
|
UserEmail: user.Token.Email,
|
||||||
|
UserId: user.Token.Sub,
|
||||||
|
UserName: user.Token.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Ctx(c).Status(http.StatusOK).Data(currentUserResponse).Send()
|
||||||
|
}
|
57
internal/base/app.go
Normal file
57
internal/base/app.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/milvus-io/milvus-sdk-go/v2/client"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/redis"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/s3"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/server"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/batch"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/dao"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Application struct {
|
||||||
|
Config *conf.Config
|
||||||
|
Logger *logger.Logger
|
||||||
|
Api *api.Api
|
||||||
|
HttpServer *server.HttpServer
|
||||||
|
GORM *gorm.DB
|
||||||
|
DAO *dao.Query
|
||||||
|
Service *service.Service
|
||||||
|
Redis *redis.Redis
|
||||||
|
Batch *batch.Batch
|
||||||
|
S3 *s3.S3
|
||||||
|
Milvus client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApplication(
|
||||||
|
config *conf.Config,
|
||||||
|
httpServer *server.HttpServer,
|
||||||
|
api *api.Api,
|
||||||
|
logger *logger.Logger,
|
||||||
|
services *service.Service,
|
||||||
|
redis *redis.Redis,
|
||||||
|
batch *batch.Batch,
|
||||||
|
s3 *s3.S3,
|
||||||
|
gorm *gorm.DB,
|
||||||
|
dao *dao.Query,
|
||||||
|
milvus client.Client,
|
||||||
|
) *Application {
|
||||||
|
return &Application{
|
||||||
|
Config: config,
|
||||||
|
HttpServer: httpServer,
|
||||||
|
Api: api,
|
||||||
|
Logger: logger,
|
||||||
|
Service: services,
|
||||||
|
Redis: redis,
|
||||||
|
Batch: batch,
|
||||||
|
S3: s3,
|
||||||
|
GORM: gorm,
|
||||||
|
DAO: dao,
|
||||||
|
Milvus: milvus,
|
||||||
|
}
|
||||||
|
}
|
116
internal/base/conf/conf.go
Normal file
116
internal/base/conf/conf.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
// Config 配置文件不能有下划线或横线,否则不能解析
|
||||||
|
type Config struct {
|
||||||
|
App *App `yaml:"app"`
|
||||||
|
|
||||||
|
Http *Http `yaml:"http"`
|
||||||
|
|
||||||
|
Grpc *Grpc `yaml:"grpc"`
|
||||||
|
|
||||||
|
Debug *Debug `yaml:"debug"`
|
||||||
|
|
||||||
|
Database *Database `yaml:"database"`
|
||||||
|
|
||||||
|
Redis *Redis `yaml:"redis"`
|
||||||
|
|
||||||
|
JWKS *JWKS `yaml:"jwks"`
|
||||||
|
|
||||||
|
Metrics *Metrics `yaml:"metrics"`
|
||||||
|
|
||||||
|
S3 *S3 `yaml:"s3"`
|
||||||
|
|
||||||
|
Kafka *Kafka `yaml:"kafka"`
|
||||||
|
|
||||||
|
Milvus *Milvus `yaml:"milvus"`
|
||||||
|
|
||||||
|
ThirdParty *ThirdParty `yaml:"third_party" mapstructure:"third_party"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type App struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
AllowedAudiences []string `yaml:"allowed_audiences" mapstructure:"allowed_audiences"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThirdParty struct {
|
||||||
|
OpenAIApiKey string `yaml:"openai_api_key" mapstructure:"openai_api_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Http struct {
|
||||||
|
Host string `yaml:"host" mapstructure:"host"`
|
||||||
|
Port int `yaml:"port" mapstructure:"port"`
|
||||||
|
Url string `yaml:"url" mapstructure:"url"`
|
||||||
|
Cors struct {
|
||||||
|
Enabled bool `yaml:"enabled" mapstructure:"enabled"`
|
||||||
|
AllowedOrigins []string `yaml:"allow_origins" mapstructure:"allow_origins"`
|
||||||
|
AllowMethods []string `yaml:"allow_methods" mapstructure:"allow_methods"`
|
||||||
|
AllowHeaders []string `yaml:"allow_headers" mapstructure:"allow_headers"`
|
||||||
|
AllowCredentials bool `yaml:"allow_credentials" mapstructure:"allow_credentials"`
|
||||||
|
ExposeHeaders []string `yaml:"expose_headers" mapstructure:"expose_headers"`
|
||||||
|
MaxAge int `yaml:"max_age" mapstructure:"max_age"`
|
||||||
|
} `yaml:"cors" mapstructure:"cors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Debug struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Database struct {
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
User string `yaml:"user"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
SSLMode string `yaml:"sslmode"`
|
||||||
|
TimeZone string `yaml:"timezone"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Redis struct {
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
|
DB int `yaml:"db"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JWKS struct {
|
||||||
|
Url string `yaml:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metrics struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type S3 struct {
|
||||||
|
Endpoint string `yaml:"endpoint" mapstructure:"endpoint"`
|
||||||
|
ExternalEndpoint string `yaml:"external_endpoint" mapstructure:"external_endpoint"`
|
||||||
|
AccessKey string `yaml:"access_key" mapstructure:"access_key"`
|
||||||
|
SecretKey string `yaml:"secret_key" mapstructure:"secret_key"`
|
||||||
|
Bucket string `yaml:"bucket" mapstructure:"bucket"`
|
||||||
|
UseSSL bool `yaml:"use_ssl" mapstructure:"use_ssl"`
|
||||||
|
Region string `yaml:"region" mapstructure:"region"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Kafka struct {
|
||||||
|
BootstrapServers []string `yaml:"bootstrap_servers" mapstructure:"bootstrap_servers"`
|
||||||
|
GroupId string `yaml:"group_id" mapstructure:"group_id"`
|
||||||
|
Username string `yaml:"username" mapstructure:"username"`
|
||||||
|
Password string `yaml:"password" mapstructure:"password"`
|
||||||
|
MainTopic string `yaml:"main_topic" mapstructure:"main_topic"`
|
||||||
|
WorkerTopic string `yaml:"worker_topic" mapstructure:"worker_topic"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Milvus struct {
|
||||||
|
Host string `yaml:"host" mapstructure:"host"`
|
||||||
|
Port int `yaml:"port" mapstructure:"port"`
|
||||||
|
DBName string `yaml:"db_name" mapstructure:"db_name"`
|
||||||
|
DocumentCollection string `yaml:"document_collection" mapstructure:"document_collection"`
|
||||||
|
User string `yaml:"user" mapstructure:"user"`
|
||||||
|
Password string `yaml:"password" mapstructure:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Grpc struct {
|
||||||
|
Address string `yaml:"address" mapstructure:"address"`
|
||||||
|
AddressGateway string `yaml:"address_gateway" mapstructure:"address_gateway"`
|
||||||
|
}
|
36
internal/base/conf/helper.go
Normal file
36
internal/base/conf/helper.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/configs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createConfigIfNotExists(path string) {
|
||||||
|
if path != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// create if not exists
|
||||||
|
var configName = "config.yaml"
|
||||||
|
|
||||||
|
if _, err := os.Stat(configName); os.IsNotExist(err) {
|
||||||
|
f, err := os.Create(configName)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write default from embed
|
||||||
|
_, err = f.Write(configs.Config)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(f *os.File) {
|
||||||
|
err := f.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}(f)
|
||||||
|
}
|
||||||
|
}
|
70
internal/base/conf/provider.go
Normal file
70
internal/base/conf/provider.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// depth 是配置文件的搜索深度
|
||||||
|
var depth = 8
|
||||||
|
|
||||||
|
func getConfigPath() string {
|
||||||
|
var path string
|
||||||
|
if os.Getenv("CONFIG") != "" {
|
||||||
|
path = os.Getenv("CONFIG")
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
var pathOptions []string
|
||||||
|
for i := 0; i <= depth; i++ {
|
||||||
|
pathOptions = append(pathOptions, strings.Repeat("../", i)+"config.yaml")
|
||||||
|
}
|
||||||
|
for _, p := range pathOptions {
|
||||||
|
if _, err := os.Stat(p); err == nil {
|
||||||
|
path = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if path != "" {
|
||||||
|
// 假设 workDir 是当前工作目录的路径
|
||||||
|
workDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将相对路径转换为绝对路径
|
||||||
|
path, err = filepath.Abs(filepath.Join(workDir, path))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfig() *Config {
|
||||||
|
var path = getConfigPath()
|
||||||
|
createConfigIfNotExists(path)
|
||||||
|
|
||||||
|
if path == "" {
|
||||||
|
panic("config file not found, created on app root.")
|
||||||
|
} else {
|
||||||
|
println("config file found:", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &Config{}
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
v.SetConfigFile(path)
|
||||||
|
if err := v.ReadInConfig(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := v.Unmarshal(c); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
9
internal/base/conf/rbac_model.go
Normal file
9
internal/base/conf/rbac_model.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/configs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Config) GetRBACModel() string {
|
||||||
|
return string(configs.RBACModel)
|
||||||
|
}
|
36
internal/base/logger/provider.go
Normal file
36
internal/base/logger/provider.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
Sugar *zap.SugaredLogger
|
||||||
|
Logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewZapLogger(config *conf.Config) *Logger {
|
||||||
|
var logger *zap.Logger
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if config.Debug.Enabled {
|
||||||
|
logger, err = zap.NewDevelopment(zap.AddCallerSkip(1))
|
||||||
|
} else {
|
||||||
|
logger, err = zap.NewProduction()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//defer func(logger *zap.Logger) {
|
||||||
|
// err := logger.Sync()
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
//}(logger)
|
||||||
|
|
||||||
|
return &Logger{Sugar: logger.Sugar(), Logger: logger}
|
||||||
|
}
|
30
internal/base/milvus/provide.go
Normal file
30
internal/base/milvus/provide.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package milvus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/milvus-io/milvus-sdk-go/v2/client"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewService(config *conf.Config, logger *logger.Logger) client.Client {
|
||||||
|
var address = config.Milvus.Host + ":" + strconv.Itoa(config.Milvus.Port)
|
||||||
|
|
||||||
|
logger.Sugar.Infof("Connecting Milvus, address=%s, dbname=%s", address, config.Milvus.DBName)
|
||||||
|
|
||||||
|
c, err := client.NewClient(context.Background(), client.Config{
|
||||||
|
Address: address,
|
||||||
|
DBName: config.Milvus.DBName,
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.Sugar.Infof("Milvus connected!")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
36
internal/base/orm/provide.go
Normal file
36
internal/base/orm/provide.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package orm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"moul.io/zapgorm2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewGORM(
|
||||||
|
config *conf.Config,
|
||||||
|
logger *logger.Logger,
|
||||||
|
) *gorm.DB {
|
||||||
|
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=%s TimeZone=%s",
|
||||||
|
config.Database.Host, config.Database.User, config.Database.Password, config.Database.Name, config.Database.Port, config.Database.SSLMode, config.Database.TimeZone)
|
||||||
|
|
||||||
|
gormConfig := &gorm.Config{}
|
||||||
|
|
||||||
|
if !config.Debug.Enabled {
|
||||||
|
zapGormLogger := zapgorm2.New(logger.Logger)
|
||||||
|
zapGormLogger.SetAsDefault()
|
||||||
|
gormConfig.Logger = zapGormLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := gorm.Open(postgres.Open(dsn), gormConfig)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
|
||||||
|
}
|
39
internal/base/redis/provide.go
Normal file
39
internal/base/redis/provide.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
|
||||||
|
"github.com/bsm/redislock"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Redis struct {
|
||||||
|
Client *redis.Client
|
||||||
|
Locker *redislock.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRedis(c *conf.Config) *Redis {
|
||||||
|
var client = redis.NewClient(&redis.Options{
|
||||||
|
Addr: fmt.Sprintf("%s:%d", c.Redis.Host, c.Redis.Port),
|
||||||
|
Password: c.Redis.Password,
|
||||||
|
DB: c.Redis.DB,
|
||||||
|
})
|
||||||
|
|
||||||
|
status := client.Ping(context.Background())
|
||||||
|
if status.Err() != nil {
|
||||||
|
panic(status.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new lock client.
|
||||||
|
locker := redislock.New(client)
|
||||||
|
|
||||||
|
var r = &Redis{
|
||||||
|
Client: client,
|
||||||
|
Locker: locker,
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
29
internal/base/s3/provide.go
Normal file
29
internal/base/s3/provide.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package s3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
|
||||||
|
"github.com/minio/minio-go/v7"
|
||||||
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
type S3 struct {
|
||||||
|
Client *minio.Client
|
||||||
|
Bucket string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewS3(config *conf.Config) *S3 {
|
||||||
|
minioClient, err := minio.New(config.S3.Endpoint, &minio.Options{
|
||||||
|
Creds: credentials.NewStaticV4(config.S3.AccessKey, config.S3.SecretKey, ""),
|
||||||
|
Secure: config.S3.UseSSL,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &S3{
|
||||||
|
Client: minioClient,
|
||||||
|
Bucket: config.S3.Bucket,
|
||||||
|
}
|
||||||
|
}
|
111
internal/base/server/http.go
Normal file
111
internal/base/server/http.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ansrivas/fiberprometheus/v2"
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/recover"
|
||||||
|
httpApi "leafdev.top/Leaf/leaf-library-3/internal/api/http"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http/response"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/consts"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/router"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HttpServer struct {
|
||||||
|
config *conf.Config
|
||||||
|
Fiber *fiber.App
|
||||||
|
apiRouter *router.Api
|
||||||
|
swaggerRouter *router.SwaggerRouter
|
||||||
|
middleware *httpApi.Middleware
|
||||||
|
authService *auth.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHTTPServer new http server.
|
||||||
|
func NewHTTPServer(
|
||||||
|
config *conf.Config,
|
||||||
|
apiRouter *router.Api,
|
||||||
|
swaggerRouter *router.SwaggerRouter,
|
||||||
|
middleware *httpApi.Middleware,
|
||||||
|
logger *logger.Logger,
|
||||||
|
) *HttpServer {
|
||||||
|
app := fiber.New(fiber.Config{
|
||||||
|
JSONEncoder: sonic.Marshal,
|
||||||
|
JSONDecoder: sonic.Unmarshal,
|
||||||
|
ErrorHandler: func(ctx *fiber.Ctx, err error) error {
|
||||||
|
logger.Sugar.Errorf("fiber error: %s", err)
|
||||||
|
return response.Ctx(ctx).Status(fiber.StatusInternalServerError).Error(consts.ErrInternalServerError).Send()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
app.Use(recover.New())
|
||||||
|
app.Use(middleware.Logger.Handler())
|
||||||
|
app.Use(middleware.JSONResponse.Handler())
|
||||||
|
|
||||||
|
return &HttpServer{
|
||||||
|
config: config,
|
||||||
|
Fiber: app,
|
||||||
|
apiRouter: apiRouter,
|
||||||
|
swaggerRouter: swaggerRouter,
|
||||||
|
middleware: middleware,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hs *HttpServer) AllowAllCors() {
|
||||||
|
if hs.config.Http.Cors.Enabled {
|
||||||
|
var config = cors.Config{
|
||||||
|
AllowOrigins: strings.Join(hs.config.Http.Cors.AllowedOrigins, ","),
|
||||||
|
AllowMethods: strings.Join(hs.config.Http.Cors.AllowMethods, ","),
|
||||||
|
AllowHeaders: strings.Join(hs.config.Http.Cors.AllowHeaders, ","),
|
||||||
|
AllowCredentials: hs.config.Http.Cors.AllowCredentials,
|
||||||
|
ExposeHeaders: strings.Join(hs.config.Http.Cors.ExposeHeaders, ","),
|
||||||
|
MaxAge: hs.config.Http.Cors.MaxAge,
|
||||||
|
}
|
||||||
|
|
||||||
|
hs.Fiber.Use(cors.New(config))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hs *HttpServer) BizRouter() *fiber.App {
|
||||||
|
hs.AllowAllCors()
|
||||||
|
|
||||||
|
rootGroup := hs.Fiber.Group("")
|
||||||
|
|
||||||
|
// Swagger
|
||||||
|
hs.swaggerRouter.Register(rootGroup)
|
||||||
|
|
||||||
|
// 注册路由
|
||||||
|
hs.apiRouter.V1(rootGroup)
|
||||||
|
|
||||||
|
// 404 Route
|
||||||
|
hs.Fiber.Use(func(ctx *fiber.Ctx) error {
|
||||||
|
return response.Ctx(ctx).Status(fiber.StatusNotFound).Send()
|
||||||
|
})
|
||||||
|
|
||||||
|
return hs.Fiber
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hs *HttpServer) MetricRouter() *fiber.App {
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
app.Use(recover.New())
|
||||||
|
|
||||||
|
metricGroup := app.Group("")
|
||||||
|
|
||||||
|
prometheus := fiberprometheus.New(hs.config.App.Name)
|
||||||
|
|
||||||
|
prometheus.RegisterAt(app, "/metrics")
|
||||||
|
|
||||||
|
metricGroup.Use(prometheus.Middleware)
|
||||||
|
|
||||||
|
metricGroup.Get("/healthz", func(ctx *fiber.Ctx) error {
|
||||||
|
return ctx.Status(http.StatusOK).SendString("OK")
|
||||||
|
})
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
16
internal/batch/provider.go
Normal file
16
internal/batch/provider.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package batch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Batch struct {
|
||||||
|
logger *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBatch(
|
||||||
|
logger *logger.Logger,
|
||||||
|
) *Batch {
|
||||||
|
//base.NewApplication()
|
||||||
|
return &Batch{logger}
|
||||||
|
}
|
31
internal/consts/auth.go
Normal file
31
internal/consts/auth.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package consts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/pkg/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AuthHeader = "Authorization"
|
||||||
|
AuthPrefix = "Bearer"
|
||||||
|
|
||||||
|
// AnonymousUser 调试模式下的用户
|
||||||
|
AnonymousUser user.Id = "anonymous"
|
||||||
|
|
||||||
|
AuthMiddlewareKey = "auth.user"
|
||||||
|
AuthAssistantShareMiddlewareKey = "auth.assistant.share"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNotValidToken = errors.New("JWT not valid")
|
||||||
|
ErrJWTFormatError = errors.New("JWT format error")
|
||||||
|
ErrNotBearerType = errors.New("not bearer token")
|
||||||
|
ErrEmptyResponse = errors.New("empty response")
|
||||||
|
ErrTokenError = errors.New("token type error")
|
||||||
|
ErrUnauthorized = errors.New("unauthorized")
|
||||||
|
ErrAudienceNotAllowed = errors.New("audience not allowed")
|
||||||
|
|
||||||
|
ErrNotYourResource = errors.New("this resource not yours")
|
||||||
|
ErrPermissionDenied = errors.New("permission denied")
|
||||||
|
)
|
7
internal/consts/model.go
Normal file
7
internal/consts/model.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package consts
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrPageNotFound = errors.New("page not found")
|
||||||
|
)
|
9
internal/consts/rbac.go
Normal file
9
internal/consts/rbac.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package consts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/pkg/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleSuperAdmin user.Role = "super-admin"
|
||||||
|
)
|
7
internal/consts/router.go
Normal file
7
internal/consts/router.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package consts
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInternalServerError = errors.New("there was a server error, but we have logged this request for further investigation")
|
||||||
|
)
|
103
internal/dao/gen.go
Normal file
103
internal/dao/gen.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"gorm.io/gen"
|
||||||
|
|
||||||
|
"gorm.io/plugin/dbresolver"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Q = new(Query)
|
||||||
|
User *user
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
|
||||||
|
*Q = *Use(db, opts...)
|
||||||
|
User = &Q.User
|
||||||
|
}
|
||||||
|
|
||||||
|
func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
|
||||||
|
return &Query{
|
||||||
|
db: db,
|
||||||
|
User: newUser(db, opts...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query struct {
|
||||||
|
db *gorm.DB
|
||||||
|
|
||||||
|
User user
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) Available() bool { return q.db != nil }
|
||||||
|
|
||||||
|
func (q *Query) clone(db *gorm.DB) *Query {
|
||||||
|
return &Query{
|
||||||
|
db: db,
|
||||||
|
User: q.User.clone(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) ReadDB() *Query {
|
||||||
|
return q.ReplaceDB(q.db.Clauses(dbresolver.Read))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) WriteDB() *Query {
|
||||||
|
return q.ReplaceDB(q.db.Clauses(dbresolver.Write))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) ReplaceDB(db *gorm.DB) *Query {
|
||||||
|
return &Query{
|
||||||
|
db: db,
|
||||||
|
User: q.User.replaceDB(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type queryCtx struct {
|
||||||
|
User IUserDo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) WithContext(ctx context.Context) *queryCtx {
|
||||||
|
return &queryCtx{
|
||||||
|
User: q.User.WithContext(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {
|
||||||
|
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {
|
||||||
|
tx := q.db.Begin(opts...)
|
||||||
|
return &QueryTx{Query: q.clone(tx), Error: tx.Error}
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueryTx struct {
|
||||||
|
*Query
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *QueryTx) Commit() error {
|
||||||
|
return q.db.Commit().Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *QueryTx) Rollback() error {
|
||||||
|
return q.db.Rollback().Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *QueryTx) SavePoint(name string) error {
|
||||||
|
return q.db.SavePoint(name).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *QueryTx) RollbackTo(name string) error {
|
||||||
|
return q.db.RollbackTo(name).Error
|
||||||
|
}
|
7
internal/dao/provider.go
Normal file
7
internal/dao/provider.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package dao
|
||||||
|
|
||||||
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
|
func NewQuery(db *gorm.DB) *Query {
|
||||||
|
return Use(db)
|
||||||
|
}
|
392
internal/dao/users.gen.go
Normal file
392
internal/dao/users.gen.go
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
// Code generated by gorm.io/gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
|
||||||
|
"gorm.io/gen"
|
||||||
|
"gorm.io/gen/field"
|
||||||
|
|
||||||
|
"gorm.io/plugin/dbresolver"
|
||||||
|
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/entity"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newUser(db *gorm.DB, opts ...gen.DOOption) user {
|
||||||
|
_user := user{}
|
||||||
|
|
||||||
|
_user.userDo.UseDB(db, opts...)
|
||||||
|
_user.userDo.UseModel(&entity.User{})
|
||||||
|
|
||||||
|
tableName := _user.userDo.TableName()
|
||||||
|
_user.ALL = field.NewAsterisk(tableName)
|
||||||
|
_user.Id = field.NewUint(tableName, "id")
|
||||||
|
_user.CreatedAt = field.NewTime(tableName, "created_at")
|
||||||
|
_user.UpdatedAt = field.NewTime(tableName, "updated_at")
|
||||||
|
_user.Name = field.NewString(tableName, "name")
|
||||||
|
|
||||||
|
_user.fillFieldMap()
|
||||||
|
|
||||||
|
return _user
|
||||||
|
}
|
||||||
|
|
||||||
|
type user struct {
|
||||||
|
userDo
|
||||||
|
|
||||||
|
ALL field.Asterisk
|
||||||
|
Id field.Uint
|
||||||
|
CreatedAt field.Time
|
||||||
|
UpdatedAt field.Time
|
||||||
|
Name field.String
|
||||||
|
|
||||||
|
fieldMap map[string]field.Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u user) Table(newTableName string) *user {
|
||||||
|
u.userDo.UseTable(newTableName)
|
||||||
|
return u.updateTableName(newTableName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u user) As(alias string) *user {
|
||||||
|
u.userDo.DO = *(u.userDo.As(alias).(*gen.DO))
|
||||||
|
return u.updateTableName(alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *user) updateTableName(table string) *user {
|
||||||
|
u.ALL = field.NewAsterisk(table)
|
||||||
|
u.Id = field.NewUint(table, "id")
|
||||||
|
u.CreatedAt = field.NewTime(table, "created_at")
|
||||||
|
u.UpdatedAt = field.NewTime(table, "updated_at")
|
||||||
|
u.Name = field.NewString(table, "name")
|
||||||
|
|
||||||
|
u.fillFieldMap()
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *user) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
|
||||||
|
_f, ok := u.fieldMap[fieldName]
|
||||||
|
if !ok || _f == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
_oe, ok := _f.(field.OrderExpr)
|
||||||
|
return _oe, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *user) fillFieldMap() {
|
||||||
|
u.fieldMap = make(map[string]field.Expr, 4)
|
||||||
|
u.fieldMap["id"] = u.Id
|
||||||
|
u.fieldMap["created_at"] = u.CreatedAt
|
||||||
|
u.fieldMap["updated_at"] = u.UpdatedAt
|
||||||
|
u.fieldMap["name"] = u.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u user) clone(db *gorm.DB) user {
|
||||||
|
u.userDo.ReplaceConnPool(db.Statement.ConnPool)
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u user) replaceDB(db *gorm.DB) user {
|
||||||
|
u.userDo.ReplaceDB(db)
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
type userDo struct{ gen.DO }
|
||||||
|
|
||||||
|
type IUserDo interface {
|
||||||
|
gen.SubQuery
|
||||||
|
Debug() IUserDo
|
||||||
|
WithContext(ctx context.Context) IUserDo
|
||||||
|
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
|
||||||
|
ReplaceDB(db *gorm.DB)
|
||||||
|
ReadDB() IUserDo
|
||||||
|
WriteDB() IUserDo
|
||||||
|
As(alias string) gen.Dao
|
||||||
|
Session(config *gorm.Session) IUserDo
|
||||||
|
Columns(cols ...field.Expr) gen.Columns
|
||||||
|
Clauses(conds ...clause.Expression) IUserDo
|
||||||
|
Not(conds ...gen.Condition) IUserDo
|
||||||
|
Or(conds ...gen.Condition) IUserDo
|
||||||
|
Select(conds ...field.Expr) IUserDo
|
||||||
|
Where(conds ...gen.Condition) IUserDo
|
||||||
|
Order(conds ...field.Expr) IUserDo
|
||||||
|
Distinct(cols ...field.Expr) IUserDo
|
||||||
|
Omit(cols ...field.Expr) IUserDo
|
||||||
|
Join(table schema.Tabler, on ...field.Expr) IUserDo
|
||||||
|
LeftJoin(table schema.Tabler, on ...field.Expr) IUserDo
|
||||||
|
RightJoin(table schema.Tabler, on ...field.Expr) IUserDo
|
||||||
|
Group(cols ...field.Expr) IUserDo
|
||||||
|
Having(conds ...gen.Condition) IUserDo
|
||||||
|
Limit(limit int) IUserDo
|
||||||
|
Offset(offset int) IUserDo
|
||||||
|
Count() (count int64, err error)
|
||||||
|
Scopes(funcs ...func(gen.Dao) gen.Dao) IUserDo
|
||||||
|
Unscoped() IUserDo
|
||||||
|
Create(values ...*entity.User) error
|
||||||
|
CreateInBatches(values []*entity.User, batchSize int) error
|
||||||
|
Save(values ...*entity.User) error
|
||||||
|
First() (*entity.User, error)
|
||||||
|
Take() (*entity.User, error)
|
||||||
|
Last() (*entity.User, error)
|
||||||
|
Find() ([]*entity.User, error)
|
||||||
|
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.User, err error)
|
||||||
|
FindInBatches(result *[]*entity.User, batchSize int, fc func(tx gen.Dao, batch int) error) error
|
||||||
|
Pluck(column field.Expr, dest interface{}) error
|
||||||
|
Delete(...*entity.User) (info gen.ResultInfo, err error)
|
||||||
|
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
|
||||||
|
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
|
||||||
|
Updates(value interface{}) (info gen.ResultInfo, err error)
|
||||||
|
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
|
||||||
|
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
|
||||||
|
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
|
||||||
|
UpdateFrom(q gen.SubQuery) gen.Dao
|
||||||
|
Attrs(attrs ...field.AssignExpr) IUserDo
|
||||||
|
Assign(attrs ...field.AssignExpr) IUserDo
|
||||||
|
Joins(fields ...field.RelationField) IUserDo
|
||||||
|
Preload(fields ...field.RelationField) IUserDo
|
||||||
|
FirstOrInit() (*entity.User, error)
|
||||||
|
FirstOrCreate() (*entity.User, error)
|
||||||
|
FindByPage(offset int, limit int) (result []*entity.User, count int64, err error)
|
||||||
|
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
|
||||||
|
Scan(result interface{}) (err error)
|
||||||
|
Returning(value interface{}, columns ...string) IUserDo
|
||||||
|
UnderlyingDB() *gorm.DB
|
||||||
|
schema.Tabler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Debug() IUserDo {
|
||||||
|
return u.withDO(u.DO.Debug())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) WithContext(ctx context.Context) IUserDo {
|
||||||
|
return u.withDO(u.DO.WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) ReadDB() IUserDo {
|
||||||
|
return u.Clauses(dbresolver.Read)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) WriteDB() IUserDo {
|
||||||
|
return u.Clauses(dbresolver.Write)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Session(config *gorm.Session) IUserDo {
|
||||||
|
return u.withDO(u.DO.Session(config))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Clauses(conds ...clause.Expression) IUserDo {
|
||||||
|
return u.withDO(u.DO.Clauses(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Returning(value interface{}, columns ...string) IUserDo {
|
||||||
|
return u.withDO(u.DO.Returning(value, columns...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Not(conds ...gen.Condition) IUserDo {
|
||||||
|
return u.withDO(u.DO.Not(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Or(conds ...gen.Condition) IUserDo {
|
||||||
|
return u.withDO(u.DO.Or(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Select(conds ...field.Expr) IUserDo {
|
||||||
|
return u.withDO(u.DO.Select(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Where(conds ...gen.Condition) IUserDo {
|
||||||
|
return u.withDO(u.DO.Where(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Order(conds ...field.Expr) IUserDo {
|
||||||
|
return u.withDO(u.DO.Order(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Distinct(cols ...field.Expr) IUserDo {
|
||||||
|
return u.withDO(u.DO.Distinct(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Omit(cols ...field.Expr) IUserDo {
|
||||||
|
return u.withDO(u.DO.Omit(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Join(table schema.Tabler, on ...field.Expr) IUserDo {
|
||||||
|
return u.withDO(u.DO.Join(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) LeftJoin(table schema.Tabler, on ...field.Expr) IUserDo {
|
||||||
|
return u.withDO(u.DO.LeftJoin(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) RightJoin(table schema.Tabler, on ...field.Expr) IUserDo {
|
||||||
|
return u.withDO(u.DO.RightJoin(table, on...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Group(cols ...field.Expr) IUserDo {
|
||||||
|
return u.withDO(u.DO.Group(cols...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Having(conds ...gen.Condition) IUserDo {
|
||||||
|
return u.withDO(u.DO.Having(conds...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Limit(limit int) IUserDo {
|
||||||
|
return u.withDO(u.DO.Limit(limit))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Offset(offset int) IUserDo {
|
||||||
|
return u.withDO(u.DO.Offset(offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IUserDo {
|
||||||
|
return u.withDO(u.DO.Scopes(funcs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Unscoped() IUserDo {
|
||||||
|
return u.withDO(u.DO.Unscoped())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Create(values ...*entity.User) error {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return u.DO.Create(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) CreateInBatches(values []*entity.User, batchSize int) error {
|
||||||
|
return u.DO.CreateInBatches(values, batchSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save : !!! underlying implementation is different with GORM
|
||||||
|
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
|
||||||
|
func (u userDo) Save(values ...*entity.User) error {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return u.DO.Save(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) First() (*entity.User, error) {
|
||||||
|
if result, err := u.DO.First(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*entity.User), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Take() (*entity.User, error) {
|
||||||
|
if result, err := u.DO.Take(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*entity.User), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Last() (*entity.User, error) {
|
||||||
|
if result, err := u.DO.Last(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*entity.User), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Find() ([]*entity.User, error) {
|
||||||
|
result, err := u.DO.Find()
|
||||||
|
return result.([]*entity.User), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*entity.User, err error) {
|
||||||
|
buf := make([]*entity.User, 0, batchSize)
|
||||||
|
err = u.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
|
||||||
|
defer func() { results = append(results, buf...) }()
|
||||||
|
return fc(tx, batch)
|
||||||
|
})
|
||||||
|
return results, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) FindInBatches(result *[]*entity.User, batchSize int, fc func(tx gen.Dao, batch int) error) error {
|
||||||
|
return u.DO.FindInBatches(result, batchSize, fc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Attrs(attrs ...field.AssignExpr) IUserDo {
|
||||||
|
return u.withDO(u.DO.Attrs(attrs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Assign(attrs ...field.AssignExpr) IUserDo {
|
||||||
|
return u.withDO(u.DO.Assign(attrs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Joins(fields ...field.RelationField) IUserDo {
|
||||||
|
for _, _f := range fields {
|
||||||
|
u = *u.withDO(u.DO.Joins(_f))
|
||||||
|
}
|
||||||
|
return &u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Preload(fields ...field.RelationField) IUserDo {
|
||||||
|
for _, _f := range fields {
|
||||||
|
u = *u.withDO(u.DO.Preload(_f))
|
||||||
|
}
|
||||||
|
return &u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) FirstOrInit() (*entity.User, error) {
|
||||||
|
if result, err := u.DO.FirstOrInit(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*entity.User), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) FirstOrCreate() (*entity.User, error) {
|
||||||
|
if result, err := u.DO.FirstOrCreate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return result.(*entity.User), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) FindByPage(offset int, limit int) (result []*entity.User, count int64, err error) {
|
||||||
|
result, err = u.Offset(offset).Limit(limit).Find()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if size := len(result); 0 < limit && 0 < size && size < limit {
|
||||||
|
count = int64(size + offset)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err = u.Offset(-1).Limit(-1).Count()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
|
||||||
|
count, err = u.Count()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = u.Offset(offset).Limit(limit).Scan(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Scan(result interface{}) (err error) {
|
||||||
|
return u.DO.Scan(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u userDo) Delete(models ...*entity.User) (result gen.ResultInfo, err error) {
|
||||||
|
return u.DO.Delete(models)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *userDo) withDO(do gen.Dao) *userDo {
|
||||||
|
u.DO = *do.(*gen.DO)
|
||||||
|
return u
|
||||||
|
}
|
15
internal/database/migrations/1_setup.sql
Normal file
15
internal/database/migrations/1_setup.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
-- +goose Up
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS users
|
||||||
|
(
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
username VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) NOT NULL,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS users;
|
12
internal/database/migrations/init.go
Normal file
12
internal/database/migrations/init.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed *.sql
|
||||||
|
var MigrationFS embed.FS
|
||||||
|
|
||||||
|
var Config *conf.Config
|
15
internal/entity/Model.go
Normal file
15
internal/entity/Model.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Model 是所有 entity 的基类,后期要将所有的 Base 改成这种形式
|
||||||
|
type Model struct {
|
||||||
|
Id schema.EntityId `gorm:"primarykey" json:"id"`
|
||||||
|
CreatedAt time.Time `gorm:"autoUpdateTime:milli" json:"created_at"`
|
||||||
|
UpdatedAt time.Time `gorm:"autoUpdateTime:milli" json:"updated_at"`
|
||||||
|
//DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||||
|
}
|
10
internal/entity/User.go
Normal file
10
internal/entity/User.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Model
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) TableName() string {
|
||||||
|
return "users"
|
||||||
|
}
|
114
internal/pkg/user/user.go
Normal file
114
internal/pkg/user/user.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Token struct {
|
||||||
|
Aud string `json:"aud"`
|
||||||
|
Iss string `json:"iss"`
|
||||||
|
Iat float64 `json:"iat"`
|
||||||
|
Exp float64 `json:"exp"`
|
||||||
|
Sub Id `json:"sub" mapstructure:"-"`
|
||||||
|
Scopes []string `json:"scopes"`
|
||||||
|
Roles []Role `json:"roles,omitempty"`
|
||||||
|
Permissions []Permission `json:"permissions"`
|
||||||
|
Uuid string `json:"uuid"`
|
||||||
|
Avatar string `json:"avatar"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
EmailVerified bool `json:"email_verified"`
|
||||||
|
RealNameVerified bool `json:"real_name_verified"`
|
||||||
|
PhoneVerified bool `json:"phone_verified"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Token Token
|
||||||
|
Id Id
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Role string
|
||||||
|
|
||||||
|
func (r Role) String() string {
|
||||||
|
return string(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Permission string
|
||||||
|
|
||||||
|
type Id string
|
||||||
|
|
||||||
|
func (u *User) GetId() Id {
|
||||||
|
return u.Token.Sub
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetName() string {
|
||||||
|
return u.Token.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetEmail() string {
|
||||||
|
return u.Token.Email
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetPhone() string {
|
||||||
|
return u.Token.Phone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetRoles() []Role {
|
||||||
|
return u.Token.Roles
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetPermissions() []Permission {
|
||||||
|
return u.Token.Permissions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetAvatar() string {
|
||||||
|
return u.Token.Avatar
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetUuid() string {
|
||||||
|
return u.Token.Uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) HasRoles(roles ...Role) bool {
|
||||||
|
if len(roles) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, role := range roles {
|
||||||
|
pass := slices.Contains(u.Token.Roles, role)
|
||||||
|
|
||||||
|
if !pass {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) HasPermissions(permissions ...Permission) bool {
|
||||||
|
if len(permissions) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range permissions {
|
||||||
|
pass := slices.Contains(u.Token.Permissions, p)
|
||||||
|
|
||||||
|
if !pass {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u Id) String() string {
|
||||||
|
return string(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (up Permission) String() string {
|
||||||
|
return string(up)
|
||||||
|
}
|
48
internal/router/api.go
Normal file
48
internal/router/api.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/api/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 两种方法都可以
|
||||||
|
//type Api struct {
|
||||||
|
// User *v1.UserController
|
||||||
|
//}
|
||||||
|
|
||||||
|
type Api struct {
|
||||||
|
HttpHandler *http.Handlers
|
||||||
|
Middleware *http.Middleware
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApiRoute(
|
||||||
|
//User *v1.UserController,
|
||||||
|
HttpHandler *http.Handlers,
|
||||||
|
Middleware *http.Middleware,
|
||||||
|
) *Api {
|
||||||
|
//return &Api{
|
||||||
|
// User,
|
||||||
|
//}
|
||||||
|
|
||||||
|
return &Api{
|
||||||
|
HttpHandler,
|
||||||
|
Middleware,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Api) V1(r fiber.Router) {
|
||||||
|
auth := r.Group("/api/v1")
|
||||||
|
{
|
||||||
|
// 要求认证
|
||||||
|
auth.Use(a.Middleware.Auth.Handler())
|
||||||
|
|
||||||
|
// RoutePermission 为权限验证
|
||||||
|
r.Get("/ping", a.Middleware.RBAC.RoutePermission(), a.HttpHandler.User.Test)
|
||||||
|
}
|
||||||
|
|
||||||
|
guest := r.Group("/api/v1")
|
||||||
|
{
|
||||||
|
guest.Get("/guest_ping", a.HttpHandler.User.Test)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
internal/router/provider.go
Normal file
9
internal/router/provider.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import "github.com/google/wire"
|
||||||
|
|
||||||
|
// Provide is providers.
|
||||||
|
var Provide = wire.NewSet(
|
||||||
|
NewApiRoute,
|
||||||
|
NewSwaggerRoute,
|
||||||
|
)
|
19
internal/router/swagger.go
Normal file
19
internal/router/swagger.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/swagger"
|
||||||
|
_ "leafdev.top/Leaf/leaf-library-3/docs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SwaggerRouter struct {
|
||||||
|
//config *conf.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSwaggerRoute() *SwaggerRouter {
|
||||||
|
return &SwaggerRouter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *SwaggerRouter) Register(r fiber.Router) {
|
||||||
|
r.Get("/swagger/*", swagger.HandlerDefault)
|
||||||
|
}
|
23
internal/schema/entity.go
Normal file
23
internal/schema/entity.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntityId uint
|
||||||
|
|
||||||
|
func (i EntityId) String() string {
|
||||||
|
return strconv.FormatUint(uint64(i), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i EntityId) Uint() uint {
|
||||||
|
return uint(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i EntityId) Uint64() uint64 {
|
||||||
|
return uint64(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i EntityId) Int64() int64 {
|
||||||
|
return int64(i)
|
||||||
|
}
|
12
internal/schema/jwt.go
Normal file
12
internal/schema/jwt.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
type JWTTokenTypes string
|
||||||
|
|
||||||
|
const (
|
||||||
|
JWTAccessToken JWTTokenTypes = "access_token"
|
||||||
|
JWTIDToken JWTTokenTypes = "id_token"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (jwtTokenTypes JWTTokenTypes) String() string {
|
||||||
|
return string(jwtTokenTypes)
|
||||||
|
}
|
22
internal/schema/stream.go
Normal file
22
internal/schema/stream.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
type EventMessage interface {
|
||||||
|
JSON() ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessPostRequest struct {
|
||||||
|
EventMessage
|
||||||
|
PostId string `json:"post_id"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProcessPostRequest) JSON() ([]byte, error) {
|
||||||
|
return json.Marshal(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessPostResult struct {
|
||||||
|
PostId string `json:"post_id"`
|
||||||
|
Keywords []string `json:"keywords"`
|
||||||
|
}
|
11
internal/schema/user_response.go
Normal file
11
internal/schema/user_response.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import "leafdev.top/Leaf/leaf-library-3/internal/pkg/user"
|
||||||
|
|
||||||
|
type CurrentUserResponse struct {
|
||||||
|
IP string `json:"ip"`
|
||||||
|
Valid bool `json:"valid"`
|
||||||
|
UserEmail string `json:"userEmail"`
|
||||||
|
UserId user.Id `json:"userId"`
|
||||||
|
UserName string `json:"userName"`
|
||||||
|
}
|
117
internal/service/auth/auth.go
Normal file
117
internal/service/auth/auth.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/consts"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/pkg/user"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *Service) AuthFromToken(tokenType schema.JWTTokenTypes, token string) (*user.User, error) {
|
||||||
|
if a.config.Debug.Enabled {
|
||||||
|
return a.parseUserJWT(tokenType, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.parseUserJWT(tokenType, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Service) GetUserFromIdToken(idToken string) (*user.User, error) {
|
||||||
|
return a.parseUserJWT(schema.JWTIDToken, idToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Service) GetUser(ctx *fiber.Ctx) *user.User {
|
||||||
|
userCtx := ctx.Locals(consts.AuthMiddlewareKey)
|
||||||
|
|
||||||
|
u, ok := userCtx.(*user.User)
|
||||||
|
u.Id = u.Token.Sub
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
panic("User context is not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Service) GetCtx(ctx context.Context) *user.User {
|
||||||
|
userCtx := ctx.Value(consts.AuthMiddlewareKey)
|
||||||
|
|
||||||
|
u, ok := userCtx.(*user.User)
|
||||||
|
u.Id = u.Token.Sub
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
panic("User context is not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Service) GetUserSafe(ctx *fiber.Ctx) (*user.User, bool) {
|
||||||
|
userCtx := ctx.Locals(consts.AuthMiddlewareKey)
|
||||||
|
|
||||||
|
u, ok := userCtx.(*user.User)
|
||||||
|
u.Id = u.Token.Sub
|
||||||
|
|
||||||
|
return u, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Service) GetCtxSafe(ctx context.Context) (*user.User, bool) {
|
||||||
|
userCtx := ctx.Value(consts.AuthMiddlewareKey)
|
||||||
|
|
||||||
|
u, ok := userCtx.(*user.User)
|
||||||
|
u.Id = u.Token.Sub
|
||||||
|
|
||||||
|
return u, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Service) SetUser(ctx context.Context, user *user.User) context.Context {
|
||||||
|
return context.WithValue(ctx, consts.AuthMiddlewareKey, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Service) parseUserJWT(tokenType schema.JWTTokenTypes, jwtToken string) (*user.User, error) {
|
||||||
|
var sub = consts.AnonymousUser
|
||||||
|
var jwtIdToken = new(user.User)
|
||||||
|
|
||||||
|
if a.config.Debug.Enabled {
|
||||||
|
jwtIdToken.Token.Sub = sub
|
||||||
|
jwtIdToken.Valid = true
|
||||||
|
return jwtIdToken, nil
|
||||||
|
} else {
|
||||||
|
token, err := a.jwks.ParseJWT(jwtToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, consts.ErrNotValidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
subStr, err := token.Claims.GetSubject()
|
||||||
|
if err != nil {
|
||||||
|
return nil, consts.ErrNotValidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
sub = user.Id(subStr)
|
||||||
|
|
||||||
|
// 如果 token.Header 中没有 typ
|
||||||
|
if token.Header["typ"] == "" {
|
||||||
|
return nil, consts.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证 token 类型
|
||||||
|
if tokenType != "" && tokenType.String() != token.Header["typ"] {
|
||||||
|
return nil, consts.ErrTokenError
|
||||||
|
}
|
||||||
|
|
||||||
|
jwtIdToken.Valid = true
|
||||||
|
|
||||||
|
err = mapstructure.Decode(token.Claims, &jwtIdToken.Token)
|
||||||
|
if err != nil {
|
||||||
|
a.logger.Logger.Error("Failed to map token claims to JwtIDToken struct.\nError: " + err.Error())
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动指定,因为 mapstructure 无法转换 UserID 类型
|
||||||
|
jwtIdToken.Token.Sub = sub
|
||||||
|
}
|
||||||
|
|
||||||
|
return jwtIdToken, nil
|
||||||
|
}
|
25
internal/service/auth/provider.go
Normal file
25
internal/service/auth/provider.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/jwks"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
config *conf.Config
|
||||||
|
jwks *jwks.JWKS
|
||||||
|
logger *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(
|
||||||
|
config *conf.Config,
|
||||||
|
jwks *jwks.JWKS,
|
||||||
|
logger *logger.Logger,
|
||||||
|
) *Service {
|
||||||
|
return &Service{
|
||||||
|
config: config,
|
||||||
|
jwks: jwks,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
23
internal/service/jwks/auth_refresh.go
Normal file
23
internal/service/jwks/auth_refresh.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package jwks
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
var refreshRate = 1 * time.Hour
|
||||||
|
|
||||||
|
func (j *JWKS) SetupAuthRefresh() {
|
||||||
|
// 先刷新一次
|
||||||
|
j.RefreshJWKS()
|
||||||
|
var firstRefreshed = true
|
||||||
|
|
||||||
|
// 启动一个定时器
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
if firstRefreshed {
|
||||||
|
firstRefreshed = false
|
||||||
|
} else {
|
||||||
|
j.RefreshJWKS()
|
||||||
|
}
|
||||||
|
time.Sleep(refreshRate)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
58
internal/service/jwks/jwks.go
Normal file
58
internal/service/jwks/jwks.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package jwks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
|
||||||
|
"github.com/MicahParks/keyfunc/v3"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Jwks keyfunc.Keyfunc
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrJWKSNotInitialized = errors.New("JWKS is not initialized")
|
||||||
|
)
|
||||||
|
|
||||||
|
type JWKS struct {
|
||||||
|
url string
|
||||||
|
logger *logger.Logger
|
||||||
|
config *conf.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJWKS(config *conf.Config, logger *logger.Logger) *JWKS {
|
||||||
|
return &JWKS{
|
||||||
|
url: config.JWKS.Url,
|
||||||
|
logger: logger,
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JWKS) RefreshJWKS() {
|
||||||
|
if j.config.Debug.Enabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
j.logger.Logger.Info("Refreshing JWKS...")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
Jwks, err = keyfunc.NewDefault([]string{j.url})
|
||||||
|
if err != nil {
|
||||||
|
j.logger.Logger.Error("Failed to create JWK Set from resource at the given URL.\nError: " + err.Error())
|
||||||
|
} else {
|
||||||
|
j.logger.Logger.Info("JWKS refreshed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JWKS) ParseJWT(jwtB64 string) (*jwt.Token, error) {
|
||||||
|
if Jwks.Keyfunc == nil {
|
||||||
|
return nil, ErrJWKSNotInitialized
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := jwt.Parse(jwtB64, Jwks.Keyfunc)
|
||||||
|
|
||||||
|
return token, err
|
||||||
|
}
|
38
internal/service/provider.go
Normal file
38
internal/service/provider.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/logger"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/auth"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/jwks"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/service/stream"
|
||||||
|
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
logger *logger.Logger
|
||||||
|
Jwks *jwks.JWKS
|
||||||
|
Auth *auth.Service
|
||||||
|
Stream *stream.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
var Provide = wire.NewSet(
|
||||||
|
jwks.NewJWKS,
|
||||||
|
auth.NewService,
|
||||||
|
stream.NewService,
|
||||||
|
NewService,
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewService(
|
||||||
|
logger *logger.Logger,
|
||||||
|
jwks *jwks.JWKS,
|
||||||
|
auth *auth.Service,
|
||||||
|
stream *stream.Service,
|
||||||
|
) *Service {
|
||||||
|
return &Service{
|
||||||
|
logger,
|
||||||
|
jwks,
|
||||||
|
auth,
|
||||||
|
stream,
|
||||||
|
}
|
||||||
|
}
|
68
internal/service/stream/consumer.go
Normal file
68
internal/service/stream/consumer.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/segmentio/kafka-go"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//func (s *Service) Listen(topic string, handler HandlerFunc) error {
|
||||||
|
// conn, err := s.dial(topic)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// batch := conn.ReadBatch(10e3, 1e6) // fetch 10KB min, 1MB max
|
||||||
|
//
|
||||||
|
// b := make([]byte, 10e3) // 10KB max per message
|
||||||
|
// for {
|
||||||
|
// n, err := batch.Read(b)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// handler(b[:n])
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
func (s *Service) Consumer(topic string, groupId string) *kafka.Reader {
|
||||||
|
var r = kafka.ReaderConfig{
|
||||||
|
Brokers: s.config.Kafka.BootstrapServers,
|
||||||
|
GroupID: groupId,
|
||||||
|
GroupTopics: nil,
|
||||||
|
Topic: topic,
|
||||||
|
CommitInterval: time.Second,
|
||||||
|
//StartOffset: kafka., // 仅对新创建的消费者组生效,从头开始消费,工作中可能更常用从最新的开始消费kafka.LastOffset
|
||||||
|
Logger: nil,
|
||||||
|
ErrorLogger: nil,
|
||||||
|
IsolationLevel: 0,
|
||||||
|
MaxAttempts: 0,
|
||||||
|
OffsetOutOfRangeError: false,
|
||||||
|
MaxBytes: 10e6, // 10MB
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.config.Kafka.Username != "" && s.config.Kafka.Password != "" {
|
||||||
|
r.Dialer = &kafka.Dialer{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
DualStack: true,
|
||||||
|
SASLMechanism: s.auth(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return kafka.NewReader(r)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type HandlerFunc func([]byte)
|
||||||
|
|
||||||
|
// ReadMessage 消费消息
|
||||||
|
func (s *Service) ReadMessage(ctx context.Context, topic string, groupId string) {
|
||||||
|
for {
|
||||||
|
if msg, err := s.Consumer(topic, groupId).ReadMessage(ctx); err != nil {
|
||||||
|
fmt.Println(fmt.Sprintf("读kafka失败,err:%v", err))
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
fmt.Println(fmt.Sprintf("topic=%s,partition=%d,offset=%d,key=%s,value=%s", msg.Topic, msg.Partition, msg.Offset, msg.Key, msg.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
internal/service/stream/kafka.go
Normal file
13
internal/service/stream/kafka.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/segmentio/kafka-go/sasl/plain"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) auth() plain.Mechanism {
|
||||||
|
mechanism := plain.Mechanism{
|
||||||
|
Username: s.config.Kafka.Username,
|
||||||
|
Password: s.config.Kafka.Password,
|
||||||
|
}
|
||||||
|
return mechanism
|
||||||
|
}
|
120
internal/service/stream/producer.go
Normal file
120
internal/service/stream/producer.go
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
package stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/segmentio/kafka-go"
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
//var connections = map[string]*kafka.Conn{}
|
||||||
|
|
||||||
|
//func (s *Service) dial(topic string) (*kafka.Conn, error) {
|
||||||
|
//
|
||||||
|
// // 如果topic 存在于 connections 则直接返回
|
||||||
|
// if conn, ok := connections[topic]; ok {
|
||||||
|
// return conn, nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ctx := context.Background()
|
||||||
|
//
|
||||||
|
// conn, err := kafka.DialLeader(ctx, "tcp", s.config.Kafka.BootstrapServers[0], s.topic(topic), 0)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// //err = conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
||||||
|
// //if err != nil {
|
||||||
|
// // return conn, err
|
||||||
|
// //}
|
||||||
|
// //
|
||||||
|
// //// set read deadline
|
||||||
|
// //err = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
|
||||||
|
// //if err != nil {
|
||||||
|
// // return conn, err
|
||||||
|
// //}
|
||||||
|
//
|
||||||
|
// connections[topic] = conn
|
||||||
|
//
|
||||||
|
// return conn, nil
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (s *Service) Publish(topic string, message ...[]byte) error {
|
||||||
|
// conn, err := s.dial(topic)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// msg := make([]kafka.Message, len(message))
|
||||||
|
// for i, v := range message {
|
||||||
|
// msg[i] = kafka.Message{Value: v}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// _, err = conn.WriteMessages(msg...)
|
||||||
|
//
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
|
||||||
|
func (s *Service) Producer(topic string) *kafka.Writer {
|
||||||
|
var w = &kafka.Writer{
|
||||||
|
Addr: kafka.TCP(s.config.Kafka.BootstrapServers...),
|
||||||
|
Topic: topic,
|
||||||
|
Balancer: &kafka.Hash{}, // 用于对key进行hash,决定消息发送到哪个分区
|
||||||
|
MaxAttempts: 0,
|
||||||
|
WriteBackoffMin: 0,
|
||||||
|
WriteBackoffMax: 0,
|
||||||
|
BatchSize: 0,
|
||||||
|
BatchBytes: 0,
|
||||||
|
BatchTimeout: 0,
|
||||||
|
ReadTimeout: 0,
|
||||||
|
//WriteTimeout: time.Second, // kafka有时候可能负载很高,写不进去,那么超时后可以放弃写入,用于可以丢消息的场景
|
||||||
|
RequiredAcks: kafka.RequireAll, // 不需要任何节点确认就返回
|
||||||
|
Async: true,
|
||||||
|
Completion: nil,
|
||||||
|
Compression: 0,
|
||||||
|
Logger: nil,
|
||||||
|
ErrorLogger: nil,
|
||||||
|
Transport: nil,
|
||||||
|
AllowAutoTopicCreation: false, // 第一次发消息的时候,如果topic不存在,就自动创建topic,工作中禁止使用
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.config.Kafka.Username != "" && s.config.Kafka.Password != "" {
|
||||||
|
w.Transport = &kafka.Transport{
|
||||||
|
SASL: s.auth(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) SendMessage(ctx context.Context, topic string, data []byte) error {
|
||||||
|
msg := kafka.Message{
|
||||||
|
Partition: 0,
|
||||||
|
Offset: 0,
|
||||||
|
HighWaterMark: 0,
|
||||||
|
//Key: key,
|
||||||
|
Value: data,
|
||||||
|
Time: time.Time{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.Producer(topic).WriteMessages(ctx, msg)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) SendEvent(ctx context.Context, topic string, data schema.EventMessage) error {
|
||||||
|
j, err := data.JSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := kafka.Message{
|
||||||
|
Partition: 0,
|
||||||
|
Offset: 0,
|
||||||
|
HighWaterMark: 0,
|
||||||
|
Value: j,
|
||||||
|
Time: time.Time{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.Producer(topic).WriteMessages(ctx, msg)
|
||||||
|
return err
|
||||||
|
}
|
15
internal/service/stream/provider.go
Normal file
15
internal/service/stream/provider.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package stream
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/internal/base/conf"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
config *conf.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(config *conf.Config) *Service {
|
||||||
|
return &Service{
|
||||||
|
config,
|
||||||
|
}
|
||||||
|
}
|
18
main.go
Normal file
18
main.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"leafdev.top/Leaf/leaf-library-3/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @title API Docs
|
||||||
|
// @version 1.0
|
||||||
|
// @securityDefinitions.apikey ApiKeyAuth
|
||||||
|
// @in header
|
||||||
|
// @name Authorization
|
||||||
|
func main() {
|
||||||
|
err := cmd.RootCmd.Execute()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
17
proto/api/v1/document_service.proto
Normal file
17
proto/api/v1/document_service.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package template.document;
|
||||||
|
|
||||||
|
option go_package = "gen/api/v1";
|
||||||
|
|
||||||
|
service DocumentService {
|
||||||
|
rpc ListDocuments(ListDocumentsRequest) returns (ListDocumentsResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListDocumentsRequest {
|
||||||
|
string Message = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListDocumentsResponse {
|
||||||
|
string Message = 1;
|
||||||
|
}
|
57
proto/gen/apidocs.swagger.json
Normal file
57
proto/gen/apidocs.swagger.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"swagger": "2.0",
|
||||||
|
"info": {
|
||||||
|
"title": "proto/api/v1/document_service.proto",
|
||||||
|
"version": "version not set"
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"name": "DocumentService"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"paths": {},
|
||||||
|
"definitions": {
|
||||||
|
"documentListDocumentsResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"protobufAny": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"@type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": {}
|
||||||
|
},
|
||||||
|
"rpcStatus": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/protobufAny"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
217
proto/gen/proto/api/v1/document_service.pb.go
Normal file
217
proto/gen/proto/api/v1/document_service.pb.go
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.34.2
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: proto/api/v1/document_service.proto
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListDocumentsRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Message string `protobuf:"bytes,1,opt,name=Message,proto3" json:"Message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListDocumentsRequest) Reset() {
|
||||||
|
*x = ListDocumentsRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_proto_api_v1_document_service_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListDocumentsRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ListDocumentsRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ListDocumentsRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_api_v1_document_service_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ListDocumentsRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ListDocumentsRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_api_v1_document_service_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListDocumentsRequest) GetMessage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Message
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListDocumentsResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Message string `protobuf:"bytes,1,opt,name=Message,proto3" json:"Message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListDocumentsResponse) Reset() {
|
||||||
|
*x = ListDocumentsResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_proto_api_v1_document_service_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListDocumentsResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ListDocumentsResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ListDocumentsResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_proto_api_v1_document_service_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ListDocumentsResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ListDocumentsResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_proto_api_v1_document_service_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListDocumentsResponse) GetMessage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Message
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_proto_api_v1_document_service_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_proto_api_v1_document_service_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x23, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x64,
|
||||||
|
0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e,
|
||||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e,
|
||||||
|
0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x30, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74,
|
||||||
|
0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
|
0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
|
0x09, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x31, 0x0a, 0x15, 0x4c, 0x69,
|
||||||
|
0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
|
0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x75, 0x0a,
|
||||||
|
0x0f, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||||
|
0x12, 0x62, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
|
||||||
|
0x73, 0x12, 0x27, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x64, 0x6f, 0x63,
|
||||||
|
0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65,
|
||||||
|
0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x65, 0x6d,
|
||||||
|
0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x4c,
|
||||||
|
0x69, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||||
|
0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0c, 0x5a, 0x0a, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f,
|
||||||
|
0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_proto_api_v1_document_service_proto_rawDescOnce sync.Once
|
||||||
|
file_proto_api_v1_document_service_proto_rawDescData = file_proto_api_v1_document_service_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_proto_api_v1_document_service_proto_rawDescGZIP() []byte {
|
||||||
|
file_proto_api_v1_document_service_proto_rawDescOnce.Do(func() {
|
||||||
|
file_proto_api_v1_document_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_api_v1_document_service_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_proto_api_v1_document_service_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_proto_api_v1_document_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
|
var file_proto_api_v1_document_service_proto_goTypes = []any{
|
||||||
|
(*ListDocumentsRequest)(nil), // 0: template.document.ListDocumentsRequest
|
||||||
|
(*ListDocumentsResponse)(nil), // 1: template.document.ListDocumentsResponse
|
||||||
|
}
|
||||||
|
var file_proto_api_v1_document_service_proto_depIdxs = []int32{
|
||||||
|
0, // 0: template.document.DocumentService.ListDocuments:input_type -> template.document.ListDocumentsRequest
|
||||||
|
1, // 1: template.document.DocumentService.ListDocuments:output_type -> template.document.ListDocumentsResponse
|
||||||
|
1, // [1:2] is the sub-list for method output_type
|
||||||
|
0, // [0:1] is the sub-list for method input_type
|
||||||
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
|
0, // [0:0] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_proto_api_v1_document_service_proto_init() }
|
||||||
|
func file_proto_api_v1_document_service_proto_init() {
|
||||||
|
if File_proto_api_v1_document_service_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_proto_api_v1_document_service_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*ListDocumentsRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_proto_api_v1_document_service_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*ListDocumentsResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_proto_api_v1_document_service_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 2,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_proto_api_v1_document_service_proto_goTypes,
|
||||||
|
DependencyIndexes: file_proto_api_v1_document_service_proto_depIdxs,
|
||||||
|
MessageInfos: file_proto_api_v1_document_service_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_proto_api_v1_document_service_proto = out.File
|
||||||
|
file_proto_api_v1_document_service_proto_rawDesc = nil
|
||||||
|
file_proto_api_v1_document_service_proto_goTypes = nil
|
||||||
|
file_proto_api_v1_document_service_proto_depIdxs = nil
|
||||||
|
}
|
164
proto/gen/proto/api/v1/document_service.pb.gw.go
Normal file
164
proto/gen/proto/api/v1/document_service.pb.gw.go
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||||
|
// source: proto/api/v1/document_service.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package v1 is a reverse proxy.
|
||||||
|
|
||||||
|
It translates gRPC into RESTful JSON APIs.
|
||||||
|
*/
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||||
|
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/grpclog"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Suppress "imported and not used" errors
|
||||||
|
var _ codes.Code
|
||||||
|
var _ io.Reader
|
||||||
|
var _ status.Status
|
||||||
|
var _ = runtime.String
|
||||||
|
var _ = utilities.NewDoubleArray
|
||||||
|
var _ = metadata.Join
|
||||||
|
|
||||||
|
func request_DocumentService_ListDocuments_0(ctx context.Context, marshaler runtime.Marshaler, client DocumentServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq ListDocumentsRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.ListDocuments(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_DocumentService_ListDocuments_0(ctx context.Context, marshaler runtime.Marshaler, server DocumentServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq ListDocumentsRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.ListDocuments(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterDocumentServiceHandlerServer registers the http handlers for service DocumentService to "mux".
|
||||||
|
// UnaryRPC :call DocumentServiceServer directly.
|
||||||
|
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||||
|
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterDocumentServiceHandlerFromEndpoint instead.
|
||||||
|
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
|
||||||
|
func RegisterDocumentServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server DocumentServiceServer) error {
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_DocumentService_ListDocuments_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
var stream runtime.ServerTransportStream
|
||||||
|
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/template.document.DocumentService/ListDocuments", runtime.WithHTTPPathPattern("/template.document.DocumentService/ListDocuments"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_DocumentService_ListDocuments_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_DocumentService_ListDocuments_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterDocumentServiceHandlerFromEndpoint is same as RegisterDocumentServiceHandler but
|
||||||
|
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||||
|
func RegisterDocumentServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||||
|
conn, err := grpc.NewClient(endpoint, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
if cerr := conn.Close(); cerr != nil {
|
||||||
|
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
if cerr := conn.Close(); cerr != nil {
|
||||||
|
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return RegisterDocumentServiceHandler(ctx, mux, conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterDocumentServiceHandler registers the http handlers for service DocumentService to "mux".
|
||||||
|
// The handlers forward requests to the grpc endpoint over "conn".
|
||||||
|
func RegisterDocumentServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||||
|
return RegisterDocumentServiceHandlerClient(ctx, mux, NewDocumentServiceClient(conn))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterDocumentServiceHandlerClient registers the http handlers for service DocumentService
|
||||||
|
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "DocumentServiceClient".
|
||||||
|
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "DocumentServiceClient"
|
||||||
|
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||||
|
// "DocumentServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares.
|
||||||
|
func RegisterDocumentServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client DocumentServiceClient) error {
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_DocumentService_ListDocuments_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/template.document.DocumentService/ListDocuments", runtime.WithHTTPPathPattern("/template.document.DocumentService/ListDocuments"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_DocumentService_ListDocuments_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_DocumentService_ListDocuments_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pattern_DocumentService_ListDocuments_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"template.document.DocumentService", "ListDocuments"}, ""))
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
forward_DocumentService_ListDocuments_0 = runtime.ForwardResponseMessage
|
||||||
|
)
|
121
proto/gen/proto/api/v1/document_service_grpc.pb.go
Normal file
121
proto/gen/proto/api/v1/document_service_grpc.pb.go
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
|
// - protoc (unknown)
|
||||||
|
// source: proto/api/v1/document_service.proto
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.64.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion9
|
||||||
|
|
||||||
|
const (
|
||||||
|
DocumentService_ListDocuments_FullMethodName = "/template.document.DocumentService/ListDocuments"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DocumentServiceClient is the client API for DocumentService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type DocumentServiceClient interface {
|
||||||
|
ListDocuments(ctx context.Context, in *ListDocumentsRequest, opts ...grpc.CallOption) (*ListDocumentsResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type documentServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDocumentServiceClient(cc grpc.ClientConnInterface) DocumentServiceClient {
|
||||||
|
return &documentServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *documentServiceClient) ListDocuments(ctx context.Context, in *ListDocumentsRequest, opts ...grpc.CallOption) (*ListDocumentsResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(ListDocumentsResponse)
|
||||||
|
err := c.cc.Invoke(ctx, DocumentService_ListDocuments_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocumentServiceServer is the server API for DocumentService service.
|
||||||
|
// All implementations must embed UnimplementedDocumentServiceServer
|
||||||
|
// for forward compatibility.
|
||||||
|
type DocumentServiceServer interface {
|
||||||
|
ListDocuments(context.Context, *ListDocumentsRequest) (*ListDocumentsResponse, error)
|
||||||
|
mustEmbedUnimplementedDocumentServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedDocumentServiceServer must be embedded to have
|
||||||
|
// forward compatible implementations.
|
||||||
|
//
|
||||||
|
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||||
|
// pointer dereference when methods are called.
|
||||||
|
type UnimplementedDocumentServiceServer struct{}
|
||||||
|
|
||||||
|
func (UnimplementedDocumentServiceServer) ListDocuments(context.Context, *ListDocumentsRequest) (*ListDocumentsResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method ListDocuments not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedDocumentServiceServer) mustEmbedUnimplementedDocumentServiceServer() {}
|
||||||
|
func (UnimplementedDocumentServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
|
// UnsafeDocumentServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to DocumentServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeDocumentServiceServer interface {
|
||||||
|
mustEmbedUnimplementedDocumentServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterDocumentServiceServer(s grpc.ServiceRegistrar, srv DocumentServiceServer) {
|
||||||
|
// If the following call pancis, it indicates UnimplementedDocumentServiceServer was
|
||||||
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||||
|
t.testEmbeddedByValue()
|
||||||
|
}
|
||||||
|
s.RegisterService(&DocumentService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _DocumentService_ListDocuments_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ListDocumentsRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(DocumentServiceServer).ListDocuments(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: DocumentService_ListDocuments_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(DocumentServiceServer).ListDocuments(ctx, req.(*ListDocumentsRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocumentService_ServiceDesc is the grpc.ServiceDesc for DocumentService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var DocumentService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "template.document.DocumentService",
|
||||||
|
HandlerType: (*DocumentServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "ListDocuments",
|
||||||
|
Handler: _DocumentService_ListDocuments_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "proto/api/v1/document_service.proto",
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user