From 62a0c59639aedd47588fa4d2be759a0487eba92d Mon Sep 17 00:00:00 2001 From: Roman Glushko Date: Mon, 12 Feb 2024 23:01:26 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6=20v0.0.2-rc.1=20(#143)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Features - ✨ #117 Allow to load dotenv files (@roma-glushko) ### Improvements - βœ¨πŸ‘· #91 Support for Windows (@roma-glushko) - πŸ‘· #139 Build Glide for OpenBSD and ppc65le, s390x, riscv64 architectures (@roma-glushko) ### Miscellaneous - πŸ‘· #92 Release binaries to Snapcraft (@roma-glushko) - πŸ‘· #123 publish images to DockerHub (@roma-glushko) - πŸ”§ #136 Migrated all API to Fiber (@roma-glushko) - πŸ‘· #139 Create a image tag with pure version (without distro suffix) (@roma-glushko) --- .env.sample | 1 + .github/workflows/release.yaml | 15 ++ .goreleaser.yml | 112 ++++++++- CHANGELOG.md | 18 ++ CONTRIBUTING.md | 75 ++++++ README.md | 37 ++- ROADMAP.md | 27 ++- config.dev.yaml | 9 +- go.mod | 51 ++-- go.sum | 291 ++++++++++++++--------- images/Makefile | 19 ++ leak_test.go | 12 +- pkg/api/http/config.go | 43 ++-- pkg/api/http/handlers.go | 57 ++--- pkg/api/http/server.go | 53 +++-- pkg/api/servers.go | 10 +- pkg/cmd/cli.go | 30 ++- pkg/config/expander.go | 1 + pkg/config/provider.go | 6 + pkg/gateway.go | 8 +- pkg/providers/anthropic/client_test.go | 3 +- pkg/providers/azureopenai/client_test.go | 5 +- pkg/providers/cohere/client_test.go | 1 + pkg/providers/octoml/client_test.go | 5 +- pkg/providers/openai/client_test.go | 1 + pkg/routers/config.go | 15 +- pkg/routers/config_test.go | 4 +- pkg/routers/health/error_budget.go | 5 +- pkg/telemetry/logging.go | 34 --- pkg/{ => version}/version.go | 8 +- 30 files changed, 658 insertions(+), 298 deletions(-) create mode 100644 .env.sample create mode 100644 CONTRIBUTING.md rename pkg/{ => version}/version.go (80%) diff --git a/.env.sample b/.env.sample new file mode 100644 index 00000000..e570b8b5 --- /dev/null +++ b/.env.sample @@ -0,0 +1 @@ +OPENAI_API_KEY= diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 93f56cdb..ed5231b5 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -33,6 +33,13 @@ jobs: with: fetch-depth: 0 + - name: Snapcraft Setup + run: | + sudo apt-get update + sudo apt-get -yq --no-install-suggests --no-install-recommends install snapcraft + mkdir -p $HOME/.cache/snapcraft/download + mkdir -p $HOME/.cache/snapcraft/stage-packages + - name: Run GoReleaser uses: goreleaser/goreleaser-action@v5 with: @@ -41,6 +48,7 @@ jobs: args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_TOKEN }} DISCORD_WEBHOOK_ID: ${{ secrets.DISCORD_WEBHOOK_ID }} DISCORD_WEBHOOK_TOKEN: ${{ secrets.DISCORD_WEBHOOK_TOKEN }} BREW_TAP_PRIVATE_KEY: ${{ secrets.BREW_TAP_PRIVATE_KEY }} @@ -64,6 +72,9 @@ jobs: - name: login into Github Container Registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin + - name: login into Github Container Registry + run: echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u einstack $ --password-stdin + - name: build ${{ matrix.image }} image working-directory: ./images env: @@ -73,3 +84,7 @@ jobs: - name: publish ${{ matrix.image }} image to Github Container Registry working-directory: ./images run: VERSION=${{ github.ref_name }} make publish-ghcr-${{ matrix.image }} + + - name: publish ${{ matrix.image }} image to Github Container Registry + working-directory: ./images + run: VERSION=${{ github.ref_name }} make publish-docherhub-${{ matrix.image }} diff --git a/.goreleaser.yml b/.goreleaser.yml index 903cdba5..653e3a27 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -14,14 +14,21 @@ builds: - linux - darwin - freebsd + - openbsd + - windows goarch: - amd64 - arm - arm64 + - ppc64le + - s390x + - riscv64 goarm: - '7' - '6' ignore: + - goos: darwin + goarch: '386' - goos: openbsd goarch: arm - goos: openbsd @@ -30,7 +37,7 @@ builds: goarch: arm - goos: freebsd goarch: arm64 - - goos: linux + - goos: windows goarch: arm changelog: @@ -45,6 +52,8 @@ archives: format: zip files: - LICENSE + - CHANGELOG.md + - ROADMAP.md checksum: name_template: "{{ .ProjectName }}_v{{ .Version }}_checksums.txt" @@ -221,6 +230,107 @@ brews: url: 'git@github.com:EinStack/homebrew-tap.git' private_key: '{{ .Env.BREW_TAP_PRIVATE_KEY }}' +snapcrafts: + - # + # ID of the snapcraft config, must be unique. + # + # Default: 'default' + id: glide + + # Build IDs for the builds you want to create snapcraft packages for. + builds: + - glide + + # You can change the name of the package. + # + # Default: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}' + # Templates: allowed + name_template: '{{ .ProjectName }}_v{{ .Tag }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' + + # The name of the snap. This is optional. + # + # Default: ProjectName + name: glide + + # The canonical title of the application, displayed in the software + # centre graphical frontends. + # + # Since: v1.19 + title: Glide + + # Whether to publish the snap to the snapcraft store. + # Remember you need to `snapcraft login` first. + publish: true + + # Single-line elevator pitch for your amazing snap. + # 79 char long at most. + summary: A open simple blazing-fast model gateway + + # This the description of your snap. You have a paragraph or two to tell the + # most important story about your snap. Keep it under 100 words though, + # we live in tweetspace and your description wants to look good in the snap + # store. + description: A open simple blazing-fast model gateway for rapid development of production GenAI apps + + # Channels in store where snap will be pushed. + # + # More info about channels here: + # https://snapcraft.io/docs/reference/channels + # + # Default: + # grade is 'stable': ["edge", "beta", "candidate", "stable"] + # grade is 'devel': ["edge", "beta"] + # Templates: allowed (since v1.15) + channel_templates: + - edge + - beta + - candidate + - stable + + # A guardrail to prevent you from releasing a snap to all your users before + # it is ready. + # `devel` will let you release only to the `edge` and `beta` channels in the + # store. `stable` will let you release also to the `candidate` and `stable` + # channels. + grade: stable + + # Snaps can be setup to follow three different confinement policies: + # `strict`, `devmode` and `classic`. A strict confinement where the snap + # can only read and write in its own namespace is recommended. Extra + # permissions for strict snaps can be declared as `plugs` for the app, which + # are explained later. More info about confinement here: + # https://snapcraft.io/docs/reference/confinement + confinement: strict + + # Your app's license, based on SPDX license expressions: + # https://spdx.org/licenses + license: Apache-2.0 + + # A snap of type base to be used as the execution environment for this snap. + # Valid values are: + # * bare - Empty base snap; + # * core - Ubuntu Core 16; + # * core18 - Ubuntu Core 18. + base: core20 + + # A list of features that must be supported by the core in order for + # this snap to install. + # + # Since: v1.19 + assumes: + - snapd2.38 + + # Each binary built by GoReleaser is an app inside the snap. In this section + # you can declare extra details for those binaries. It is optional. + # See: https://snapcraft.io/docs/snapcraft-app-and-service-metadata + apps: + # The name of the app must be the same name as the binary built or the snapcraft name. + glide: + # You can override the command name. + # + # Default: AppName + command: glide + announce: discord: # Whether its enabled or not. diff --git a/CHANGELOG.md b/CHANGELOG.md index e596df47..48a393dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,24 @@ The changelog consists of three categories: - **Improvements** - bugfixes, performance and other types of improvements to existing functionality - **Miscellaneous** - all other updates like build, release, CLI, etc. +## 0.0.2-rc.1 (Feb 12th, 2024) + +### Features + +- ✨#117 Allow to load dotenv files (@roma-glushko) + +### Improvements + +- βœ¨πŸ‘·#91 Support for Windows (@roma-glushko) +- πŸ‘· #139 Build Glide for OpenBSD and ppc65le, s390x, riscv64 architectures (@roma-glushko) + +### Miscellaneous + +- πŸ‘· #92 Release binaries to Snapcraft (@roma-glushko) +- πŸ‘· #123 publish images to DockerHub (@roma-glushko) +- πŸ”§ #136 Migrated all API to Fiber (@roma-glushko) +- πŸ‘· #139 Create a image tag with pure version (without distro suffix) (@roma-glushko) + ## 0.0.1 (Jan 31st, 2024) ### Features diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..2735b5e4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,75 @@ +# Contribution Guide + +First off, we are super excited that you are willing to improve Glide πŸ™Œ + +There are three areas to contribute: + +- **Technical**: Help us to improve existing functionality, fix bugs, and bring on new features both to Glide and related repositories like Python SDK. +- **Documentation**: Improve documentation content, uncover undocumented features & gotchas, write guides and walkthroughs. +- **Vision**: Help us to uncover use cases where Glide could have helped that might be useful for a broader set of people + +--- + +## Technical Contribution + +### Communication & Coordination + +We value your time. +To make your onboarding as smooth as possible while reducing amount of back and forth, +we coordinate and communicate in [the EinStack's Discord space](https://discord.gg/rsBzprY7uT) before jumping on anything major. + +Overcommunication is the key to solving many problems. + +### GEPs + +We are using [enhancement proposals](https://github.com/EinStack/geps) to +define bigger problems and suggest our solutions to them. + +The enhancement proposals share your ideas on solving the problem and let other people give a feedback, +identify areas to investigate, brainstorm alternatives. + +To start a new GEP, you don't have to know all the answers to all questions. +You can outline gaps and let other people contribute their ideas on possible solutions. + +### Dev Commands + +Many useful commands are in [the root makefile](Makefile). +We use make as a convenient interface to automate a bunch of commands like codebase linting, running tests, running dev binary, etc. +Be sure to take a look at all available commands. + +### CI Checks + +All important checks are automated on the level of pull request checks. +Be sure to keep your PRs green, before moving the PR to the review stage. + +## Improve Our Documentation + +### Typos & Uncovered Functionality + +If you spot a typo or incorrect information, please do use the `raise issue` or `suggest edits` functionality directly on the documentation page. + +If you see some uncovered functionality, please fill briefly [a Github issue](https://github.com/EinStack/docs/issues). + +### Guides + +A special place takes our guides. Guide is a walkthrough that solves a concrete use case or problem step by step. + +To inspire our end users and illustrate the true capabilities of Glide, we want to grow the number of guides. + +If you have any specific use cases to cover, please do let us know in [Discord](https://discord.gg/rsBzprY7uT) or [our docs repo](https://github.com/EinStack/docs) (even if you don't have a chance to work on that). + +## Expand Our Vision + +If you feel like we have overlooked +some useful functionality or features that would be great to have, +feel free to create a new discussion in [our Github Discussions](https://github.com/EinStack/glide/discussions/categories/ideas). + +We will review and discuss all ideas and will try to fit them into [the Glide's roadmap](ROADMAP.md). + +## Don't want to contribute but uses Glide + +That's perfectly fine! + +Feel free to connect with us in [Discord](https://discord.gg/rsBzprY7uT) and ask any question you have. +Remember, there are no dumb questions, but there can be missing opportunities to make your life easier if you don't speak up about things you struggle with. + diff --git a/README.md b/README.md index 7b7572ef..d35e914a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Check out our [documentation](https://glide.einstack.ai)! - **High availability** and **resiliency** when working with external model providers. Automatic **fallbacks** on provider failures, rate limits, transient errors. Smart retries to reduce communication latency. - Support **popular LLM providers**. - **High performance**. Performance is our priority. We want to keep Glide "invisible" for your latency-wise, while providing rich functionality. -- **Production-ready observability** via OpenTelemetry, emit metrics on models health, allows whitebox monitoring. +- **Production-ready observability** via OpenTelemetry, emit metrics on models health, allows whitebox monitoring (coming soon) - Straightforward and simple maintenance and configuration, centralized API key control & management & rotation, etc. ## Supported Providers @@ -72,6 +72,9 @@ Detailed info on routers can be found [here](https://glide.einstack.ai/essential ### Installation +> [!Note] +> Windows users should follow an instruction right from [the demo README file](https://github.com/EinStack/glide-demo) that specifies how to do the steps without the `make` command as Windows doesn't come with it by default. + The easiest way to deploy Glide is to our [demo repository](https://github.com/EinStack/glide-demo.git) and [docker-compose](https://docs.docker.com/compose/). ### 1. Clone the demo repository @@ -120,7 +123,7 @@ See [API Reference](https://glide.einstack.ai/api-reference/introduction) for mo ### API Docs -Finally, Glide comes with OpenAPI documentation that is accessible via http://127.0.0.1:9099/v1/swagger/index.html +Finally, Glide comes with OpenAPI documentation that is accessible via http://127.0.0.1:9099/v1/swagger That's it πŸ™Œ @@ -139,11 +142,37 @@ brew install einstack/tap/glide ### Snapcraft (Linux) -Coming Soon +[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-white.svg)](https://snapcraft.io/glide) + +```bash +snap install glide +``` + +To upgrade the already installed package, you just need to run: + +```bash +snap refresh glide +``` + +Detailed instruction on Snapcraft installation for different Linux distos: + +- [Arch](https://snapcraft.io/install/glide/arch) +- [CentOS](https://snapcraft.io/install/glide/centos) +- [Debian](https://snapcraft.io/install/glide/debian) +- [elementaryOS](https://snapcraft.io/install/glide/elementary) +- [Fedora](https://snapcraft.io/install/glide/fedora) +- [KDE Neon](https://snapcraft.io/install/glide/kde-neon) +- [Kubuntu](https://snapcraft.io/install/glide/kubuntu) +- [Manjaro](https://snapcraft.io/install/glide/manjaro) +- [Pop! OS](https://snapcraft.io/install/glide/pop) +- [openSUSE](https://snapcraft.io/install/glide/opensuse) +- [RHEL](https://snapcraft.io/install/glide/rhel) +- [Ubuntu](https://snapcraft.io/install/glide/ubuntu) +- [Raspberry Pi](https://snapcraft.io/install/glide/raspbian) ### Docker Images -Glide provides official images in our [GHCR](https://github.com/EinStack/glide/pkgs/container/glide): +Glide provides official images in our [GHCR](https://github.com/EinStack/glide/pkgs/container/glide) & [DockerHub](https://hub.docker.com/u/einstack ): - Alpine 3.19: ```bash diff --git a/ROADMAP.md b/ROADMAP.md index facda76a..2de24477 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,16 +1,16 @@ -*Updated: Fri, 12 Jan 2024* +*Updated: Wed, Jan 31st, 2024* # Glide - Roadmap -This document describes the current status and the upcoming milestones of the Glide LLM Router. +This document describes the current status and the upcoming milestones of the Glide gateway. ## Glide -#### Milestone Summary +### Milestone Summary | Status | Milestone | Goals | | :---: | :--- | :---: | -| 🍏 | **Unified Chat Endpoint Support** | 4 / 4 | +| 🍏 | **Unified Chat API** | 4 / 4 | | 🍏 | **Fallback Routing Strategy** | 1 / 1 | | 🍏 | **Priority, Round Robin, Weighted Round Robin, Least Latency** | 4 / 4 | | 🍏 | **Documentation** | 1 / 1 | @@ -24,30 +24,33 @@ This document describes the current status and the upcoming milestones of the Gl | 🍎 | **Intelligent Routing** | 0 / 1 | | 🍎 | **General Availability Routing** | 0 / 1 | -### Private Preview +### Private Preview βœ… ([v0.0.1](https://github.com/EinStack/glide/releases/tag/0.0.1)) - Unified LLM Chat REST API - Support for most popular LLM providers - Seamless model fallbacking - Routing Strategies: Priority, Round Robin, Weighted Round Robin, Least Latency -### Public Preview -- Embeddings -- Steaming -- Intelligent Routing +### Public Preview (In Progress) + +- Unified Embeddings API +- Unified Steaming Chat API +- Observability +- The Exact Caching +- Intelligent Routing (?) ### General Availability +- Kubernetes Insallation (Helm Chart) - Python SDK - Speech-to-text & Text-to-speech models -- Exact & Semantic Caching +- The Semantic Caching ### Future - Cost Management & Budgeting - Safety & Control Over Inputs & Outputs - - and many more! -Open [an issue](https://github.com/modelgateway/glide/issues) or start [a discussion](https://github.com/modelgateway/glide/discussions) +Open [an issue](https://github.com/EinStack/glide/issues) or start [a discussion](https://github.com/EinStack/glide/discussions) if there is a feature or an enhancement you'd like to see in Glide. diff --git a/config.dev.yaml b/config.dev.yaml index ec07d594..80c77a5b 100644 --- a/config.dev.yaml +++ b/config.dev.yaml @@ -5,13 +5,8 @@ telemetry: routers: language: - - id: myrouter + - id: default models: - id: openai openai: - api_key: "" - - id: azureopenai - azureopenai: - api_key: "" - model: "" - base_url: "" + api_key: "${env:OPENAI_API_KEY}" diff --git a/go.mod b/go.mod index d59105cb..f2288d51 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,13 @@ module glide go 1.21.5 require ( - github.com/cloudwego/hertz v0.7.3 github.com/go-playground/validator/v10 v10.17.0 - github.com/hertz-contrib/logger/zap v1.1.0 - github.com/hertz-contrib/swagger v0.1.0 + github.com/gofiber/contrib/fiberzap/v2 v2.1.2 + github.com/gofiber/contrib/swagger v1.1.1 + github.com/gofiber/fiber/v2 v2.52.0 + github.com/joho/godotenv v1.5.1 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 - github.com/swaggo/files v1.0.1 github.com/swaggo/swag v1.16.2 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 @@ -19,41 +19,46 @@ require ( require ( github.com/KyleBanks/depth v1.2.1 // indirect - github.com/andeya/ameda v1.5.3 // indirect - github.com/andeya/goutil v1.0.1 // indirect - github.com/bytedance/go-tagexpr/v2 v2.9.11 // indirect - github.com/bytedance/gopkg v0.0.0-20231219111115-a5eedbe96960 // indirect - github.com/bytedance/sonic v1.10.2 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect - github.com/chenzhuoyu/iasm v0.9.1 // indirect - github.com/cloudwego/netpoll v0.5.0 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/go-openapi/analysis v0.21.4 // indirect + github.com/go-openapi/errors v0.20.3 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/loads v0.21.2 // indirect + github.com/go-openapi/runtime v0.26.0 // indirect github.com/go-openapi/spec v0.20.13 // indirect + github.com/go-openapi/strfmt v0.21.7 // indirect github.com/go-openapi/swag v0.22.7 // indirect + github.com/go-openapi/validate v0.22.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.5.5 // indirect + github.com/google/uuid v1.5.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/cpuid/v2 v2.2.6 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/nyaruka/phonenumbers v1.3.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/tidwall/gjson v1.17.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 - golang.org/x/arch v0.6.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + go.mongodb.org/mongo-driver v1.11.3 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.16.1 // indirect - google.golang.org/protobuf v1.32.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 7c3d524b..5d17b87c 100644 --- a/go.sum +++ b/go.sum @@ -1,50 +1,57 @@ +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/andeya/ameda v1.5.3 h1:SvqnhQPZwwabS8HQTRGfJwWPl2w9ZIPInHAw9aE1Wlk= -github.com/andeya/ameda v1.5.3/go.mod h1:FQDHRe1I995v6GG+8aJ7UIUToEmbdTJn/U26NCPIgXQ= -github.com/andeya/goutil v1.0.1 h1:eiYwVyAnnK0dXU5FJsNjExkJW4exUGn/xefPt3k4eXg= -github.com/andeya/goutil v1.0.1/go.mod h1:jEG5/QnnhG7yGxwFUX6Q+JGMif7sjdHmmNVjn7nhJDo= -github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= -github.com/bytedance/go-tagexpr/v2 v2.9.11 h1:jJgmoDKPKacGl0llPYbYL/+/2N+Ng0vV0ipbnVssXHY= -github.com/bytedance/go-tagexpr/v2 v2.9.11/go.mod h1:UAyKh4ZRLBPGsyTRFZoPqTni1TlojMdOJXQnEIPCX84= -github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= -github.com/bytedance/gopkg v0.0.0-20231219111115-a5eedbe96960 h1:t2xAuIlnhWJDIpcHZEbpoVsQH1hOk9eGGaKU2dXl1PE= -github.com/bytedance/gopkg v0.0.0-20231219111115-a5eedbe96960/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= -github.com/bytedance/mockey v1.2.1 h1:g84ngI88hz1DR4wZTL3yOuqlEcq67MretBfQUdXwrmw= -github.com/bytedance/mockey v1.2.1/go.mod h1:+Jm/fzWZAuhEDrPXVjDf/jLM2BlLXJkwk94zf2JZ3X4= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= -github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= -github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= -github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= -github.com/cloudwego/hertz v0.7.3 h1:VM1DxditA6vxI97rG5SBu4hHB24xdzDbKBQfUy7sfVE= -github.com/cloudwego/hertz v0.7.3/go.mod h1:WliNtVbwihWHHgAaIQEbVXl0O3aWj0ks1eoPrcEAnjs= -github.com/cloudwego/netpoll v0.5.0 h1:oRrOp58cPCvK2QbMozZNDESvrxQaEHW2dCimmwH1lcU= -github.com/cloudwego/netpoll v0.5.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/cpuguy83/go-md2man/v2 v2.0.3/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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= +github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= +github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= +github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= +github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= +github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= +github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= +github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= +github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/spec v0.20.13 h1:XJDIN+dLH6vqXgafnl5SUIMnzaChQ6QTo0/UPMbkIaE= github.com/go-openapi/spec v0.20.13/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= +github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= +github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= +github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8= github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -53,149 +60,217 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74= github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gofiber/contrib/fiberzap/v2 v2.1.2 h1:7Z1BqS1sYK9e9jTwqPcWx9qQt46PI8oeswgAp6YNZC4= +github.com/gofiber/contrib/fiberzap/v2 v2.1.2/go.mod h1:ulCCQOdDYABGsOQfbndASmCsCN86hsC96iKoOTNYfy8= +github.com/gofiber/contrib/swagger v1.1.1 h1:on+D2fbXkvm0H0lur1rx69mpxLdX1wIH/FrTRZ99b9Y= +github.com/gofiber/contrib/swagger v1.1.1/go.mod h1:pa9awsFSz/3BbSnyTe/drNZaiFfnhC4hk3m9BVet7Co= +github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE= +github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= -github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= -github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ= -github.com/hertz-contrib/logger/zap v1.1.0 h1:4efINiIDJrXEtAFeEdDJvc3Hye0VFxp+0X4BwaZgxNs= -github.com/hertz-contrib/logger/zap v1.1.0/go.mod h1:D/rJJgsYn+SGaHVfVqWS3vHTbbc7ODAlJO+6smWgTeE= -github.com/hertz-contrib/swagger v0.1.0 h1:FlnMPRHuvAt/3pt3KCQRZ6RH1g/agma9SU70Op2Pb58= -github.com/hertz-contrib/swagger v0.1.0/go.mod h1:Bt5i+Nyo7bGmYbuEfMArx7raf1oK+nWVgYbEvhpICKE= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= -github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= -github.com/nyaruka/phonenumbers v1.3.0 h1:IFyyJfF2Elg8xGKFghWrRXzb6qAHk+Q3uPqmIgS20JQ= -github.com/nyaruka/phonenumbers v1.3.0/go.mod h1:4jyKp/BFUokLbCHyoZag+T3S1KezFVoEKtgnbpzItC4= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +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.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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/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/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 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 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= -github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= -github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= -github.com/tidwall/gjson v1.17.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.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= 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/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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +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.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +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/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= +go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= 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.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= -golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= -golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190311183353-d8887717615a/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/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-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/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.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/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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +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-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/images/Makefile b/images/Makefile index 2bb33870..533f10c8 100644 --- a/images/Makefile +++ b/images/Makefile @@ -97,5 +97,24 @@ publish-ghcr-%: ## Push images to Github Registry docker tag $(REPOSITORY):$(VERSION)-$* ghcr.io/$(REPOSITORY):latest; \ echo "- pushing ghcr.io/$(REPOSITORY):latest"; \ docker push ghcr.io/$(REPOSITORY):latest; \ + docker tag $(REPOSITORY):$(VERSION)-$* ghcr.io/$(REPOSITORY):$(VERSION); \ + echo "- pushing ghcr.io/$(REPOSITORY):$(VERSION)"; \ + docker push ghcr.io/$(REPOSITORY):$(VERSION); \ + fi; \ + } + +publish-dockerhub-%: ## Push images to Docker Hub + @echo "🚚Pushing the $* image to Github Registry.." + @docker tag $(REPOSITORY):$(VERSION)-$* $(REPOSITORY):$(VERSION)-$* + @echo "- pushing $(REPOSITORY):$(VERSION)-$*" + @docker push $(REPOSITORY):$(VERSION)-$* + @echo $(VERSION) | grep -q $(RC_PART) || { \ + docker tag $(REPOSITORY):$(VERSION)-$* $(REPOSITORY):latest-$*; \ + echo "- pushing $(REPOSITORY):latest-$*"; \ + docker push $(REPOSITORY):latest-$*; \ + if [ "$*" = "alpine" ]; then \ + docker tag $(REPOSITORY):$(VERSION)-$* $(REPOSITORY):latest; \ + echo "- pushing $(REPOSITORY):latest"; \ + docker push $(REPOSITORY):latest; \ fi; \ } diff --git a/leak_test.go b/leak_test.go index 024a502a..de6aa9be 100644 --- a/leak_test.go +++ b/leak_test.go @@ -1,11 +1,11 @@ package main import ( - _ "go.uber.org/goleak" + "testing" + + "go.uber.org/goleak" ) -// TODO: investigate why netpoll leaves pending goroutines -// https://github.com/modelgateway/Glide/issues/33 -//func TestMain(m *testing.M) { -// goleak.VerifyTestMain(m) -//} +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/pkg/api/http/config.go b/pkg/api/http/config.go index f33cc15b..8e261098 100644 --- a/pkg/api/http/config.go +++ b/pkg/api/http/config.go @@ -4,10 +4,8 @@ import ( "fmt" "time" - "github.com/cloudwego/hertz/pkg/common/config" - - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/network/netpoll" + "github.com/gofiber/fiber/v2" + "glide/pkg/version" ) type ServerConfig struct { @@ -20,10 +18,10 @@ type ServerConfig struct { } func DefaultServerConfig() *ServerConfig { - maxReqBodySize := 4 * 1024 * 1024 - readTimeout := 3 * time.Second - writeTimeout := 3 * time.Second - idleTimeout := 1 * time.Second + maxReqBodySizeBytes := 4 * 1024 * 1024 // 4Mb + readTimeout := 30 * time.Second + writeTimeout := 1 * time.Minute + idleTimeout := 30 * time.Second return &ServerConfig{ Host: "127.0.0.1", @@ -31,7 +29,7 @@ func DefaultServerConfig() *ServerConfig { IdleTimeout: &idleTimeout, ReadTimeout: &readTimeout, WriteTimeout: &writeTimeout, - MaxRequestBodySize: &maxReqBodySize, + MaxRequestBodySize: &maxReqBodySizeBytes, } } @@ -39,28 +37,35 @@ func (cfg *ServerConfig) Address() string { return fmt.Sprintf("%s:%v", cfg.Host, cfg.Port) } -func (cfg *ServerConfig) ToServer() *server.Hertz { - // More configs are listed on https://www.cloudwego.io/docs/hertz/tutorials/basic-feature/engine/ - serverOptions := []config.Option{ - server.WithHostPorts(cfg.Address()), - server.WithTransport(netpoll.NewTransporter), +func (cfg *ServerConfig) ToServer() *fiber.App { + // More configs are listed on https://docs.gofiber.io/api/fiber + // TODO: Consider alternative JSON marshallers that provides better performance over the standard marshaller + serverConfig := fiber.Config{ + AppName: "glide", + DisableDefaultDate: true, + ServerHeader: fmt.Sprintf("glide/%v", version.Version), + StreamRequestBody: true, + Immutable: false, + DisablePreParseMultipartForm: true, + EnablePrintRoutes: false, + DisableStartupMessage: false, } if cfg.IdleTimeout != nil { - serverOptions = append(serverOptions, server.WithIdleTimeout(*cfg.IdleTimeout)) + serverConfig.IdleTimeout = *cfg.IdleTimeout } if cfg.ReadTimeout != nil { - serverOptions = append(serverOptions, server.WithReadTimeout(*cfg.ReadTimeout)) + serverConfig.ReadTimeout = *cfg.ReadTimeout } if cfg.WriteTimeout != nil { - serverOptions = append(serverOptions, server.WithWriteTimeout(*cfg.WriteTimeout)) + serverConfig.WriteTimeout = *cfg.WriteTimeout } if cfg.MaxRequestBodySize != nil { - serverOptions = append(serverOptions, server.WithMaxRequestBodySize(*cfg.MaxRequestBodySize)) + serverConfig.BodyLimit = *cfg.MaxRequestBodySize } - return server.Default(serverOptions...) + return fiber.New(serverConfig) } diff --git a/pkg/api/http/handlers.go b/pkg/api/http/handlers.go index e25bd6ca..611bdedb 100644 --- a/pkg/api/http/handlers.go +++ b/pkg/api/http/handlers.go @@ -1,18 +1,15 @@ package http import ( - "context" - "encoding/json" "errors" + "github.com/gofiber/fiber/v2" + "glide/pkg/api/schemas" "glide/pkg/routers" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/protocol/consts" ) -type Handler = func(ctx context.Context, c *app.RequestContext) +type Handler = func(c *fiber.Ctx) error // Swagger 101: // - https://github.com/swaggo/swag/tree/master/example/celler @@ -32,57 +29,39 @@ type Handler = func(ctx context.Context, c *app.RequestContext) // @Failure 404 {object} http.ErrorSchema // @Router /v1/language/{router}/chat [POST] func LangChatHandler(routerManager *routers.RouterManager) Handler { - return func(ctx context.Context, c *app.RequestContext) { + return func(c *fiber.Ctx) error { // Unmarshal request body var req *schemas.UnifiedChatRequest - err := json.Unmarshal(c.Request.Body(), &req) + err := c.BodyParser(&req) if err != nil { - // Return bad request error - c.JSON(consts.StatusBadRequest, ErrorSchema{ + return c.Status(fiber.StatusBadRequest).JSON(ErrorSchema{ Message: err.Error(), }) - - return - } - - // Bind JSON to request - err = c.BindJSON(&req) - if err != nil { - // Return bad request error - c.JSON(consts.StatusBadRequest, ErrorSchema{ - Message: err.Error(), - }) - - return } // Get router ID from path - routerID := c.Param("router") + routerID := c.Params("router") router, err := routerManager.GetLangRouter(routerID) if errors.Is(err, routers.ErrRouterNotFound) { // Return not found error - c.JSON(consts.StatusNotFound, ErrorSchema{ + return c.Status(fiber.StatusNotFound).JSON(ErrorSchema{ Message: err.Error(), }) - - return } // Chat with router - resp, err := router.Chat(ctx, req) + resp, err := router.Chat(c.Context(), req) if err != nil { // Return internal server error - c.JSON(consts.StatusInternalServerError, ErrorSchema{ + return c.Status(fiber.StatusInternalServerError).JSON(ErrorSchema{ Message: err.Error(), }) - - return } // Return chat response - c.JSON(consts.StatusOK, resp) + return c.Status(fiber.StatusOK).JSON(resp) } } @@ -97,7 +76,7 @@ func LangChatHandler(routerManager *routers.RouterManager) Handler { // @Success 200 {object} http.RouterListSchema // @Router /v1/language/ [GET] func LangRoutersHandler(routerManager *routers.RouterManager) Handler { - return func(ctx context.Context, c *app.RequestContext) { + return func(c *fiber.Ctx) error { configuredRouters := routerManager.GetLangRouters() cfgs := make([]*routers.LangRouterConfig, 0, len(configuredRouters)) @@ -105,7 +84,7 @@ func LangRoutersHandler(routerManager *routers.RouterManager) Handler { cfgs = append(cfgs, router.Config) } - c.JSON(consts.StatusOK, RouterListSchema{Routers: cfgs}) + return c.Status(fiber.StatusOK).JSON(RouterListSchema{Routers: cfgs}) } } @@ -119,6 +98,12 @@ func LangRoutersHandler(routerManager *routers.RouterManager) Handler { // @Produce json // @Success 200 {object} http.HealthSchema // @Router /v1/health/ [get] -func HealthHandler(_ context.Context, c *app.RequestContext) { - c.JSON(consts.StatusOK, HealthSchema{Healthy: true}) +func HealthHandler(c *fiber.Ctx) error { + return c.Status(fiber.StatusOK).JSON(HealthSchema{Healthy: true}) +} + +func NotFoundHandler(c *fiber.Ctx) error { + return c.Status(fiber.StatusNotFound).JSON(ErrorSchema{ + Message: "The route is not found", + }) } diff --git a/pkg/api/http/server.go b/pkg/api/http/server.go index f8a78d17..d44beac1 100644 --- a/pkg/api/http/server.go +++ b/pkg/api/http/server.go @@ -2,25 +2,27 @@ package http import ( "context" + "errors" "fmt" "time" - "github.com/hertz-contrib/swagger" - swaggerFiles "github.com/swaggo/files" + "github.com/gofiber/contrib/fiberzap/v2" + + "github.com/gofiber/contrib/swagger" + + "github.com/gofiber/fiber/v2" _ "glide/docs" // importing docs package to include them into the binary "glide/pkg/routers" "glide/pkg/telemetry" - - "github.com/cloudwego/hertz/pkg/app/server" ) type Server struct { config *ServerConfig telemetry *telemetry.Telemetry routerManager *routers.RouterManager - server *server.Hertz + server *fiber.App } func NewServer(config *ServerConfig, tel *telemetry.Telemetry, routerManager *routers.RouterManager) (*Server, error) { @@ -35,28 +37,47 @@ func NewServer(config *ServerConfig, tel *telemetry.Telemetry, routerManager *ro } func (srv *Server) Run() error { - defaultGroup := srv.server.Group("/v1") + srv.server.Use(swagger.New(swagger.Config{ + Title: "Glide API Docs", + BasePath: "/v1/", + Path: "swagger", + FilePath: "./docs/swagger.json", + })) + + srv.server.Use(fiberzap.New(fiberzap.Config{ + Logger: srv.telemetry.Logger, + })) - defaultGroup.GET("/language/", LangRoutersHandler(srv.routerManager)) - defaultGroup.POST("/language/:router/chat/", LangChatHandler(srv.routerManager)) + v1 := srv.server.Group("/v1") - defaultGroup.GET("/health/", HealthHandler) + v1.Get("/language/", LangRoutersHandler(srv.routerManager)) + v1.Post("/language/:router/chat/", LangChatHandler(srv.routerManager)) - schemaDocURL := swagger.URL(fmt.Sprintf("http://%v/v1/swagger/doc.json", srv.config.Address())) - defaultGroup.GET("/swagger/*any", swagger.WrapHandler(swaggerFiles.Handler, schemaDocURL)) + v1.Get("/health/", HealthHandler) - return srv.server.Run() + srv.server.Use(NotFoundHandler) + + return srv.server.Listen(srv.config.Address()) } -func (srv *Server) Shutdown(_ context.Context) error { - exitWaitTime := srv.server.GetOptions().ExitWaitTimeout +func (srv *Server) Shutdown(ctx context.Context) error { + exitWaitTime := 5 * time.Second srv.telemetry.Logger.Info( fmt.Sprintf("Begin graceful shutdown, wait at most %d seconds...", exitWaitTime/time.Second), ) - ctx, cancel := context.WithTimeout(context.Background(), exitWaitTime) + c, cancel := context.WithTimeout(ctx, exitWaitTime) defer cancel() - return srv.server.Shutdown(ctx) //nolint:contextcheck + if err := srv.server.ShutdownWithContext(c); err != nil { + if errors.Is(err, context.DeadlineExceeded) { + srv.telemetry.Logger.Info("Server closed forcefully due to shutdown timeout") + return nil + } + + return err + } + + return nil } diff --git a/pkg/api/servers.go b/pkg/api/servers.go index 8b0580d9..7a1d3c0d 100644 --- a/pkg/api/servers.go +++ b/pkg/api/servers.go @@ -4,6 +4,8 @@ import ( "context" "sync" + "go.uber.org/zap" + "glide/pkg/routers" "glide/pkg/telemetry" @@ -14,6 +16,7 @@ import ( type ServerManager struct { httpServer *http.Server shutdownWG *sync.WaitGroup + telemetry *telemetry.Telemetry } func NewServerManager(cfg *Config, tel *telemetry.Telemetry, router *routers.RouterManager) (*ServerManager, error) { @@ -27,6 +30,7 @@ func NewServerManager(cfg *Config, tel *telemetry.Telemetry, router *routers.Rou return &ServerManager{ httpServer: httpServer, shutdownWG: &sync.WaitGroup{}, + telemetry: tel, }, nil } @@ -37,10 +41,10 @@ func (mgr *ServerManager) Start() { go func() { defer mgr.shutdownWG.Done() - // TODO: log the error err := mgr.httpServer.Run() - - println(err) + if err != nil { + mgr.telemetry.Logger.Error("error on running HTTP server", zap.Error(err)) + } }() } } diff --git a/pkg/cmd/cli.go b/pkg/cmd/cli.go index ffa2b933..154b83ca 100644 --- a/pkg/cmd/cli.go +++ b/pkg/cmd/cli.go @@ -1,13 +1,19 @@ package cmd import ( - "glide/pkg" - "glide/pkg/config" + "log" + + "glide/pkg/version" "github.com/spf13/cobra" + "glide/pkg" + "glide/pkg/config" ) -var cfgFile string +var ( + dotEnvFile string + cfgFile string +) const Description = ` β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— @@ -34,9 +40,19 @@ func NewCLI() *cobra.Command { Use: "glide", Short: "🐦Glide is an open-source, lightweight, high-performance model gateway", Long: Description, - Version: pkg.FullVersion, - RunE: func(cmd *cobra.Command, args []string) error { - configProvider, err := config.NewProvider().Load(cfgFile) + Version: version.FullVersion, + RunE: func(cmd *cobra.Command, _ []string) error { + configProvider := config.NewProvider() + + err := configProvider.LoadDotEnv(dotEnvFile) + + if err != nil { + log.Println("⚠️failed to load dotenv file: ", err) // don't have an inited logger at this moment + } else { + log.Printf("πŸ”§dot env file loaded (%v)", dotEnvFile) + } + + _, err = configProvider.Load(cfgFile) if err != nil { return err } @@ -52,7 +68,9 @@ func NewCLI() *cobra.Command { SilenceErrors: true, } + cli.PersistentFlags().StringVarP(&dotEnvFile, "env", "e", ".env", "dotenv file") cli.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file") + _ = cli.MarkPersistentFlagRequired("config") return cli diff --git a/pkg/config/expander.go b/pkg/config/expander.go index ef2c32b0..ac3c2d31 100644 --- a/pkg/config/expander.go +++ b/pkg/config/expander.go @@ -71,6 +71,7 @@ func (e *Expander) expandFileDirectives(content string) string { } filePath := matches[1] + content, err := os.ReadFile(filepath.Clean(filePath)) if err != nil { log.Printf("could not expand the file directive (${file:%s}): %v", filePath, err) diff --git a/pkg/config/provider.go b/pkg/config/provider.go index ccfb35e2..5101aecc 100644 --- a/pkg/config/provider.go +++ b/pkg/config/provider.go @@ -7,6 +7,8 @@ import ( "reflect" "strings" + "github.com/joho/godotenv" + "github.com/go-playground/validator/v10" "gopkg.in/yaml.v3" @@ -40,6 +42,10 @@ func NewProvider() *Provider { } } +func (p *Provider) LoadDotEnv(envPath string) error { + return godotenv.Load(envPath) +} + func (p *Provider) Load(configPath string) (*Provider, error) { content, err := os.ReadFile(filepath.Clean(configPath)) if err != nil { diff --git a/pkg/gateway.go b/pkg/gateway.go index 4c11a565..a27eddbd 100644 --- a/pkg/gateway.go +++ b/pkg/gateway.go @@ -7,6 +7,8 @@ import ( "os/signal" "syscall" + "glide/pkg/version" + "glide/pkg/routers" "glide/pkg/config" @@ -41,8 +43,8 @@ func NewGateway(configProvider *config.Provider) (*Gateway, error) { return nil, err } - tel.Logger.Info("🐦Glide is starting up", zap.String("version", FullVersion)) - tel.Logger.Debug("config loaded successfully:\n" + configProvider.GetStr()) + tel.Logger.Info("🐦Glide is starting up", zap.String("version", version.FullVersion)) + tel.Logger.Debug("βœ… config loaded successfully:\n" + configProvider.GetStr()) routerManager, err := routers.NewManager(&cfg.Routers, tel) if err != nil { @@ -66,7 +68,7 @@ func NewGateway(configProvider *config.Provider) (*Gateway, error) { // Run starts and runs the gateway according to given configuration func (gw *Gateway) Run(ctx context.Context) error { gw.configProvider.Start() - gw.serverManager.Start() + gw.serverManager.Start() //nolint:contextcheck signal.Notify(gw.signalC, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) defer signal.Stop(gw.signalC) diff --git a/pkg/providers/anthropic/client_test.go b/pkg/providers/anthropic/client_test.go index 321d38ed..c8927a37 100644 --- a/pkg/providers/anthropic/client_test.go +++ b/pkg/providers/anthropic/client_test.go @@ -37,6 +37,7 @@ func TestAnthropicClient_ChatRequest(t *testing.T) { } w.Header().Set("Content-Type", "application/json") + _, err = w.Write(chatResponse) if err != nil { t.Errorf("error on sending chat response: %v", err) @@ -68,7 +69,7 @@ func TestAnthropicClient_ChatRequest(t *testing.T) { func TestAnthropicClient_BadChatRequest(t *testing.T) { // Anthropic Messages API: https://docs.anthropic.com/claude/reference/messages_post - AnthropicMock := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + AnthropicMock := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { // Return a non-OK status code w.WriteHeader(http.StatusBadRequest) }) diff --git a/pkg/providers/azureopenai/client_test.go b/pkg/providers/azureopenai/client_test.go index b7800aec..62080029 100644 --- a/pkg/providers/azureopenai/client_test.go +++ b/pkg/providers/azureopenai/client_test.go @@ -37,6 +37,7 @@ func TestAzureOpenAIClient_ChatRequest(t *testing.T) { } w.Header().Set("Content-Type", "application/json") + _, err = w.Write(chatResponse) if err != nil { t.Errorf("error on sending chat response: %v", err) @@ -66,7 +67,7 @@ func TestAzureOpenAIClient_ChatRequest(t *testing.T) { } func TestAzureOpenAIClient_ChatError(t *testing.T) { - azureOpenAIMock := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + azureOpenAIMock := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { http.Error(w, "Internal Server Error", http.StatusInternalServerError) }) @@ -99,7 +100,7 @@ func TestAzureOpenAIClient_ChatError(t *testing.T) { func TestDoChatRequest_ErrorResponse(t *testing.T) { // Create a mock HTTP server that returns a non-OK status code - mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusBadRequest) })) diff --git a/pkg/providers/cohere/client_test.go b/pkg/providers/cohere/client_test.go index c88fef4a..7828aa37 100644 --- a/pkg/providers/cohere/client_test.go +++ b/pkg/providers/cohere/client_test.go @@ -37,6 +37,7 @@ func TestCohereClient_ChatRequest(t *testing.T) { } w.Header().Set("Content-Type", "application/json") + _, err = w.Write(chatResponse) if err != nil { t.Errorf("error on sending chat response: %v", err) diff --git a/pkg/providers/octoml/client_test.go b/pkg/providers/octoml/client_test.go index 5e99e3f1..1c5c7e63 100644 --- a/pkg/providers/octoml/client_test.go +++ b/pkg/providers/octoml/client_test.go @@ -37,6 +37,7 @@ func TestOctoMLClient_ChatRequest(t *testing.T) { } w.Header().Set("Content-Type", "application/json") + _, err = w.Write(chatResponse) if err != nil { t.Errorf("error on sending chat response: %v", err) @@ -69,7 +70,7 @@ func TestOctoMLClient_ChatRequest(t *testing.T) { func TestOctoMLClient_Chat_Error(t *testing.T) { // Set up the test case // Create a mock API server that returns an error - octoMLMock := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + octoMLMock := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { // Return an error http.Error(w, "Internal Server Error", http.StatusInternalServerError) }) @@ -104,7 +105,7 @@ func TestOctoMLClient_Chat_Error(t *testing.T) { func TestDoChatRequest_ErrorResponse(t *testing.T) { // Create a mock HTTP server that returns a non-OK status code - mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusBadRequest) })) diff --git a/pkg/providers/openai/client_test.go b/pkg/providers/openai/client_test.go index 81c8f4df..f8ca7e6a 100644 --- a/pkg/providers/openai/client_test.go +++ b/pkg/providers/openai/client_test.go @@ -37,6 +37,7 @@ func TestOpenAIClient_ChatRequest(t *testing.T) { } w.Header().Set("Content-Type", "application/json") + _, err = w.Write(chatResponse) if err != nil { t.Errorf("error on sending chat response: %v", err) diff --git a/pkg/routers/config.go b/pkg/routers/config.go index c1c4fbf7..025f0c6d 100644 --- a/pkg/routers/config.go +++ b/pkg/routers/config.go @@ -29,11 +29,11 @@ func (c *Config) BuildLangRouters(tel *telemetry.Telemetry) ([]*LangRouter, erro seenIDs[routerConfig.ID] = true if !routerConfig.Enabled { - tel.Logger.Info("router is disabled, skipping", zap.String("routerID", routerConfig.ID)) + tel.Logger.Info(fmt.Sprintf("Router \"%v\" is disabled, skipping", routerConfig.ID)) continue } - tel.Logger.Debug("init router", zap.String("routerID", routerConfig.ID)) + tel.Logger.Debug("Init router", zap.String("routerID", routerConfig.ID)) router, err := NewLangRouter(&c.LanguageRouters[idx], tel) if err != nil { @@ -82,7 +82,7 @@ func (c *LangRouterConfig) BuildModels(tel *telemetry.Telemetry) ([]providers.La if !modelConfig.Enabled { tel.Logger.Info( - "model is disabled, skipping", + "Model is disabled, skipping", zap.String("router", c.ID), zap.String("model", modelConfig.ID), ) @@ -91,7 +91,7 @@ func (c *LangRouterConfig) BuildModels(tel *telemetry.Telemetry) ([]providers.La } tel.Logger.Debug( - "init lang model", + "Init lang model", zap.String("router", c.ID), zap.String("model", modelConfig.ID), ) @@ -114,11 +114,12 @@ func (c *LangRouterConfig) BuildModels(tel *telemetry.Telemetry) ([]providers.La } if len(models) == 1 { - tel.Logger.Warn( - "router has only one active model defined. "+ + tel.Logger.WithOptions(zap.AddStacktrace(zap.ErrorLevel)).Warn( + fmt.Sprintf("Router \"%v\" has only one active model defined. "+ "This is not recommended for production setups. "+ "Define at least a few models to leverage resiliency logic Glide provides", - zap.String("router", c.ID), + c.ID, + ), ) } diff --git a/pkg/routers/config_test.go b/pkg/routers/config_test.go index c24cdea1..f2912164 100644 --- a/pkg/routers/config_test.go +++ b/pkg/routers/config_test.go @@ -65,9 +65,9 @@ func TestRouterConfig_BuildModels(t *testing.T) { require.NoError(t, err) require.Len(t, routers, 2) require.Len(t, routers[0].models, 1) - require.IsType(t, routers[0].routing, &routing.PriorityRouting{}) + require.IsType(t, &routing.PriorityRouting{}, routers[0].routing) require.Len(t, routers[1].models, 1) - require.IsType(t, routers[1].routing, &routing.LeastLatencyRouting{}) + require.IsType(t, &routing.LeastLatencyRouting{}, routers[1].routing) } func TestRouterConfig_InvalidSetups(t *testing.T) { diff --git a/pkg/routers/health/error_budget.go b/pkg/routers/health/error_budget.go index e6eae66c..b420097d 100644 --- a/pkg/routers/health/error_budget.go +++ b/pkg/routers/health/error_budget.go @@ -1,6 +1,7 @@ package health import ( + "errors" "fmt" "strconv" "strings" @@ -58,7 +59,7 @@ func (b *ErrorBudget) UnmarshalText(text []byte) error { parts := strings.Split(string(text), budgetSeparator) if len(parts) != 2 { - return fmt.Errorf("invalid format") + return errors.New("invalid format") } budget, err := strconv.Atoi(parts[0]) @@ -73,7 +74,7 @@ func (b *ErrorBudget) UnmarshalText(text []byte) error { unit := Unit(parts[1]) if unit != MILLI && unit != SEC && unit != MIN && unit != HOUR { - return fmt.Errorf("invalid unit (supported: ms, s, m, h)") + return errors.New("invalid unit (supported: ms, s, m, h)") } b.budget = uint(budget) diff --git a/pkg/telemetry/logging.go b/pkg/telemetry/logging.go index dbeeb408..c4aa5ffe 100644 --- a/pkg/telemetry/logging.go +++ b/pkg/telemetry/logging.go @@ -1,8 +1,6 @@ package telemetry import ( - "github.com/cloudwego/hertz/pkg/common/hlog" - hertzzap "github.com/hertz-contrib/logger/zap" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -62,31 +60,6 @@ func (c *LogConfig) ToZapConfig() *zap.Config { return &zapConfig } -func NewHertzLogger(zapConfig *zap.Config) (*hertzzap.Logger, error) { - // Both hertzzap and zap have a set of private methods that prevents from leveraging - // their native encoder & sink building functionality - // We had to copy & paste some of those to get it working - var encoder zapcore.Encoder - - if zapConfig.Encoding == "console" { - encoder = zapcore.NewConsoleEncoder(zapConfig.EncoderConfig) - } else { - encoder = zapcore.NewJSONEncoder(zapConfig.EncoderConfig) - } - - sink, _, err := zap.Open(zapConfig.OutputPaths...) - if err != nil { - return nil, err - } - - return hertzzap.NewLogger( - hertzzap.WithCoreEnc(encoder), - hertzzap.WithCoreWs(sink), - hertzzap.WithCoreLevel(zapConfig.Level), - hertzzap.WithZapOptions(zap.AddCallerSkip(3)), - ), nil -} - func NewLogger(cfg *LogConfig) (*zap.Logger, error) { zapConfig := cfg.ToZapConfig() @@ -95,12 +68,5 @@ func NewLogger(cfg *LogConfig) (*zap.Logger, error) { return nil, err } - hertzLogger, err := NewHertzLogger(zapConfig) - if err != nil { - return nil, err - } - - hlog.SetLogger(hertzLogger) - return logger, nil } diff --git a/pkg/version.go b/pkg/version/version.go similarity index 80% rename from pkg/version.go rename to pkg/version/version.go index 5ad11003..83735b8c 100644 --- a/pkg/version.go +++ b/pkg/version/version.go @@ -1,13 +1,13 @@ -package pkg +package version import ( "fmt" "runtime" ) -// version must be set from the contents of VERSION file by go build's +// Version must be set from the contents of VERSION file by go build's // -X main.version= option in the Makefile. -var version = "devel" +var Version = "devel" // commitSha will be the hash that the binary was built from // and will be populated by the Makefile @@ -21,7 +21,7 @@ var FullVersion string func init() { FullVersion = fmt.Sprintf( "%s (commit: %s, runtime: %s, buildDate: %s)", - version, + Version, commitSha, runtime.Version(), buildDate,