├── .github ├── dependabot.yml └── workflows │ ├── analysis.yml │ ├── lint.yml │ └── test.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── README.md ├── cache ├── README.md ├── go.mod ├── go.sum ├── manager.go ├── manager_test.go ├── null_store.go ├── redis │ ├── go.mod │ ├── go.sum │ ├── store.go │ └── store_test.go ├── repository.go ├── repository_test.go ├── snapshot.go ├── snapshot_test.go ├── store.go ├── utils.go └── utils_test.go ├── chi ├── README.md ├── go.mod ├── go.sum ├── server.go └── server_test.go ├── cloudevents ├── eventdispatcher │ ├── README.md │ ├── context.go │ ├── context_test.go │ ├── dispatcher.go │ ├── dispatcher_test.go │ ├── go.mod │ ├── go.sum │ └── listener.go └── protocol │ └── amqp091 │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── message.go │ ├── protocol.go │ ├── receiver.go │ ├── sender.go │ └── write_message.go ├── codec ├── README.md ├── codec.go ├── go.mod ├── go.sum ├── json │ ├── codec.go │ ├── codec_test.go │ ├── go.mod │ └── go.sum ├── msgpack │ ├── codec.go │ ├── codec_test.go │ ├── go.mod │ └── go.sum └── sonic │ ├── codec.go │ ├── codec_test.go │ ├── go.mod │ └── go.sum ├── codecov.yml ├── config ├── config.go ├── config_test.go ├── go.mod ├── go.sum ├── provider.go └── provider_test.go ├── constraints ├── README.md ├── constraints.go └── go.mod ├── contract ├── asyncable.go ├── countable.go ├── go.mod ├── htmlable.go ├── jsonable.go ├── nameable.go ├── renderable.go ├── retriable.go ├── server.go └── stringable.go ├── coroutines ├── coroutines.go ├── coroutines_test.go ├── go.mod ├── go.sum ├── worker.go └── worker_test.go ├── crontab ├── README.md ├── example │ ├── go.mod │ ├── go.sum │ └── main.go ├── go.mod ├── go.sum ├── logger.go ├── logger_test.go ├── server.go └── server_test.go ├── eino └── components │ └── embedding │ └── cached │ ├── README.md │ ├── cacher.go │ ├── cacher_test.go │ ├── embedding.go │ ├── embedding_test.go │ ├── example │ ├── go.mod │ ├── go.sum │ └── main.go │ ├── generator.go │ ├── generator_test.go │ ├── go.mod │ ├── go.sum │ └── redis │ ├── cacher.go │ ├── cacher_test.go │ ├── go.mod │ └── go.sum ├── encrypter ├── README.md ├── encrypter.go ├── encrypter_test.go ├── go.mod └── go.sum ├── ent ├── go.mod ├── go.sum ├── logger.go ├── logger_test.go └── multidriver │ ├── driver.go │ ├── go.mod │ ├── go.sum │ ├── option.go │ ├── policy.go │ └── policy_test.go ├── env ├── context.go ├── context_test.go ├── env.go ├── env_test.go ├── go.mod ├── go.sum ├── provider.go └── provider_test.go ├── errors ├── errors.go ├── errors_test.go ├── go.mod ├── go.sum ├── group.go ├── group_test.go ├── timeout.go └── timeout_test.go ├── event ├── README.md ├── context.go ├── context_test.go ├── dispatcher.go ├── dispatcher_test.go ├── example │ ├── go.mod │ ├── go.sum │ └── main.go ├── go.mod ├── go.sum ├── listener.go ├── middleware.go ├── middleware │ └── recovery │ │ ├── go.mod │ │ ├── go.sum │ │ ├── recovery.go │ │ └── recovery_test.go ├── provider.go └── provider_test.go ├── eventbus ├── README.md ├── eventbus.go ├── eventbus_test.go ├── go.mod └── go.sum ├── examples ├── cache │ ├── go.mod │ ├── go.sum │ └── main.go ├── cloudevents │ ├── amqp091 │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ └── eventdispatcher │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go ├── mysql │ └── canal │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go └── otel │ └── otlp │ ├── go.mod │ ├── go.sum │ └── main.go ├── filesystem ├── filesystem.go ├── filesystem_test.go ├── go.mod ├── go.sum ├── local │ ├── filesystem.go │ ├── filesystem_test.go │ ├── go.mod │ ├── go.sum │ └── testfile │ │ └── .gitignore ├── oss │ ├── filesystem.go │ ├── filesystem_test.go │ ├── go.mod │ └── go.sum ├── paths.go ├── paths_test.go ├── repository.go ├── repository_test.go └── s3 │ ├── filesystem.go │ ├── filesystem_test.go │ ├── go.mod │ └── go.sum ├── foundation ├── go.mod ├── go.sum ├── kernel.go ├── kernel_test.go ├── provider.go └── provider_test.go ├── gin ├── README.md ├── go.mod ├── go.sum ├── server.go └── server_test.go ├── go.mod ├── go.sum ├── gomod_test.go ├── gorm ├── go.mod ├── go.sum ├── manager.go ├── manager_test.go └── scope │ ├── README.md │ ├── example_test.go │ ├── go.mod │ ├── go.sum │ ├── helpers.go │ ├── helpers_test.go │ ├── init_test.go │ ├── scopes.go │ └── scopes_test.go ├── hashing ├── go.mod ├── go.sum ├── hasher.go ├── hashing.go └── md5 │ ├── go.mod │ ├── go.sum │ ├── hasher.go │ └── hasher_test.go ├── http └── server │ ├── README.md │ ├── example_test.go │ ├── go.mod │ ├── go.sum │ ├── server.go │ └── server_test.go ├── hyperf └── jet │ ├── README.md │ ├── client.go │ ├── client_test.go │ ├── context.go │ ├── context_test.go │ ├── formatter.go │ ├── generator.go │ ├── generator_test.go │ ├── go.mod │ ├── go.sum │ ├── middleware.go │ ├── middleware │ ├── logging │ │ ├── README.md │ │ ├── go.mod │ │ ├── go.sum │ │ ├── logging.go │ │ └── logging_test.go │ ├── recovery │ │ ├── go.mod │ │ ├── go.sum │ │ ├── recovery.go │ │ └── recovery_test.go │ ├── retry │ │ ├── README.md │ │ ├── backoff.go │ │ ├── backoff_test.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── options.go │ │ ├── retry.go │ │ └── retry_test.go │ ├── timeout │ │ ├── README.md │ │ ├── go.mod │ │ ├── go.sum │ │ ├── timeout.go │ │ └── timeout_test.go │ └── tracing │ │ ├── go.mod │ │ ├── go.sum │ │ ├── tracing.go │ │ └── tracing_test.go │ ├── middleware_test.go │ ├── packer.go │ ├── packer_test.go │ ├── transporter.go │ └── transporter_test.go ├── internal └── tools │ ├── codecovfix │ └── main.go │ ├── go.mod │ ├── go.sum │ └── main.go ├── kratos ├── log │ ├── otel │ │ ├── convert.go │ │ ├── convert_test.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── logger.go │ │ └── options.go │ ├── stack │ │ ├── README.md │ │ ├── example_test.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── stack.go │ │ └── stack_test.go │ └── syslog │ │ ├── go.mod │ │ ├── go.sum │ │ ├── syslog.go │ │ └── syslog_test.go └── middleware │ ├── cors │ ├── cors.go │ ├── go.mod │ └── go.sum │ ├── protovalidate │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── internal │ │ ├── buf.gen.yaml │ │ ├── buf.lock │ │ ├── buf.yaml │ │ └── proto │ │ │ └── protovalidate │ │ │ └── v1 │ │ │ ├── person.pb.go │ │ │ └── person.proto │ ├── validator.go │ └── validator_test.go │ ├── slowlog │ ├── go.mod │ ├── go.sum │ ├── slowlog.go │ └── slowlog_test.go │ └── tracing │ ├── README.md │ ├── go.mod │ ├── go.sum │ ├── internal │ ├── buf.gen.yaml │ ├── buf.yaml │ └── proto │ │ └── tracing │ │ └── v1 │ │ ├── hello.pb.go │ │ └── hello.proto │ ├── metadata.go │ ├── metadata_test.go │ ├── span.go │ ├── span_test.go │ ├── statshandler.go │ ├── statshandler_test.go │ ├── tracer.go │ ├── tracer_test.go │ ├── tracing.go │ └── tracing_test.go ├── locker ├── README.md ├── go.mod ├── go.sum ├── locker.go ├── locker_test.go ├── owner.go ├── owner_test.go └── redis │ ├── go.mod │ ├── go.sum │ ├── locker.go │ └── locker_test.go ├── mysql └── canal │ ├── README.md │ ├── canal.go │ ├── events.go │ ├── go.mod │ ├── go.sum │ ├── internal │ └── dispatcher.go │ ├── positioner.go │ ├── positioner │ └── redis │ │ ├── go.mod │ │ ├── go.sum │ │ ├── options.go │ │ ├── positioner.go │ │ └── positioner_test.go │ └── server │ ├── go.mod │ ├── go.sum │ └── server.go ├── otel └── otlp │ ├── README.md │ ├── client.go │ ├── go.mod │ ├── go.sum │ ├── hook.go │ ├── provider.go │ └── transport.go ├── recovery ├── go.mod ├── go.sum ├── recovery.go └── recovery_test.go ├── redis ├── go.mod ├── go.sum ├── manager.go └── manager_test.go ├── renovate.json ├── signal ├── README.md ├── go.mod ├── go.sum ├── handler.go ├── server.go └── server_test.go ├── support ├── bytes │ ├── size.go │ └── size_test.go ├── collection │ ├── README.md │ ├── collection.go │ └── collection_test.go ├── contexts │ ├── contexts.go │ ├── contexts_test.go │ ├── values.go │ └── values_test.go ├── coordinator │ ├── README.md │ ├── coordinator.go │ ├── coordinator_test.go │ ├── manager.go │ └── manager_test.go ├── debug │ ├── dump.go │ └── dump_test.go ├── go.mod ├── go.sum ├── helpers.go ├── helpers_test.go ├── maps │ ├── README.md │ ├── maps.go │ └── maps_test.go ├── proxy_value.go ├── proxy_value_test.go ├── slices │ ├── slices.go │ └── slices_test.go ├── strings │ ├── strings.go │ └── strings_test.go ├── values.go └── values_test.go ├── timezone ├── context.go ├── go.mod ├── go.sum ├── provider.go └── provider_test.go ├── udp ├── README.md ├── go.mod ├── go.sum ├── server.go └── server_test.go ├── version.go ├── version_test.go ├── versions.yaml └── x ├── README.md ├── container ├── container.go ├── global.go ├── global_test.go ├── go.mod └── go.sum ├── pagination ├── go.mod ├── go.sum ├── paginator.go └── paginator_test.go └── prints ├── README.md ├── basic.go ├── basic_test.go ├── go.mod ├── go.sum ├── output.jpg ├── progressbar.go ├── progressbar_test.go └── prompt.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | - package-ecosystem: gomod 8 | directory: / 9 | schedule: 10 | interval: daily -------------------------------------------------------------------------------- /.github/workflows/analysis.yml: -------------------------------------------------------------------------------- 1 | name: Go Static Analysis 2 | 3 | on: 4 | push: 5 | branches: 6 | - 3.x 7 | pull_request: 8 | branches: 9 | - 3.x 10 | 11 | jobs: 12 | golangci: 13 | name: nilaway 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: install nilaway 19 | run: go install go.uber.org/nilaway/cmd/nilaway@latest 20 | 21 | - name: nilaway 22 | run: ~/go/bin/nilaway ./... 23 | continue-on-error: true -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Go Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - 3.x 7 | pull_request: 8 | branches: 9 | - 3.x 10 | 11 | jobs: 12 | golangci: 13 | name: lint 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Go mod cache 19 | uses: actions/cache@v4 20 | with: 21 | path: | 22 | ~/.cache/go-build 23 | ~/go/pkg/mod 24 | key: ${{ runner.os }}-go-mod 25 | 26 | - name: Tools cache 27 | uses: actions/cache@v4 28 | env: 29 | cache-name: go-tools-cache 30 | with: 31 | path: .tools 32 | key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('./internal/tools/**') }} 33 | 34 | - name: GolangCI-Lint cache 35 | uses: actions/cache@v4 36 | with: 37 | path: ~/.cache/golangci-lint 38 | key: ${{ runner.os }}-golangci-lint-${{ hashFiles('**/.golangci.yml') }} 39 | restore-keys: ${{ runner.os }}-golangci-lint- 40 | 41 | - uses: actions/setup-go@v5 42 | with: 43 | go-version: stable 44 | check-latest: true 45 | cache: false 46 | 47 | - name: Run lint 48 | run: make lint 49 | 50 | - name: Build 51 | run: make build 52 | 53 | - name: Check clean repository 54 | run: make check-clean-work-tree -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | *_ignore_test.go 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | vendor/ 17 | .idea 18 | _backup 19 | _example 20 | .todo 21 | .tools -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | linters: 4 | default: none 5 | 6 | enable: 7 | - bodyclose 8 | - dogsled 9 | - durationcheck 10 | - errcheck 11 | - copyloopvar 12 | - govet 13 | - goconst 14 | - mnd 15 | - gocyclo 16 | - ineffassign 17 | - prealloc 18 | - revive 19 | - staticcheck 20 | - unused 21 | - whitespace 22 | - wastedassign 23 | - unconvert 24 | - misspell 25 | settings: 26 | revive: 27 | rules: 28 | - name: package-comments 29 | disabled: true 30 | 31 | formatters: 32 | enable: 33 | - gofmt 34 | - gofumpt 35 | - goimports 36 | settings: 37 | gofmt: 38 | rewrite-rules: 39 | - pattern: 'interface{}' 40 | replacement: 'any' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Go Fries Components (https://github.com/flc1125, https://flc.io) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cache/README.md: -------------------------------------------------------------------------------- 1 | # Cache 2 | 3 | ## Usage Example 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "context" 10 | "log" 11 | "time" 12 | 13 | "github.com/redis/go-redis/v9" 14 | 15 | redisStore "github.com/go-fries/fries/cache/redis/v3" 16 | "github.com/go-fries/fries/cache/v3" 17 | ) 18 | 19 | var ctx = context.Background() 20 | 21 | type User struct { 22 | Name string 23 | Age int 24 | } 25 | 26 | func main() { 27 | // 创建个 Redis 连接客户端 28 | rdb := redis.NewClient(&redis.Options{ 29 | Addr: "localhost:6379", 30 | }) 31 | defer rdb.Close() 32 | 33 | // create a redis store 34 | store := redisStore.New(rdb, redisStore.Prefix("example:cache")) 35 | 36 | // create a cache repository 37 | repository := cache.NewRepository(store) 38 | 39 | // set cache 40 | ok, err := repository.Set(ctx, "key", User{ 41 | Name: "example", 42 | Age: 18, 43 | }, time.Second*10) 44 | if err != nil { 45 | log.Fatal(err) 46 | } 47 | _ = ok 48 | 49 | // get cache 50 | var user User 51 | err = repository.Get(ctx, "key", &user) 52 | if err != nil { 53 | log.Fatal(err) 54 | } 55 | log.Printf("user: %+v", user) 56 | 57 | // remember 58 | user2, err := cache.Remember(ctx, repository, "key2", time.Second*10, func() (User, error) { 59 | return User{ 60 | Name: "example2", 61 | Age: 20, 62 | }, nil 63 | }) 64 | if err != nil { 65 | log.Fatal(err) 66 | } 67 | log.Printf("user2: %+v", user2) 68 | } 69 | ``` -------------------------------------------------------------------------------- /cache/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/cache/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/locker/v3 => ../locker 6 | 7 | require ( 8 | github.com/go-fries/fries/locker/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/google/uuid v1.6.0 // indirect 15 | github.com/pmezard/go-difflib v1.0.0 // indirect 16 | gopkg.in/yaml.v3 v3.0.1 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /cache/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 4 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 8 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 12 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 13 | -------------------------------------------------------------------------------- /cache/manager.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | type Manager struct { 4 | Repository 5 | 6 | drivers map[string]Repository 7 | } 8 | 9 | func NewManager(repository Repository) *Manager { 10 | return &Manager{ 11 | Repository: repository, 12 | drivers: make(map[string]Repository), 13 | } 14 | } 15 | 16 | func (m *Manager) Register(name string, repository Repository) { 17 | m.drivers[name] = repository 18 | } 19 | 20 | func (m *Manager) Driver(names ...string) Repository { 21 | var name string 22 | if len(names) > 0 { 23 | name = names[0] 24 | } 25 | 26 | if name == "" { 27 | return m.Repository 28 | } 29 | 30 | if c, ok := m.drivers[name]; ok { 31 | return c 32 | } 33 | 34 | panic("cache: the repository [" + name + "] is not registered.") 35 | } 36 | -------------------------------------------------------------------------------- /cache/manager_test.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestManager(t *testing.T) { 10 | var r1, r2 Repository 11 | 12 | manager := NewManager(r1) 13 | manager.Register("r2", r2) 14 | 15 | assert.Equal(t, r1, manager.Driver()) 16 | assert.Equal(t, r2, manager.Driver("r2")) 17 | assert.Panics(t, func() { 18 | manager.Driver("r3") 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /cache/null_store.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/go-fries/fries/locker/v3" 8 | ) 9 | 10 | type NullStore struct{} 11 | 12 | var _ Store = (*NullStore)(nil) 13 | 14 | func (n *NullStore) Has(context.Context, string) (bool, error) { 15 | return true, nil 16 | } 17 | 18 | func (n *NullStore) Get(context.Context, string, any) error { 19 | return nil 20 | } 21 | 22 | func (n *NullStore) Put(context.Context, string, any, time.Duration) (bool, error) { 23 | return true, nil 24 | } 25 | 26 | func (n *NullStore) Increment(context.Context, string, int) (int, error) { 27 | return 0, nil 28 | } 29 | 30 | func (n *NullStore) Decrement(context.Context, string, int) (int, error) { 31 | return 0, nil 32 | } 33 | 34 | func (n *NullStore) Forever(context.Context, string, any) (bool, error) { 35 | return true, nil 36 | } 37 | 38 | func (n *NullStore) Forget(context.Context, string) (bool, error) { 39 | return true, nil 40 | } 41 | 42 | func (n *NullStore) Flush(context.Context) (bool, error) { 43 | return true, nil 44 | } 45 | 46 | func (n *NullStore) Lock(string, time.Duration) locker.Locker { 47 | return nil 48 | } 49 | 50 | func (n *NullStore) GetPrefix() string { 51 | return "" 52 | } 53 | -------------------------------------------------------------------------------- /cache/redis/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/cache/redis/v3 2 | 3 | go 1.23.0 4 | 5 | replace ( 6 | github.com/go-fries/fries/cache/v3 => ../ 7 | github.com/go-fries/fries/codec/json/v3 => ../../codec/json 8 | github.com/go-fries/fries/codec/v3 => ../../codec 9 | github.com/go-fries/fries/locker/redis/v3 => ../../locker/redis 10 | github.com/go-fries/fries/locker/v3 => ../../locker 11 | ) 12 | 13 | require ( 14 | github.com/go-fries/fries/cache/v3 v3.4.0 15 | github.com/go-fries/fries/codec/json/v3 v3.4.0 16 | github.com/go-fries/fries/codec/v3 v3.4.0 17 | github.com/go-fries/fries/locker/redis/v3 v3.4.0 18 | github.com/go-fries/fries/locker/v3 v3.4.0 19 | github.com/redis/go-redis/v9 v9.9.0 20 | github.com/stretchr/testify v1.10.0 21 | ) 22 | 23 | require ( 24 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 25 | github.com/davecgh/go-spew v1.1.1 // indirect 26 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 27 | github.com/google/uuid v1.6.0 // indirect 28 | github.com/pmezard/go-difflib v1.0.0 // indirect 29 | gopkg.in/yaml.v3 v3.0.1 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /cache/utils.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "time" 7 | ) 8 | 9 | // Get is a utility function that retrieves a value from the cache using the provided key. 10 | // It unmarshals the value into the provided destination variable. 11 | func Get[T any](ctx context.Context, repository Repository, key string) (T, error) { 12 | var result T 13 | return result, repository.Get(ctx, key, &result) 14 | } 15 | 16 | // Remember is a utility function that retrieves a value from the cache using the provided key. 17 | // If the value is not found, it calls the provided callback function to generate the value, 18 | // If the value is found in the cache, it returns the cached value and a nil error. 19 | func Remember[T any](ctx context.Context, repository Repository, key string, ttl time.Duration, callback func() (T, error)) (T, error) { 20 | var result T 21 | err := repository.Get(ctx, key, &result) 22 | if !errors.Is(err, ErrNotFound) { 23 | return result, err 24 | } 25 | 26 | result, err = callback() 27 | if err != nil { 28 | return result, err 29 | } 30 | 31 | _, err = repository.Put(ctx, key, result, ttl) 32 | if err != nil { 33 | return result, err 34 | } 35 | 36 | return result, nil 37 | } 38 | -------------------------------------------------------------------------------- /chi/README.md: -------------------------------------------------------------------------------- 1 | # go-chi server 2 | 3 | - https://github.com/go-chi/chi 4 | 5 | ## Example 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "net/http" 12 | 13 | "github.com/go-chi/chi/v5" 14 | "github.com/go-kratos/kratos/v2" 15 | 16 | chis "github.com/go-kratos-ecosystem/components/v2/chi" 17 | ) 18 | 19 | func main() { 20 | cs := chis.NewServer( 21 | chi.NewRouter(), 22 | chis.Addr(":8001"), 23 | ) 24 | 25 | cs.Get("/", func(w http.ResponseWriter, _ *http.Request) { 26 | _, _ = w.Write([]byte("hello world")) 27 | }) 28 | 29 | app := kratos.New( 30 | kratos.Server(cs), 31 | ) 32 | 33 | if err := app.Run(); err != nil { 34 | panic(err) 35 | } 36 | } 37 | ``` -------------------------------------------------------------------------------- /chi/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/chi/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/go-chi/chi/v5 v5.2.1 7 | github.com/go-kratos/kratos/v2 v2.8.4 8 | github.com/stretchr/testify v1.10.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/kr/text v0.2.0 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | gopkg.in/yaml.v3 v3.0.1 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /chi/server.go: -------------------------------------------------------------------------------- 1 | package chi 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/go-chi/chi/v5" 8 | "github.com/go-kratos/kratos/v2/log" 9 | ) 10 | 11 | type Server struct { 12 | *chi.Mux 13 | server *http.Server 14 | addr string 15 | } 16 | 17 | type Option func(*Server) 18 | 19 | func Addr(addr string) Option { 20 | return func(s *Server) { 21 | s.addr = addr 22 | } 23 | } 24 | 25 | func NewServer(c *chi.Mux, opts ...Option) *Server { 26 | srv := &Server{ 27 | Mux: c, 28 | addr: ":8080", 29 | } 30 | 31 | for _, opt := range opts { 32 | opt(srv) 33 | } 34 | 35 | srv.server = &http.Server{ 36 | Addr: srv.addr, 37 | Handler: c, 38 | } 39 | 40 | return srv 41 | } 42 | 43 | func (s *Server) Start(_ context.Context) error { 44 | log.Infof("[go-chi] server listening on: %s", s.addr) 45 | return s.server.ListenAndServe() 46 | } 47 | 48 | func (s *Server) Stop(ctx context.Context) error { 49 | log.Info("[go-chi] server stopping") 50 | return s.server.Shutdown(ctx) 51 | } 52 | -------------------------------------------------------------------------------- /chi/server_test.go: -------------------------------------------------------------------------------- 1 | package chi 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | "time" 9 | 10 | "github.com/go-chi/chi/v5" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestServer(t *testing.T) { 15 | srv := NewServer(chi.NewRouter(), Addr(":8001")) 16 | 17 | srv.Get("/ping", func(w http.ResponseWriter, r *http.Request) { 18 | assert.Equal(t, http.MethodGet, r.Method) 19 | _, _ = w.Write([]byte("pong")) 20 | }) 21 | 22 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) 23 | defer cancel() 24 | 25 | go func() { 26 | assert.ErrorIs(t, srv.Start(ctx), http.ErrServerClosed) 27 | }() 28 | 29 | time.Sleep(100 * time.Millisecond) 30 | 31 | req, err := http.NewRequest(http.MethodGet, "http://"+srv.addr+"/ping", nil) 32 | assert.NoError(t, err) 33 | 34 | recorder := httptest.NewRecorder() 35 | srv.ServeHTTP(recorder, req) 36 | 37 | assert.Equal(t, http.StatusOK, recorder.Code) 38 | assert.Equal(t, "pong", recorder.Body.String()) 39 | 40 | assert.NoError(t, srv.Stop(ctx)) 41 | } 42 | -------------------------------------------------------------------------------- /cloudevents/eventdispatcher/README.md: -------------------------------------------------------------------------------- 1 | # Event-Dispatcher for CloudEvents 2 | 3 | ## Usage 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "context" 10 | "log" 11 | 12 | cloudevents "github.com/cloudevents/sdk-go/v2" 13 | "github.com/go-fries/fries/cloudevents/eventdispatcher/v3" 14 | ) 15 | 16 | type ExampleEvent struct { 17 | UserID string 18 | } 19 | 20 | type ExampleListener struct{} 21 | 22 | func (l *ExampleListener) Handle(ctx context.Context, event *ExampleEvent) error { 23 | log.Printf("Received event for user: %s", event.UserID) 24 | return nil 25 | } 26 | 27 | func main() { 28 | client, err := cloudevents.NewClient(nil) // Replace nil with your protocol configuration if needed 29 | if err != nil { 30 | log.Fatalf("Failed to create client: %v", err) 31 | } 32 | 33 | dispatcher := eventdispatcher.NewDispatcher() 34 | 35 | // the method one: 36 | dispatcher.AddListener( 37 | "example.type", 38 | eventdispatcher.ListenerFunc[*ExampleEvent](func(ctx context.Context, event *ExampleEvent) error { 39 | log.Printf("Received event for user: %s", event.UserID) 40 | return nil 41 | }), 42 | ) 43 | // the method two: 44 | dispatcher.AddListener( 45 | "example.type", 46 | eventdispatcher.ListenerAdapter(&ExampleListener{}), 47 | ) 48 | 49 | _ = client.StartReceiver(context.Background(), func(ctx context.Context, event cloudevents.Event) error { 50 | log.Printf("Received event: %v", event) 51 | return nil 52 | }) 53 | } 54 | ``` -------------------------------------------------------------------------------- /cloudevents/eventdispatcher/context.go: -------------------------------------------------------------------------------- 1 | package eventdispatcher 2 | 3 | import ( 4 | "context" 5 | 6 | cloudevents "github.com/cloudevents/sdk-go/v2" 7 | ) 8 | 9 | type contextKey struct{} 10 | 11 | func NewContext(ctx context.Context, event cloudevents.Event) context.Context { 12 | return context.WithValue(ctx, contextKey{}, event) 13 | } 14 | 15 | func FromContext(ctx context.Context) (cloudevents.Event, bool) { 16 | event, ok := ctx.Value(contextKey{}).(cloudevents.Event) 17 | if !ok { 18 | return cloudevents.Event{}, false 19 | } 20 | return event, true 21 | } 22 | -------------------------------------------------------------------------------- /cloudevents/eventdispatcher/context_test.go: -------------------------------------------------------------------------------- 1 | package eventdispatcher 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | cloudevents "github.com/cloudevents/sdk-go/v2" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestContext(t *testing.T) { 12 | t.Run("with event", func(t *testing.T) { 13 | event := cloudevents.NewEvent() 14 | event.SetID("test-event") 15 | event.SetType("test.type") 16 | 17 | ctx := NewContext(context.Background(), event) 18 | 19 | retrievedEvent, ok := FromContext(ctx) 20 | assert.True(t, ok) 21 | assert.Equal(t, "test-event", retrievedEvent.ID()) 22 | assert.Equal(t, event, retrievedEvent) 23 | }) 24 | 25 | t.Run("empty context", func(t *testing.T) { 26 | emptyCtx := context.Background() 27 | _, ok := FromContext(emptyCtx) 28 | assert.False(t, ok) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /cloudevents/eventdispatcher/dispatcher.go: -------------------------------------------------------------------------------- 1 | package eventdispatcher 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync" 7 | 8 | cloudevents "github.com/cloudevents/sdk-go/v2" 9 | "golang.org/x/sync/errgroup" 10 | ) 11 | 12 | var ErrNoListener = fmt.Errorf("no listener registered for the event") 13 | 14 | type Dispatcher struct { 15 | listeners map[string][]Listener 16 | rw sync.RWMutex 17 | } 18 | 19 | func NewDispatcher() *Dispatcher { 20 | return &Dispatcher{ 21 | listeners: make(map[string][]Listener), 22 | } 23 | } 24 | 25 | func (d *Dispatcher) AddListener(typed string, listener Listener) { 26 | d.rw.Lock() 27 | defer d.rw.Unlock() 28 | 29 | if _, exists := d.listeners[typed]; !exists { 30 | d.listeners[typed] = make([]Listener, 0) 31 | } 32 | 33 | d.listeners[typed] = append(d.listeners[typed], listener) 34 | } 35 | 36 | func (d *Dispatcher) Dispatch(ctx context.Context, event cloudevents.Event) error { 37 | d.rw.RLock() 38 | defer d.rw.RUnlock() 39 | 40 | for typed, listener := range d.listeners { 41 | if event.Type() == typed { 42 | eg, ctx := errgroup.WithContext(NewContext(ctx, event)) 43 | for _, l := range listener { 44 | eg.Go(func() error { 45 | return l.Handle(ctx, event) 46 | }) 47 | } 48 | return eg.Wait() 49 | } 50 | } 51 | 52 | return ErrNoListener 53 | } 54 | 55 | func (d *Dispatcher) Reset() { 56 | d.rw.Lock() 57 | defer d.rw.Unlock() 58 | 59 | d.listeners = make(map[string][]Listener) 60 | } 61 | -------------------------------------------------------------------------------- /cloudevents/eventdispatcher/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/cloudevents/eventdispatcher/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/cloudevents/sdk-go/v2 v2.16.0 7 | github.com/stretchr/testify v1.10.0 8 | golang.org/x/sync v0.15.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/google/uuid v1.6.0 // indirect 14 | github.com/json-iterator/go v1.1.12 // indirect 15 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 16 | github.com/modern-go/reflect2 v1.0.2 // indirect 17 | github.com/pmezard/go-difflib v1.0.0 // indirect 18 | go.uber.org/multierr v1.11.0 // indirect 19 | go.uber.org/zap v1.27.0 // indirect 20 | gopkg.in/yaml.v3 v3.0.1 // indirect 21 | ) 22 | -------------------------------------------------------------------------------- /cloudevents/eventdispatcher/listener.go: -------------------------------------------------------------------------------- 1 | package eventdispatcher 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | cloudevents "github.com/cloudevents/sdk-go/v2" 8 | ) 9 | 10 | var ErrFailedToUnmarshalEvent = fmt.Errorf("failed to unmarshal event data") 11 | 12 | type Listener interface { 13 | Handle(ctx context.Context, event cloudevents.Event) error 14 | } 15 | 16 | type AnyListener[T any] interface { 17 | Handle(ctx context.Context, event T) error 18 | } 19 | 20 | type listenerAdapter[T any] struct { 21 | l AnyListener[T] 22 | } 23 | 24 | func ListenerAdapter[T any](l AnyListener[T]) Listener { 25 | return &listenerAdapter[T]{l: l} 26 | } 27 | 28 | func (a *listenerAdapter[T]) Handle(ctx context.Context, event cloudevents.Event) error { 29 | var data T 30 | if err := event.DataAs(&data); err != nil { 31 | return ErrFailedToUnmarshalEvent 32 | } 33 | return a.l.Handle(ctx, data) 34 | } 35 | 36 | type ListenerFunc[T any] func(ctx context.Context, event T) error 37 | 38 | var _ Listener = ListenerFunc[string](nil) 39 | 40 | func (l ListenerFunc[T]) Handle(ctx context.Context, event cloudevents.Event) error { 41 | var data T 42 | if err := event.DataAs(&data); err != nil { 43 | return ErrFailedToUnmarshalEvent 44 | } 45 | return l(ctx, data) 46 | } 47 | -------------------------------------------------------------------------------- /cloudevents/protocol/amqp091/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/cloudevents/protocol/amqp091/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/cloudevents/sdk-go/v2 v2.16.0 7 | github.com/rabbitmq/amqp091-go v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/json-iterator/go v1.1.12 // indirect 12 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 13 | github.com/modern-go/reflect2 v1.0.2 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /codec/README.md: -------------------------------------------------------------------------------- 1 | # Codec 2 | 3 | ## Usage 4 | 5 | ```go 6 | package codec_test 7 | 8 | import ( 9 | "log" 10 | 11 | "github.com/go-kratos-ecosystem/components/v2/codec/json" 12 | ) 13 | 14 | var j = json.Codec 15 | 16 | func ExampleJSON() { 17 | bytes, err := j.Marshal(map[string]string{ 18 | "key": "value", 19 | }) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | 24 | var dest map[string]string 25 | err = j.Unmarshal(bytes, &dest) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | } 30 | ``` -------------------------------------------------------------------------------- /codec/codec.go: -------------------------------------------------------------------------------- 1 | package codec 2 | 3 | // Codec is an interface for serialization and deserialization operations. 4 | type Codec interface { 5 | // Marshal converts the given data into a byte slice. 6 | // This method supports converting data structures of any type into a byte slice for transmission or storage. 7 | // Parameters: 8 | // data - The data to be serialized, of any type. 9 | // Return value: 10 | // It returns the byte slice obtained after serialization, and an error if serialization fails. 11 | Marshal(data any) ([]byte, error) 12 | 13 | // Unmarshal converts the given byte slice into a data structure. 14 | // This method supports deserializing a byte slice into a data structure of any type. 15 | // Parameters: 16 | // src - The byte slice to be deserialized. 17 | // dest - A pointer to the destination data structure where the deserialized data will be stored. 18 | // The specific type of the data structure needs to match the content of the byte slice. 19 | // Return value: 20 | // It returns an error if deserialization fails. 21 | Unmarshal(src []byte, dest any) error 22 | } 23 | -------------------------------------------------------------------------------- /codec/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/codec/v3 2 | 3 | go 1.23.0 4 | -------------------------------------------------------------------------------- /codec/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-fries/fries/87659eefd879e4017e1f3bec8ddf07129a20f9ea/codec/go.sum -------------------------------------------------------------------------------- /codec/json/codec.go: -------------------------------------------------------------------------------- 1 | package json 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/go-fries/fries/codec/v3" 7 | ) 8 | 9 | var Codec codec.Codec = &jsonCodec{} 10 | 11 | type jsonCodec struct{} 12 | 13 | func (j *jsonCodec) Marshal(data any) ([]byte, error) { 14 | return json.Marshal(data) 15 | } 16 | 17 | func (j *jsonCodec) Unmarshal(src []byte, dest any) error { 18 | return json.Unmarshal(src, dest) 19 | } 20 | -------------------------------------------------------------------------------- /codec/json/codec_test.go: -------------------------------------------------------------------------------- 1 | package json 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestJSON(t *testing.T) { 11 | j1, j2 := Codec, Codec 12 | 13 | assert.Same(t, j1, j2) 14 | 15 | data := map[string]any{ 16 | "foo": "bar", 17 | } 18 | 19 | // marshal 20 | bytes1, err := json.Marshal(data) 21 | assert.NoError(t, err) 22 | 23 | bytes2, err := j1.Marshal(data) 24 | assert.NoError(t, err) 25 | 26 | assert.Equal(t, bytes1, bytes2) 27 | 28 | // unmarshal 29 | dest1, dest2 := make(map[string]any), make(map[string]any) 30 | assert.NoError(t, json.Unmarshal(bytes1, &dest1)) 31 | assert.NoError(t, j1.Unmarshal(bytes1, &dest2)) 32 | 33 | assert.Equal(t, dest1, dest2) 34 | } 35 | 36 | func BenchmarkJSONCodec_Marshal(b *testing.B) { 37 | data := map[string]any{ 38 | "foo": "bar", 39 | } 40 | 41 | b.ReportAllocs() 42 | b.ResetTimer() 43 | b.RunParallel(func(pb *testing.PB) { 44 | for pb.Next() { 45 | _, err := Codec.Marshal(data) 46 | assert.NoError(b, err) 47 | } 48 | }) 49 | } 50 | 51 | func BenchmarkJSONCodec_Unmarshal(b *testing.B) { 52 | data := map[string]any{ 53 | "foo": "bar", 54 | } 55 | 56 | bytes, err := Codec.Marshal(data) 57 | assert.NoError(b, err) 58 | 59 | b.ReportAllocs() 60 | b.ResetTimer() 61 | b.RunParallel(func(pb *testing.PB) { 62 | for pb.Next() { 63 | var dest map[string]any 64 | assert.NoError(b, Codec.Unmarshal(bytes, &dest)) 65 | } 66 | }) 67 | } 68 | -------------------------------------------------------------------------------- /codec/json/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/codec/json/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/codec/v3 => ../ 6 | 7 | require ( 8 | github.com/go-fries/fries/codec/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | gopkg.in/yaml.v3 v3.0.1 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /codec/json/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /codec/msgpack/codec.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "github.com/go-fries/fries/codec/v3" 5 | "github.com/vmihailenco/msgpack/v5" 6 | ) 7 | 8 | var Codec codec.Codec = &msgPackCodec{} 9 | 10 | type msgPackCodec struct{} 11 | 12 | func (j *msgPackCodec) Marshal(data any) ([]byte, error) { 13 | return msgpack.Marshal(data) 14 | } 15 | 16 | func (j *msgPackCodec) Unmarshal(src []byte, dest any) error { 17 | return msgpack.Unmarshal(src, dest) 18 | } 19 | -------------------------------------------------------------------------------- /codec/msgpack/codec_test.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestJSON(t *testing.T) { 10 | c1, c2 := Codec, Codec 11 | 12 | assert.Same(t, c1, c2) 13 | 14 | data := map[string]any{ 15 | "foo": "bar", 16 | } 17 | 18 | // marshal 19 | bytes, err := c1.Marshal(data) 20 | assert.NoError(t, err) 21 | 22 | // unmarshal 23 | dest := make(map[string]any) 24 | assert.NoError(t, c1.Unmarshal(bytes, &dest)) 25 | } 26 | 27 | func BenchmarkMsgPackCodec_Marshal(b *testing.B) { 28 | data := map[string]any{ 29 | "foo": "bar", 30 | } 31 | 32 | b.ReportAllocs() 33 | b.ResetTimer() 34 | b.RunParallel(func(pb *testing.PB) { 35 | for pb.Next() { 36 | _, err := Codec.Marshal(data) 37 | assert.NoError(b, err) 38 | } 39 | }) 40 | } 41 | 42 | func BenchmarkMsgPackCodec_Unmarshal(b *testing.B) { 43 | data := map[string]any{ 44 | "foo": "bar", 45 | } 46 | 47 | bytes, err := Codec.Marshal(data) 48 | assert.NoError(b, err) 49 | 50 | b.ReportAllocs() 51 | b.ResetTimer() 52 | b.RunParallel(func(pb *testing.PB) { 53 | for pb.Next() { 54 | var dest map[string]any 55 | assert.NoError(b, Codec.Unmarshal(bytes, &dest)) 56 | } 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /codec/msgpack/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/codec/msgpack/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/codec/v3 => ../ 6 | 7 | require ( 8 | github.com/go-fries/fries/codec/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | github.com/vmihailenco/msgpack/v5 v5.4.1 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/pmezard/go-difflib v1.0.0 // indirect 16 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 17 | gopkg.in/yaml.v3 v3.0.1 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /codec/msgpack/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= 8 | github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= 9 | github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= 10 | github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 14 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | -------------------------------------------------------------------------------- /codec/sonic/codec.go: -------------------------------------------------------------------------------- 1 | package sonic 2 | 3 | import ( 4 | "github.com/bytedance/sonic" 5 | "github.com/go-fries/fries/codec/v3" 6 | ) 7 | 8 | var Codec codec.Codec = &sonicCodec{} 9 | 10 | type sonicCodec struct{} 11 | 12 | func (j *sonicCodec) Marshal(data any) ([]byte, error) { 13 | return sonic.Marshal(data) 14 | } 15 | 16 | func (j *sonicCodec) Unmarshal(src []byte, dest any) error { 17 | return sonic.Unmarshal(src, dest) 18 | } 19 | -------------------------------------------------------------------------------- /codec/sonic/codec_test.go: -------------------------------------------------------------------------------- 1 | package sonic 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestSonic(t *testing.T) { 10 | c1, c2 := Codec, Codec 11 | 12 | assert.Same(t, c1, c2) 13 | 14 | data := map[string]any{ 15 | "foo": "bar", 16 | } 17 | 18 | // marshal 19 | bytes, err := c1.Marshal(data) 20 | assert.NoError(t, err) 21 | 22 | // unmarshal 23 | dest := make(map[string]any) 24 | assert.NoError(t, c1.Unmarshal(bytes, &dest)) 25 | } 26 | 27 | func BenchmarkSonicCodec_Marshal(b *testing.B) { 28 | data := map[string]any{ 29 | "foo": "bar", 30 | } 31 | 32 | b.ReportAllocs() 33 | b.ResetTimer() 34 | b.RunParallel(func(pb *testing.PB) { 35 | for pb.Next() { 36 | _, err := Codec.Marshal(data) 37 | assert.NoError(b, err) 38 | } 39 | }) 40 | } 41 | 42 | func BenchmarkSonicCodec_Unmarshal(b *testing.B) { 43 | data := map[string]any{ 44 | "foo": "bar", 45 | } 46 | 47 | bytes, err := Codec.Marshal(data) 48 | assert.NoError(b, err) 49 | 50 | b.ReportAllocs() 51 | b.ResetTimer() 52 | b.RunParallel(func(pb *testing.PB) { 53 | for pb.Next() { 54 | var dest map[string]any 55 | assert.NoError(b, Codec.Unmarshal(bytes, &dest)) 56 | } 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /codec/sonic/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/codec/sonic/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/codec/v3 => ../ 6 | 7 | require ( 8 | github.com/bytedance/sonic v1.13.3 9 | github.com/go-fries/fries/codec/v3 v3.4.0 10 | github.com/stretchr/testify v1.10.0 11 | ) 12 | 13 | require ( 14 | github.com/bytedance/sonic/loader v0.2.4 // indirect 15 | github.com/cloudwego/base64x v0.1.5 // indirect 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/klauspost/cpuid/v2 v2.2.10 // indirect 18 | github.com/pmezard/go-difflib v1.0.0 // indirect 19 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 20 | golang.org/x/arch v0.18.0 // indirect 21 | golang.org/x/sys v0.33.0 // indirect 22 | gopkg.in/yaml.v3 v3.0.1 // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "context" 4 | 5 | // configKey is a type used to store configuration in the context. 6 | // It uses generics (T) so that it can work with any type of configuration. 7 | type configKey[T any] struct{} 8 | 9 | // NewContext creates and returns a new context that carries configuration information. 10 | // This function takes an existing context (ctx) and a configuration object (config), 11 | // and stores the configuration in the new context using configKey as the key. 12 | func NewContext[T any](ctx context.Context, config T) context.Context { 13 | return context.WithValue(ctx, configKey[T]{}, config) 14 | } 15 | 16 | // FromContext retrieves the configuration object from the given context. 17 | // It uses configKey as the key to fetch the configuration. 18 | func FromContext[T any](ctx context.Context) (T, bool) { 19 | config, ok := ctx.Value(configKey[T]{}).(T) 20 | return config, ok 21 | } 22 | -------------------------------------------------------------------------------- /config/config_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | type config struct { 11 | Host string 12 | Port int 13 | } 14 | 15 | type config2 struct { 16 | Host string 17 | Port int 18 | } 19 | 20 | func TestConfig(t *testing.T) { 21 | ctx := NewContext(context.Background(), &config{ 22 | Host: "localhost", 23 | Port: 8080, 24 | }) 25 | ctx2 := NewContext(ctx, &config2{ 26 | Host: "localhost2", 27 | Port: 8080, 28 | }) 29 | 30 | cfg, ok := FromContext[*config](ctx) 31 | assert.True(t, ok) 32 | assert.Equal(t, "localhost", cfg.Host) 33 | assert.Equal(t, 8080, cfg.Port) 34 | 35 | cfg2, ok := FromContext[*config2](ctx) 36 | assert.False(t, ok) 37 | assert.Nil(t, cfg2) 38 | 39 | cfg2, ok = FromContext[*config2](ctx2) 40 | assert.True(t, ok) 41 | assert.Equal(t, "localhost2", cfg2.Host) 42 | } 43 | -------------------------------------------------------------------------------- /config/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/config/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /config/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /config/provider.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "context" 4 | 5 | // Provider is a generic structure that represents a provider with a specific configuration. 6 | // It provides functionalities to bootstrap a context with the configuration and to terminate the context. 7 | type Provider[T any] struct { 8 | config T 9 | } 10 | 11 | // NewProvider creates and returns a new instance of the Provider with the given configuration. 12 | // It is a constructor function that initializes the Provider with a generic configuration. 13 | func NewProvider[T any](config T) *Provider[T] { 14 | return &Provider[T]{config: config} 15 | } 16 | 17 | // Bootstrap initializes and returns a new context with the provider's configuration. 18 | // It takes the current context as input and merges it with the provider's configuration to create a new context. 19 | // This function is typically used at the beginning of an application's lifecycle to set up the necessary configurations. 20 | func (p *Provider[T]) Bootstrap(ctx context.Context) (context.Context, error) { 21 | return NewContext(ctx, p.config), nil 22 | } 23 | 24 | // Terminate is a placeholder function that simulates the termination process of a context. 25 | func (p *Provider[T]) Terminate(ctx context.Context) (context.Context, error) { 26 | return ctx, nil 27 | } 28 | -------------------------------------------------------------------------------- /config/provider_test.go: -------------------------------------------------------------------------------- 1 | // provider_test.go 2 | package config 3 | 4 | import ( 5 | "context" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | type testConfig struct { 13 | Name string 14 | Port int 15 | } 16 | 17 | func TestProvider(t *testing.T) { 18 | cfg := testConfig{Name: "test", Port: 1234} 19 | provider := NewProvider(cfg) 20 | 21 | ctx := context.Background() 22 | newCtx, err := provider.Bootstrap(ctx) 23 | require.NoError(t, err) 24 | 25 | got, ok := FromContext[testConfig](newCtx) 26 | assert.True(t, ok) 27 | assert.Equal(t, cfg, got) 28 | 29 | terminatedCtx, err := provider.Terminate(newCtx) 30 | require.NoError(t, err) 31 | assert.Equal(t, newCtx, terminatedCtx) 32 | } 33 | -------------------------------------------------------------------------------- /constraints/README.md: -------------------------------------------------------------------------------- 1 | # Constraints 2 | 3 | The code of this package comes from [constraints](https://github.com/golang/exp/blob/master/constraints/constraints.go). Thanks to the official for providing the code. 4 | 5 | ## Thanks 6 | 7 | - https://github.com/golang/exp -------------------------------------------------------------------------------- /constraints/constraints.go: -------------------------------------------------------------------------------- 1 | package constraints 2 | 3 | // Signed is a constraint that permits any signed integer type. 4 | type Signed interface { 5 | ~int | ~int8 | ~int16 | ~int32 | ~int64 6 | } 7 | 8 | // Unsigned is a constraint that permits any unsigned integer type. 9 | type Unsigned interface { 10 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr 11 | } 12 | 13 | // Integer is a constraint that permits any integer type. 14 | type Integer interface { 15 | Signed | Unsigned 16 | } 17 | 18 | // Float is a constraint that permits any floating-point type. 19 | type Float interface { 20 | ~float32 | ~float64 21 | } 22 | 23 | // Complex is a constraint that permits any complex numeric type. 24 | type Complex interface { 25 | ~complex64 | ~complex128 26 | } 27 | 28 | // Ordered is a constraint that permits any ordered type: any type 29 | // that supports the operators < <= >= >. 30 | type Ordered interface { 31 | Integer | Float | ~string 32 | } 33 | 34 | // Numeric is a constraint that permits any numeric type. 35 | type Numeric interface { 36 | Integer | Float | Complex 37 | } 38 | -------------------------------------------------------------------------------- /constraints/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/constraints/v3 2 | 3 | go 1.23.0 4 | -------------------------------------------------------------------------------- /contract/asyncable.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Asyncable interface { 4 | Async() bool 5 | } 6 | 7 | type AsyncFeature struct{} 8 | 9 | func (*AsyncFeature) Async() bool { 10 | return true 11 | } 12 | -------------------------------------------------------------------------------- /contract/countable.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Countable interface { 4 | Count() int 5 | } 6 | -------------------------------------------------------------------------------- /contract/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/contract/v3 2 | 3 | go 1.23.0 4 | -------------------------------------------------------------------------------- /contract/htmlable.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Htmlable interface { 4 | Html() string 5 | } 6 | -------------------------------------------------------------------------------- /contract/jsonable.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Jsonable interface { 4 | Json() string 5 | } 6 | -------------------------------------------------------------------------------- /contract/nameable.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Nameable interface { 4 | Name() string 5 | } 6 | -------------------------------------------------------------------------------- /contract/renderable.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Renderable interface { 4 | Render() string 5 | } 6 | -------------------------------------------------------------------------------- /contract/retriable.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Retriable interface { 4 | Retries() int 5 | } 6 | -------------------------------------------------------------------------------- /contract/server.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | import "context" 4 | 5 | // Server is alias for github.com/go-kratos/kratos/v2/transport.Server 6 | type Server interface { 7 | Start(context.Context) error 8 | Stop(context.Context) error 9 | } 10 | -------------------------------------------------------------------------------- /contract/stringable.go: -------------------------------------------------------------------------------- 1 | package contract 2 | 3 | type Stringable interface { 4 | String() string 5 | } 6 | -------------------------------------------------------------------------------- /coroutines/coroutines.go: -------------------------------------------------------------------------------- 1 | package coroutines 2 | 3 | import "sync" 4 | 5 | func Wait(fns ...func()) { 6 | var wg sync.WaitGroup 7 | wg.Add(len(fns)) 8 | for _, fn := range fns { 9 | go func(fn func()) { 10 | defer wg.Done() 11 | fn() 12 | }(fn) 13 | } 14 | wg.Wait() 15 | } 16 | 17 | func Run(fns ...func()) { 18 | for _, fn := range fns { 19 | go fn() 20 | } 21 | } 22 | 23 | func Parallel(number int, fns ...func()) { 24 | ch := make(chan struct{}, number) 25 | for _, fn := range fns { 26 | ch <- struct{}{} 27 | go func(task func()) { 28 | defer func() { 29 | <-ch 30 | }() 31 | task() 32 | }(fn) 33 | } 34 | } 35 | 36 | func ParallelWait(number int, fns ...func()) { 37 | var wg sync.WaitGroup 38 | ch := make(chan struct{}, number) 39 | defer close(ch) 40 | wg.Add(len(fns)) 41 | for _, fn := range fns { 42 | ch <- struct{}{} 43 | go func(task func()) { 44 | defer func() { 45 | <-ch 46 | wg.Done() 47 | }() 48 | task() 49 | }(fn) 50 | } 51 | wg.Wait() 52 | } 53 | -------------------------------------------------------------------------------- /coroutines/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/coroutines/v3 2 | 3 | go 1.23.0 4 | 5 | replace ( 6 | github.com/go-fries/fries/errors/v3 => ../errors 7 | github.com/go-fries/fries/support/v3 => ./../support 8 | ) 9 | 10 | require ( 11 | github.com/go-fries/fries/support/v3 v3.4.0 12 | github.com/stretchr/testify v1.10.0 13 | ) 14 | 15 | require ( 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/go-fries/fries/errors/v3 v3.4.0 // indirect 18 | github.com/go-kratos/kratos/v2 v2.8.4 // indirect 19 | github.com/pmezard/go-difflib v1.0.0 // indirect 20 | golang.org/x/sys v0.33.0 // indirect 21 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 22 | google.golang.org/grpc v1.73.0 // indirect 23 | google.golang.org/protobuf v1.36.6 // indirect 24 | gopkg.in/yaml.v3 v3.0.1 // indirect 25 | ) 26 | -------------------------------------------------------------------------------- /coroutines/worker.go: -------------------------------------------------------------------------------- 1 | package coroutines 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type Worker struct { 8 | fns chan func() 9 | wg sync.WaitGroup 10 | } 11 | 12 | // NewWorker creates a new worker for running tasks in parallel. 13 | // The max parameter specifies the maximum number of goroutines that can run at the same time. 14 | // 15 | // Example: 16 | // 17 | // w := coroutines.NewWorker(10) 18 | // defer w.Close() 19 | // w.Push(func() { 20 | // // do something 21 | // }...) 22 | // w.Wait() 23 | func NewWorker(number int) *Worker { 24 | s := &Worker{ 25 | fns: make(chan func(), number*2), //nolint:mnd 26 | } 27 | 28 | go s.work(number) 29 | 30 | return s 31 | } 32 | 33 | func (s *Worker) work(num int) { 34 | ch := make(chan struct{}, num) 35 | defer close(ch) 36 | 37 | for fn := range s.fns { 38 | ch <- struct{}{} 39 | go func(fn func()) { 40 | defer func() { 41 | <-ch 42 | s.wg.Done() 43 | }() 44 | 45 | fn() 46 | }(fn) 47 | } 48 | } 49 | 50 | func (s *Worker) Push(fns ...func()) { 51 | s.wg.Add(len(fns)) 52 | for _, fn := range fns { 53 | s.fns <- fn 54 | } 55 | } 56 | 57 | func (s *Worker) Wait() { 58 | s.wg.Wait() 59 | } 60 | 61 | func (s *Worker) Close() { 62 | close(s.fns) 63 | } 64 | -------------------------------------------------------------------------------- /coroutines/worker_test.go: -------------------------------------------------------------------------------- 1 | package coroutines 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/go-fries/fries/support/v3" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestWorker(t *testing.T) { 12 | var ( 13 | fns []func() 14 | ch = make(chan struct{}, 200) 15 | now = time.Now() 16 | ) 17 | _ = support.Repeat(func() error { 18 | ch <- struct{}{} 19 | return nil 20 | }, 200) 21 | _ = support.Repeat(func() error { 22 | fns = append(fns, func() { 23 | time.Sleep(100 * time.Millisecond) 24 | <-ch 25 | }) 26 | return nil 27 | }, 100) 28 | 29 | assert.Len(t, ch, 200) 30 | assert.Len(t, fns, 100) 31 | assert.True(t, time.Since(now) < 100*time.Millisecond) 32 | 33 | w := NewWorker(10) 34 | defer w.Close() 35 | 36 | // the first time 37 | w.Push(fns...) 38 | w.Wait() 39 | 40 | assert.True(t, time.Since(now) < 2*time.Second) 41 | assert.True(t, time.Since(now) > 1*time.Second) 42 | assert.Len(t, ch, 100) 43 | 44 | // the second time 45 | now2 := time.Now() 46 | w.Push(fns...) 47 | w.Wait() 48 | assert.True(t, time.Since(now2) < 2*time.Second) 49 | assert.True(t, time.Since(now2) > 1*time.Second) 50 | assert.Len(t, ch, 0) 51 | } 52 | -------------------------------------------------------------------------------- /crontab/README.md: -------------------------------------------------------------------------------- 1 | # Crontab 2 | 3 | ## Example 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "context" 10 | 11 | "github.com/flc1125/go-cron/v4" 12 | "github.com/go-fries/fries/crontab/v3" 13 | "github.com/go-kratos/kratos/v2" 14 | ) 15 | 16 | func main() { 17 | c := cron.New( 18 | cron.WithSeconds(), 19 | cron.WithMiddleware( /*...*/ ), 20 | ) 21 | 22 | _, _ = c.AddFunc("* * * * * *", func(context.Context) error { 23 | // do something 24 | return nil 25 | }) 26 | 27 | // kratos app start 28 | app := kratos.New( 29 | kratos.Server( 30 | crontab.NewServer(c), 31 | ), 32 | ) 33 | 34 | err := app.Run() 35 | if err != nil { 36 | panic(err) 37 | } 38 | } 39 | ``` -------------------------------------------------------------------------------- /crontab/example/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/crontab/example/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/crontab/v3 => ../ 6 | 7 | require ( 8 | github.com/flc1125/go-cron/v4 v4.5.5 9 | github.com/go-fries/fries/crontab/v3 v3.4.0 10 | github.com/go-kratos/kratos/v2 v2.8.4 11 | ) 12 | 13 | require ( 14 | github.com/go-playground/form/v4 v4.2.3 // indirect 15 | github.com/google/go-cmp v0.7.0 // indirect 16 | github.com/google/uuid v1.6.0 // indirect 17 | golang.org/x/net v0.40.0 // indirect 18 | golang.org/x/sync v0.15.0 // indirect 19 | google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect 20 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 21 | google.golang.org/grpc v1.73.0 // indirect 22 | google.golang.org/protobuf v1.36.6 // indirect 23 | gopkg.in/yaml.v3 v3.0.1 // indirect 24 | ) 25 | -------------------------------------------------------------------------------- /crontab/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/flc1125/go-cron/v4" 7 | "github.com/go-fries/fries/crontab/v3" 8 | "github.com/go-kratos/kratos/v2" 9 | ) 10 | 11 | func main() { 12 | c := cron.New( 13 | cron.WithSeconds(), 14 | cron.WithMiddleware( /*...*/ ), 15 | ) 16 | 17 | _, _ = c.AddFunc("* * * * * *", func(context.Context) error { 18 | // do something 19 | return nil 20 | }) 21 | 22 | // kratos app start 23 | app := kratos.New( 24 | kratos.Server( 25 | crontab.NewServer(c), 26 | ), 27 | ) 28 | 29 | err := app.Run() 30 | if err != nil { 31 | panic(err) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crontab/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/crontab/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/flc1125/go-cron/v4 v4.5.5 7 | github.com/go-kratos/kratos/v2 v2.8.4 8 | github.com/stretchr/testify v1.10.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/kr/text v0.2.0 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | golang.org/x/sync v0.15.0 // indirect 16 | gopkg.in/yaml.v3 v3.0.1 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /crontab/logger.go: -------------------------------------------------------------------------------- 1 | package crontab 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/go-kratos/kratos/v2/log" 7 | ) 8 | 9 | type Logger struct { 10 | logger log.Logger 11 | } 12 | 13 | func NewLogger(logger log.Logger) *Logger { 14 | return &Logger{logger: logger} 15 | } 16 | 17 | func (l *Logger) Printf(format string, v ...any) { 18 | _ = l.logger.Log(log.LevelInfo, "msg", fmt.Sprintf(format, v...)) 19 | } 20 | -------------------------------------------------------------------------------- /crontab/logger_test.go: -------------------------------------------------------------------------------- 1 | package crontab 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/go-kratos/kratos/v2/log" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | type testLogger struct { 12 | ch chan string 13 | } 14 | 15 | func newTestLogger() *testLogger { 16 | return &testLogger{ 17 | ch: make(chan string, 1), 18 | } 19 | } 20 | 21 | func (t *testLogger) Log(level log.Level, keyvals ...any) error { 22 | t.ch <- fmt.Sprintf("level: %s, keyvals: %v", level, keyvals) 23 | return nil 24 | } 25 | 26 | func TestLogger(t *testing.T) { 27 | _, ok := any(NewLogger(nil)).(interface{ Printf(string, ...any) }) 28 | assert.True(t, ok) 29 | 30 | logger := newTestLogger() 31 | l := NewLogger(logger) 32 | l.Printf("test %s", "logger") 33 | assert.Equal(t, "level: INFO, keyvals: [msg test logger]", <-logger.ch) 34 | } 35 | -------------------------------------------------------------------------------- /crontab/server.go: -------------------------------------------------------------------------------- 1 | package crontab 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/flc1125/go-cron/v4" 7 | "github.com/go-kratos/kratos/v2/log" 8 | ) 9 | 10 | type Server struct { 11 | *cron.Cron 12 | } 13 | 14 | func NewServer(c *cron.Cron) *Server { 15 | return &Server{ 16 | Cron: c, 17 | } 18 | } 19 | 20 | func (s *Server) Start(context.Context) error { 21 | log.Info("[Crontab] server starting") 22 | s.Run() 23 | return nil 24 | } 25 | 26 | func (s *Server) Stop(ctx context.Context) error { 27 | log.Info("[Crontab] server stopping") 28 | 29 | for { 30 | select { 31 | case <-ctx.Done(): 32 | return ctx.Err() 33 | case <-s.Cron.Stop().Done(): 34 | return nil 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /crontab/server_test.go: -------------------------------------------------------------------------------- 1 | package crontab 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/flc1125/go-cron/v4" 9 | ) 10 | 11 | func TestCrontab(t *testing.T) { 12 | var ( 13 | ctx = context.Background() 14 | data = make(chan string, 1) 15 | srv = NewServer(cron.New( 16 | cron.WithSeconds(), 17 | )) 18 | ) 19 | 20 | _, _ = srv.AddFunc("* * * * * *", func(context.Context) error { 21 | data <- "Hello World!" 22 | return nil 23 | }) 24 | 25 | go srv.Start(ctx) //nolint:errcheck 26 | defer srv.Stop(ctx) //nolint:errcheck 27 | 28 | ctx, cancel := context.WithTimeout(ctx, time.Second*2) 29 | defer cancel() 30 | 31 | select { 32 | case <-ctx.Done(): 33 | t.Error("Crontab test timeout") 34 | return 35 | case msg := <-data: 36 | if msg != "Hello World!" { 37 | t.Errorf("Crontab test failed: %s", msg) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /eino/components/embedding/cached/cacher.go: -------------------------------------------------------------------------------- 1 | package cached 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "time" 7 | ) 8 | 9 | var defaultCacher Cacher = &noCacher{} 10 | 11 | var ErrCacherKeyNotFound = errors.New("embedding/cached: key not found in cacher") 12 | 13 | type Cacher interface { 14 | // Set stores the value in the cache with the given key. 15 | // If the key already exists, it will be overwritten. 16 | Set(ctx context.Context, key string, value []float64, expire time.Duration) error 17 | 18 | // Get retrieves the value from the cache with the given key. 19 | // If the key does not exist, the err will be ErrCacherKeyNotFound. 20 | // If the value is not of type []float64, it returns an error. 21 | Get(ctx context.Context, key string) ([]float64, error) 22 | } 23 | 24 | type noCacher struct{} 25 | 26 | var _ Cacher = (*noCacher)(nil) 27 | 28 | func (c *noCacher) Set(_ context.Context, _ string, _ []float64, _ time.Duration) error { 29 | return nil 30 | } 31 | 32 | func (c *noCacher) Get(_ context.Context, _ string) ([]float64, error) { 33 | return nil, ErrCacherKeyNotFound 34 | } 35 | -------------------------------------------------------------------------------- /eino/components/embedding/cached/cacher_test.go: -------------------------------------------------------------------------------- 1 | package cached 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestCacher_noCacher(t *testing.T) { 11 | c := &noCacher{} 12 | ctx := context.Background() 13 | 14 | assert.NoError(t, c.Set(ctx, "key", []float64{1.0, 2.0}, 0)) 15 | value, err := c.Get(ctx, "key") 16 | assert.Error(t, err) 17 | assert.Equal(t, ErrCacherKeyNotFound, err) 18 | assert.Nil(t, value) 19 | } 20 | -------------------------------------------------------------------------------- /eino/components/embedding/cached/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "crypto/md5" 6 | "log" 7 | 8 | "github.com/cloudwego/eino/components/embedding" 9 | cachedredis "github.com/go-fries/fries/eino/components/embedding/cached/redis/v3" 10 | "github.com/go-fries/fries/eino/components/embedding/cached/v3" 11 | "github.com/redis/go-redis/v9" 12 | ) 13 | 14 | func main() { 15 | rdb := redis.NewClient(&redis.Options{ 16 | Addr: "localhost:6379", 17 | }) 18 | 19 | // the original embedder, you can replace it with any other embedder implementation 20 | // It's only a example, you need to bring a real embedder implementation here. 21 | var originalEmbedder embedding.Embedder 22 | // embedder, err := openai.NewEmbedder(ctx, &openai.EmbeddingConfig{ 23 | // APIKey: accessKey, 24 | // } 25 | // ... 26 | 27 | embedder := cached.NewEmbedder(originalEmbedder, 28 | cached.WithCacher(cachedredis.NewCacher(rdb)), // using Redis as the cache 29 | cached.WithGenerator(cached.NewHashGenerator(md5.New())), // using md5 for generating unique keys 30 | ) 31 | 32 | embeddings, err := embedder.EmbedStrings(context.Background(), []string{"hello", "how are you"}) 33 | if err != nil { 34 | log.Fatal(err) 35 | } 36 | 37 | log.Printf("embeddings: %v", embeddings) 38 | } 39 | -------------------------------------------------------------------------------- /encrypter/README.md: -------------------------------------------------------------------------------- 1 | # Encrypter 2 | 3 | ## Usage 4 | 5 | ```go 6 | package main 7 | 8 | import "github.com/go-kratos-ecosystem/components/v2/encrypter" 9 | 10 | func main() { 11 | e := encrypter.New("EAFBSPAXDCIOGRUVNERQGXPYGPNKYATM") 12 | 13 | ciphertext, _ := e.Encrypt("test") 14 | plaintext, _ := e.Decrypt(ciphertext) 15 | 16 | println(ciphertext, plaintext) // I-UVz6tds3MlRX-1afR36cLcmMw= test 17 | } 18 | ``` -------------------------------------------------------------------------------- /encrypter/encrypter_test.go: -------------------------------------------------------------------------------- 1 | package encrypter 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestNew(t *testing.T) { 10 | assert.Equal(t, &Encrypter{ 11 | key: []byte("test"), 12 | }, New("test")) 13 | } 14 | 15 | func TestEncrypter(t *testing.T) { 16 | e := New("EAFBSPAXDCIOGRUVNERQGXPYGPNKYATM") 17 | 18 | ciphertext, _ := e.Encrypt("test") 19 | plaintext, _ := e.Decrypt(ciphertext) 20 | 21 | println(ciphertext, plaintext) 22 | 23 | assert.NotNil(t, ciphertext) 24 | assert.NotNil(t, plaintext) 25 | assert.Equal(t, "test", plaintext) 26 | } 27 | 28 | func TestEncrypter_Error(t *testing.T) { 29 | e := New("test") 30 | 31 | _, err1 := e.Encrypt("test") 32 | assert.Error(t, err1) 33 | 34 | _, err2 := e.Decrypt("test") 35 | assert.Error(t, err2) 36 | } 37 | 38 | func TestEncrypter_Decrypt_Error(t *testing.T) { 39 | e := New("EAFBSPAXDCIOGRUVNERQGXPYGPNKYATM") 40 | 41 | _, err1 := e.Decrypt("j9_mcZXKVlInk8bbpBqJOpmDp") 42 | assert.Error(t, err1) 43 | 44 | _, err2 := e.Decrypt("MQ==") 45 | assert.Error(t, err2) 46 | } 47 | -------------------------------------------------------------------------------- /encrypter/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/encrypter/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /encrypter/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /ent/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/ent/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/go-kratos/kratos/v2 v2.8.4 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/kr/text v0.2.0 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.1 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /ent/logger.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/go-kratos/kratos/v2/log" 7 | ) 8 | 9 | type Logger func(...any) 10 | 11 | func NewLogger(logger log.Logger, levels ...log.Level) Logger { 12 | level := log.LevelDebug 13 | if len(levels) > 0 { 14 | level = levels[0] 15 | } 16 | 17 | return func(args ...any) { 18 | _ = logger.Log(level, "msg", fmt.Sprint(args...)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ent/logger_test.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/go-kratos/kratos/v2/log" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestLogger(t *testing.T) { 11 | logger := NewLogger(log.DefaultLogger, log.LevelInfo) 12 | assert.NotPanics(t, func() { 13 | logger("test") 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /ent/multidriver/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/ent/multidriver/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | entgo.io/ent v0.14.4 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/google/uuid v1.6.0 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.1 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /ent/multidriver/go.sum: -------------------------------------------------------------------------------- 1 | entgo.io/ent v0.14.4 h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI= 2 | entgo.io/ent v0.14.4/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 6 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 10 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 14 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | -------------------------------------------------------------------------------- /ent/multidriver/option.go: -------------------------------------------------------------------------------- 1 | package multidriver 2 | 3 | import "entgo.io/ent/dialect" 4 | 5 | type Option func(*Driver) 6 | 7 | func WithWriter(w dialect.Driver) Option { 8 | return func(d *Driver) { 9 | d.writer = w 10 | } 11 | } 12 | 13 | func WithReaders(r ...dialect.Driver) Option { 14 | return func(d *Driver) { 15 | d.readers = r 16 | } 17 | } 18 | 19 | func WithPolicy(p Policy) Option { 20 | return func(d *Driver) { 21 | d.policy = p 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ent/multidriver/policy.go: -------------------------------------------------------------------------------- 1 | package multidriver 2 | 3 | import ( 4 | "math/rand" 5 | "sync/atomic" 6 | 7 | "entgo.io/ent/dialect" 8 | ) 9 | 10 | type Policy interface { 11 | Resolve([]dialect.Driver) dialect.Driver 12 | } 13 | 14 | type PolicyFunc func([]dialect.Driver) dialect.Driver 15 | 16 | func (f PolicyFunc) Resolve(drivers []dialect.Driver) dialect.Driver { 17 | return f(drivers) 18 | } 19 | 20 | func RoundRobinPolicy() Policy { 21 | var i int 22 | return PolicyFunc(func(drivers []dialect.Driver) dialect.Driver { 23 | i = (i + 1) % len(drivers) 24 | return drivers[i] 25 | }) 26 | } 27 | 28 | func StrictRoundRobinPolicy() Policy { 29 | var i int64 30 | return PolicyFunc(func(drivers []dialect.Driver) dialect.Driver { 31 | return drivers[int(atomic.AddInt64(&i, 1))%len(drivers)] 32 | }) 33 | } 34 | 35 | func RandomPolicy() Policy { 36 | return PolicyFunc(func(drivers []dialect.Driver) dialect.Driver { 37 | return drivers[rand.Intn(len(drivers))] 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /ent/multidriver/policy_test.go: -------------------------------------------------------------------------------- 1 | package multidriver 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | "testing" 7 | 8 | "entgo.io/ent/dialect" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | var ( 13 | driver1 = &dialect.DebugDriver{} 14 | driver2 = &dialect.DebugDriver{} 15 | driver3 = &dialect.DebugDriver{} 16 | ) 17 | 18 | // var driver1, driver2, driver3 dialect.Driver 19 | 20 | func TestPolicy_RoundRobinPolicy(t *testing.T) { 21 | p1 := RoundRobinPolicy() 22 | p2 := StrictRoundRobinPolicy() 23 | drivers := []dialect.Driver{driver1, driver2, driver3} 24 | 25 | for i := 0; i < 10; i++ { 26 | assert.Same(t, drivers[(i+1)%len(drivers)], p1.Resolve(drivers)) 27 | assert.Same(t, drivers[(i+1)%len(drivers)], p2.Resolve(drivers)) 28 | } 29 | } 30 | 31 | func TestPolicy_RandomPolicy(t *testing.T) { 32 | p := RandomPolicy() 33 | drivers := []dialect.Driver{driver1, driver2, driver3} 34 | 35 | for i := 0; i < 10; i++ { 36 | assert.Contains(t, drivers, p.Resolve(drivers)) 37 | } 38 | } 39 | 40 | func BenchmarkPolicy_StrictRoundRobinPolicy(b *testing.B) { 41 | p := StrictRoundRobinPolicy() 42 | drivers := []dialect.Driver{driver1, driver2, driver3} 43 | 44 | var i int64 45 | var mu sync.Mutex 46 | b.RunParallel(func(pb *testing.PB) { 47 | for pb.Next() { 48 | mu.Lock() 49 | assert.Same(b, drivers[int(atomic.AddInt64(&i, 1))%len(drivers)], p.Resolve(drivers)) 50 | mu.Unlock() 51 | } 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /env/context.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import "context" 4 | 5 | type currentEnvKey struct{} 6 | 7 | func NewContext(ctx context.Context, env Env) context.Context { 8 | return context.WithValue(ctx, currentEnvKey{}, env) 9 | } 10 | 11 | func FromContext(ctx context.Context) (Env, bool) { 12 | if env, ok := ctx.Value(currentEnvKey{}).(Env); ok { 13 | return env, true 14 | } 15 | 16 | return "", false 17 | } 18 | -------------------------------------------------------------------------------- /env/context_test.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestContext(t *testing.T) { 11 | ctx := context.Background() 12 | 13 | env1, ok1 := FromContext(ctx) 14 | assert.NotEqual(t, Dev, env1) 15 | assert.False(t, ok1) 16 | assert.Equal(t, Env(""), env1) 17 | 18 | envCtx := NewContext(ctx, Dev) 19 | env2, ok2 := FromContext(envCtx) 20 | assert.Equal(t, Dev, env2) 21 | assert.True(t, ok2) 22 | } 23 | -------------------------------------------------------------------------------- /env/env.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | type Env string 4 | 5 | var ( 6 | Dev Env = "dev" 7 | Prod Env = "prod" 8 | Debug Env = "debug" 9 | Stage Env = "stage" 10 | ) 11 | 12 | func (e Env) String() string { 13 | return string(e) 14 | } 15 | 16 | func (e Env) Is(envs ...Env) bool { 17 | for _, env := range envs { 18 | if e == env { 19 | return true 20 | } 21 | } 22 | 23 | return false 24 | } 25 | 26 | var currentEnv = Prod 27 | 28 | func SetEnv(env Env) { 29 | currentEnv = env 30 | } 31 | 32 | func GetEnv() Env { 33 | return currentEnv 34 | } 35 | 36 | func Is(envs ...Env) bool { 37 | return currentEnv.Is(envs...) 38 | } 39 | 40 | func IsDev() bool { 41 | return Is(Dev) 42 | } 43 | 44 | func IsProd() bool { 45 | return Is(Prod) 46 | } 47 | 48 | func IsDebug() bool { 49 | return Is(Debug) 50 | } 51 | 52 | func IsStage() bool { 53 | return Is(Stage) 54 | } 55 | 56 | func IsUseString(envs ...string) bool { 57 | for _, env := range envs { 58 | if currentEnv == Env(env) { 59 | return true 60 | } 61 | } 62 | 63 | return false 64 | } 65 | -------------------------------------------------------------------------------- /env/env_test.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestEnv(t *testing.T) { 10 | assert.Equal(t, Env("dev"), Dev) 11 | assert.Equal(t, Env("prod"), Prod) 12 | assert.Equal(t, Env("debug"), Debug) 13 | assert.Equal(t, Env("stage"), Stage) 14 | } 15 | 16 | func TestString(t *testing.T) { 17 | assert.Equal(t, "dev", Dev.String()) 18 | assert.Equal(t, "prod", Prod.String()) 19 | assert.Equal(t, "debug", Debug.String()) 20 | assert.Equal(t, "stage", Stage.String()) 21 | } 22 | 23 | func TestIs(t *testing.T) { 24 | SetEnv(Dev) 25 | assert.True(t, Is(Dev)) 26 | assert.False(t, Is(Prod)) 27 | assert.False(t, Is(Debug)) 28 | assert.False(t, Is(Stage)) 29 | assert.True(t, Is(Dev, Prod)) 30 | assert.True(t, IsDev()) 31 | assert.False(t, IsProd()) 32 | assert.False(t, IsDebug()) 33 | assert.False(t, IsStage()) 34 | assert.True(t, IsUseString("dev")) 35 | assert.False(t, IsUseString("prod")) 36 | assert.True(t, IsUseString("dev", "prod")) 37 | assert.True(t, Is("dev")) 38 | assert.False(t, Is("prod")) 39 | assert.Equal(t, Dev, GetEnv()) 40 | 41 | SetEnv(Prod) 42 | assert.True(t, Is(Prod)) 43 | assert.False(t, Is(Dev)) 44 | assert.Equal(t, Prod, GetEnv()) 45 | } 46 | 47 | func TestCustom(t *testing.T) { 48 | SetEnv("online") 49 | 50 | assert.True(t, Is("online")) 51 | assert.False(t, Is("dev")) 52 | } 53 | -------------------------------------------------------------------------------- /env/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/env/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /env/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /env/provider.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type Provider struct { 8 | env Env 9 | } 10 | 11 | func NewProvider(env Env) *Provider { 12 | return &Provider{env: env} 13 | } 14 | 15 | func (p *Provider) Bootstrap(ctx context.Context) (context.Context, error) { 16 | SetEnv(p.env) 17 | return NewContext(ctx, p.env), nil 18 | } 19 | 20 | func (p *Provider) Terminate(ctx context.Context) (context.Context, error) { 21 | return ctx, nil 22 | } 23 | -------------------------------------------------------------------------------- /env/provider_test.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestProvider(t *testing.T) { 11 | assert.False(t, Is(Debug)) 12 | 13 | p := NewProvider(Debug) 14 | ctx, err := p.Bootstrap(context.Background()) 15 | assert.NoError(t, err) 16 | 17 | e1, ok := FromContext(ctx) 18 | assert.True(t, ok) 19 | assert.Equal(t, Debug, e1) 20 | 21 | ctx2, err := p.Terminate(ctx) 22 | assert.NoError(t, err) 23 | 24 | e2, ok := FromContext(ctx2) 25 | assert.True(t, ok) 26 | assert.Equal(t, Debug, e2) 27 | } 28 | -------------------------------------------------------------------------------- /errors/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/errors/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/go-kratos/kratos/v2 v2.8.4 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/kr/text v0.2.0 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | golang.org/x/sys v0.33.0 // indirect 15 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 16 | google.golang.org/grpc v1.73.0 // indirect 17 | google.golang.org/protobuf v1.36.6 // indirect 18 | gopkg.in/yaml.v3 v3.0.1 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /errors/group.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import "errors" 4 | 5 | var multipleErrors = "multiple errors" 6 | 7 | type Group struct { 8 | errors []error 9 | } 10 | 11 | func NewGroup() *Group { 12 | return &Group{ 13 | errors: make([]error, 0), 14 | } 15 | } 16 | 17 | func (g *Group) Add(errs ...error) *Group { 18 | for _, err := range errs { 19 | if err == nil { 20 | continue 21 | } 22 | 23 | g.errors = append(g.errors, err) 24 | } 25 | 26 | return g 27 | } 28 | 29 | func (g *Group) Error() string { 30 | switch len(g.errors) { 31 | case 0: 32 | return "" 33 | case 1: 34 | return g.errors[0].Error() 35 | default: 36 | return multipleErrors 37 | } 38 | } 39 | 40 | func (g *Group) Errors() []error { 41 | return g.errors 42 | } 43 | 44 | func (g *Group) Len() int { 45 | return len(g.errors) 46 | } 47 | 48 | func (g *Group) Has(err error) bool { 49 | for _, e := range g.errors { 50 | if errors.Is(e, err) { 51 | return true 52 | } 53 | } 54 | 55 | return false 56 | } 57 | 58 | func (g *Group) First() error { 59 | if len(g.errors) == 0 { 60 | return nil 61 | } 62 | 63 | return g.errors[0] 64 | } 65 | 66 | func (g *Group) IsNil() bool { 67 | return len(g.errors) == 0 68 | } 69 | -------------------------------------------------------------------------------- /errors/group_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var ( 11 | err1 = errors.New("err1") 12 | err2 = errors.New("err2") 13 | err3 = errors.New("err3") 14 | ) 15 | 16 | func TestGroup(t *testing.T) { 17 | g := NewGroup() 18 | 19 | assert.Equal(t, 0, g.Len()) 20 | assert.Equal(t, g, g.Add(nil, err1, err2)) 21 | 22 | assert.Equal(t, 2, g.Len()) 23 | assert.Equal(t, multipleErrors, g.Error()) 24 | assert.Equal(t, []error{err1, err2}, g.Errors()) 25 | assert.True(t, g.Has(err1)) 26 | assert.True(t, g.Has(err2)) 27 | assert.False(t, g.Has(err3)) 28 | assert.Equal(t, err1, g.First()) 29 | } 30 | 31 | func TestGroup_Error(t *testing.T) { 32 | g := NewGroup() 33 | assert.Equal(t, "", g.Error()) 34 | 35 | assert.Equal(t, g, g.Add(err1)) 36 | assert.Equal(t, "err1", g.Error()) 37 | 38 | assert.Equal(t, g, g.Add(err2)) 39 | assert.Equal(t, multipleErrors, g.Error()) 40 | } 41 | 42 | func TestGroup_First(t *testing.T) { 43 | g := NewGroup() 44 | assert.Nil(t, g.First()) 45 | 46 | assert.Equal(t, g, g.Add(err1)) 47 | assert.Equal(t, err1, g.First()) 48 | 49 | assert.Equal(t, g, g.Add(err2)) 50 | assert.Equal(t, err1, g.First()) 51 | } 52 | 53 | func TestGroup_IsNil(t *testing.T) { 54 | g := NewGroup() 55 | assert.True(t, g.IsNil()) 56 | 57 | assert.Equal(t, g, g.Add(err1)) 58 | assert.False(t, g.IsNil()) 59 | } 60 | -------------------------------------------------------------------------------- /errors/timeout.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type TimeoutError struct { 10 | Timeout time.Duration 11 | err error 12 | } 13 | 14 | func NewTimeoutError(timeout time.Duration, err error) *TimeoutError { 15 | return &TimeoutError{ 16 | Timeout: timeout, 17 | err: err, 18 | } 19 | } 20 | 21 | func (e *TimeoutError) Error() string { 22 | return fmt.Sprintf("timeout after %s: %v", e.Timeout, e.err) 23 | } 24 | 25 | func (e *TimeoutError) Unwrap() error { 26 | return e.err 27 | } 28 | 29 | func IsTimeoutError(err error) bool { 30 | var target *TimeoutError 31 | return errors.As(err, &target) 32 | } 33 | -------------------------------------------------------------------------------- /errors/timeout_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestTimeoutError(t *testing.T) { 11 | err := NewTimeoutError(5*time.Second, nil) 12 | assert.Equal(t, "timeout after 5s: ", err.Error()) 13 | assert.Nil(t, err.Unwrap()) 14 | assert.True(t, IsTimeoutError(err)) 15 | assert.Equal(t, 5*time.Second, err.Timeout) 16 | assert.Implements(t, (*error)(nil), err) 17 | } 18 | -------------------------------------------------------------------------------- /event/context.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | import "context" 4 | 5 | type contextKey struct{} 6 | 7 | func NewContext(ctx context.Context, d *Dispatcher) context.Context { 8 | return context.WithValue(ctx, contextKey{}, d) 9 | } 10 | 11 | func FromContext(ctx context.Context) (*Dispatcher, bool) { 12 | d, ok := ctx.Value(contextKey{}).(*Dispatcher) 13 | return d, ok 14 | } 15 | -------------------------------------------------------------------------------- /event/context_test.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestContext(t *testing.T) { 11 | d1, ok1 := FromContext(context.Background()) 12 | assert.False(t, ok1) 13 | assert.Nil(t, d1) 14 | 15 | var d *Dispatcher 16 | ctx := NewContext(context.Background(), d) 17 | 18 | d2, ok2 := FromContext(ctx) 19 | assert.True(t, ok2) 20 | assert.Equal(t, d, d2) 21 | } 22 | -------------------------------------------------------------------------------- /event/example/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/event/example/v3 2 | 3 | go 1.23.0 4 | 5 | replace ( 6 | github.com/go-fries/fries/event/middleware/recovery/v3 => ../middleware/recovery/ 7 | github.com/go-fries/fries/event/v3 => ../ 8 | ) 9 | 10 | require ( 11 | github.com/go-fries/fries/event/middleware/recovery/v3 v3.4.0 12 | github.com/go-fries/fries/event/v3 v3.4.0 13 | ) 14 | 15 | require golang.org/x/sync v0.15.0 // indirect 16 | -------------------------------------------------------------------------------- /event/example/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= 8 | golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /event/example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/go-fries/fries/event/middleware/recovery/v3" 8 | "github.com/go-fries/fries/event/v3" 9 | ) 10 | 11 | func main() { 12 | dispatcher := event.NewDispatcher(event.WithoutError(), event.WithParallel(1)) 13 | 14 | // Use middleware 15 | dispatcher.Use( 16 | recovery.New(), 17 | ) 18 | 19 | dispatcher.RegisterListeners( 20 | event.AdaptListener(event.ListenerFunc[*UserEvent](func(_ context.Context, event *UserEvent) error { 21 | fmt.Println("this is user func listener, the name is", event.Name) 22 | return nil 23 | })), 24 | event.AdaptListenerFunc(func(_ context.Context, event *UserEvent) error { 25 | fmt.Println("this is user func listener, the name is", event.Name) 26 | return nil 27 | }), 28 | event.AdaptListener(&UserListener{}), 29 | ) 30 | 31 | if err := dispatcher.Dispatch(context.Background(), &UserEvent{Name: "z"}, 32 | event.WithDispatchWithError()); err != nil { 33 | fmt.Println(err) 34 | } 35 | 36 | // Wait for all listeners to finish processing 37 | dispatcher.Wait() 38 | } 39 | 40 | type UserEvent struct { 41 | Name string 42 | } 43 | 44 | type UserListener struct{} 45 | 46 | func (u *UserListener) Handle(_ context.Context, event *UserEvent) error { 47 | fmt.Println("this is user struct listener, the name is", event.Name) 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /event/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/event/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/stretchr/testify v1.10.0 7 | golang.org/x/sync v0.15.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /event/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= 8 | golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 12 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 13 | -------------------------------------------------------------------------------- /event/listener.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type Listener[T any] interface { 8 | Handle(ctx context.Context, event T) error 9 | } 10 | 11 | type AnyListener interface { 12 | Handle(ctx context.Context, event any) error 13 | } 14 | 15 | // listenerAdapter adapts a Listener[T] to an AnyListener. 16 | type listenerAdapter[T any] struct { 17 | L Listener[T] 18 | } 19 | 20 | // AdaptListener adapts a Listener[T] to an AnyListener. 21 | func AdaptListener[T any](l Listener[T]) AnyListener { 22 | return &listenerAdapter[T]{L: l} 23 | } 24 | 25 | func (a *listenerAdapter[T]) Handle(ctx context.Context, event any) error { 26 | if e, ok := event.(T); ok { 27 | return a.L.Handle(ctx, e) 28 | } 29 | return nil 30 | } 31 | 32 | // ListenerFunc is a function type that implements the Listener interface. 33 | type ListenerFunc[T any] func(ctx context.Context, event T) error 34 | 35 | var _ Listener[string] = ListenerFunc[string](nil) 36 | 37 | func (f ListenerFunc[T]) Handle(ctx context.Context, event T) error { 38 | return f(ctx, event) 39 | } 40 | 41 | // AdaptListenerFunc adapts a function to the Listener interface. 42 | func AdaptListenerFunc[T any](f func(ctx context.Context, event T) error) AnyListener { 43 | return AdaptListener(ListenerFunc[T](f)) 44 | } 45 | -------------------------------------------------------------------------------- /event/middleware.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | import "context" 4 | 5 | type Handler func(ctx context.Context, event any) error 6 | 7 | type Middleware func(Handler) Handler 8 | 9 | func Chain(mws ...Middleware) Middleware { 10 | return func(h Handler) Handler { 11 | for i := len(mws) - 1; i >= 0; i-- { 12 | h = mws[i](h) 13 | } 14 | return h 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /event/middleware/recovery/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/event/middleware/recovery/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/event/v3 => ../../ 6 | 7 | require ( 8 | github.com/go-fries/fries/event/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | golang.org/x/sync v0.15.0 // indirect 16 | gopkg.in/yaml.v3 v3.0.1 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /event/middleware/recovery/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= 8 | golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 12 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 13 | -------------------------------------------------------------------------------- /event/provider.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type Provider struct { 8 | *Dispatcher 9 | } 10 | 11 | func NewProvider(dispatcher *Dispatcher) *Provider { 12 | return &Provider{ 13 | Dispatcher: dispatcher, 14 | } 15 | } 16 | 17 | func (p *Provider) Bootstrap(ctx context.Context) (context.Context, error) { 18 | return NewContext(ctx, p.Dispatcher), nil 19 | } 20 | 21 | func (p *Provider) Terminate(ctx context.Context) (context.Context, error) { 22 | p.Wait() 23 | return ctx, nil 24 | } 25 | -------------------------------------------------------------------------------- /event/provider_test.go: -------------------------------------------------------------------------------- 1 | package event 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestProvider(t *testing.T) { 11 | d := NewDispatcher() 12 | p := NewProvider(d) 13 | p.RegisterListeners(nil) 14 | 15 | ctx, err := p.Bootstrap(context.Background()) 16 | assert.NoError(t, err) 17 | 18 | d1, ok := FromContext(ctx) 19 | assert.True(t, ok) 20 | assert.Equal(t, d, d1) 21 | 22 | ctx, err = p.Terminate(ctx) 23 | assert.NoError(t, err) 24 | 25 | d2, ok := FromContext(ctx) 26 | assert.True(t, ok) 27 | assert.Equal(t, d, d2) 28 | } 29 | -------------------------------------------------------------------------------- /eventbus/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/eventbus/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /eventbus/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /examples/cache/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/examples/cache/v3 2 | 3 | go 1.23.0 4 | 5 | replace ( 6 | github.com/go-fries/fries/cache/redis/v3 => ../../cache/redis/ 7 | github.com/go-fries/fries/cache/v3 => ../../cache/ 8 | github.com/go-fries/fries/codec/json/v3 => ../../codec/json/ 9 | github.com/go-fries/fries/codec/v3 => ../../codec/ 10 | github.com/go-fries/fries/locker/redis/v3 => ../../locker/redis/ 11 | github.com/go-fries/fries/locker/v3 => ../../locker/ 12 | ) 13 | 14 | require ( 15 | github.com/go-fries/fries/cache/redis/v3 v3.4.0 16 | github.com/go-fries/fries/cache/v3 v3.4.0 17 | github.com/redis/go-redis/v9 v9.9.0 18 | ) 19 | 20 | require ( 21 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 22 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 23 | github.com/go-fries/fries/codec/json/v3 v3.4.0 // indirect 24 | github.com/go-fries/fries/codec/v3 v3.4.0 // indirect 25 | github.com/go-fries/fries/locker/redis/v3 v3.4.0 // indirect 26 | github.com/go-fries/fries/locker/v3 v3.4.0 // indirect 27 | github.com/google/uuid v1.6.0 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /examples/cache/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | 8 | "github.com/redis/go-redis/v9" 9 | 10 | redisStore "github.com/go-fries/fries/cache/redis/v3" 11 | "github.com/go-fries/fries/cache/v3" 12 | ) 13 | 14 | var ctx = context.Background() 15 | 16 | type User struct { 17 | Name string 18 | Age int 19 | } 20 | 21 | func main() { 22 | // 创建个 Redis 连接客户端 23 | rdb := redis.NewClient(&redis.Options{ 24 | Addr: "localhost:6379", 25 | }) 26 | defer rdb.Close() // nolint:errcheck 27 | 28 | // create a redis store 29 | store := redisStore.New(rdb, redisStore.Prefix("example:cache")) 30 | 31 | // create a cache repository 32 | repository := cache.NewRepository(store) 33 | 34 | // set cache 35 | ok, err := repository.Set(ctx, "key", User{ 36 | Name: "example", 37 | Age: 18, //nolint:mnd 38 | }, time.Second*10) //nolint:mnd 39 | if err != nil { 40 | log.Fatal(err) 41 | } 42 | _ = ok 43 | 44 | // get cache 45 | var user User 46 | err = repository.Get(ctx, "key", &user) 47 | if err != nil { 48 | log.Fatal(err) 49 | } 50 | log.Printf("user: %+v", user) 51 | 52 | // remember 53 | user2, err := cache.Remember(ctx, repository, "key2", time.Second*10, func() (User, error) { //nolint:mnd 54 | return User{ 55 | Name: "example2", 56 | Age: 20, //nolint:mnd 57 | }, nil 58 | }) 59 | if err != nil { 60 | log.Fatal(err) 61 | } 62 | log.Printf("user2: %+v", user2) 63 | } 64 | -------------------------------------------------------------------------------- /examples/cloudevents/amqp091/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/examples/cloudevents/amqp091/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/cloudevents/protocol/amqp091/v3 => ../../../cloudevents/protocol/amqp091/ 6 | 7 | require ( 8 | github.com/cloudevents/sdk-go/v2 v2.16.0 9 | github.com/go-fries/fries/cloudevents/protocol/amqp091/v3 v3.4.0 10 | github.com/google/uuid v1.6.0 11 | github.com/rabbitmq/amqp091-go v1.10.0 12 | ) 13 | 14 | require ( 15 | github.com/json-iterator/go v1.1.12 // indirect 16 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 17 | github.com/modern-go/reflect2 v1.0.2 // indirect 18 | go.uber.org/multierr v1.11.0 // indirect 19 | go.uber.org/zap v1.27.0 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /examples/cloudevents/eventdispatcher/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/examples/cloudevents/eventdispatcher/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/cloudevents/eventdispatcher/v3 => ../../../cloudevents/eventdispatcher/ 6 | 7 | require ( 8 | github.com/cloudevents/sdk-go/v2 v2.16.0 9 | github.com/go-fries/fries/cloudevents/eventdispatcher/v3 v3.4.0 10 | ) 11 | 12 | require ( 13 | github.com/google/uuid v1.6.0 // indirect 14 | github.com/json-iterator/go v1.1.12 // indirect 15 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 16 | github.com/modern-go/reflect2 v1.0.2 // indirect 17 | go.uber.org/multierr v1.11.0 // indirect 18 | go.uber.org/zap v1.27.0 // indirect 19 | golang.org/x/sync v0.15.0 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /examples/cloudevents/eventdispatcher/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | cloudevents "github.com/cloudevents/sdk-go/v2" 8 | "github.com/go-fries/fries/cloudevents/eventdispatcher/v3" 9 | ) 10 | 11 | type ExampleEvent struct { 12 | UserID string 13 | } 14 | 15 | type ExampleListener struct{} 16 | 17 | func (l *ExampleListener) Handle(ctx context.Context, event *ExampleEvent) error { 18 | log.Printf("Received event for user: %s", event.UserID) 19 | return nil 20 | } 21 | 22 | func main() { 23 | client, err := cloudevents.NewClient(nil) // Replace nil with your protocol configuration if needed 24 | if err != nil { 25 | log.Fatalf("Failed to create client: %v", err) 26 | } 27 | 28 | dispatcher := eventdispatcher.NewDispatcher() 29 | 30 | // the method one: 31 | dispatcher.AddListener( 32 | "example.type", 33 | eventdispatcher.ListenerFunc[*ExampleEvent](func(ctx context.Context, event *ExampleEvent) error { 34 | log.Printf("Received event for user: %s", event.UserID) 35 | return nil 36 | }), 37 | ) 38 | // the method two: 39 | dispatcher.AddListener( 40 | "example.type", 41 | eventdispatcher.ListenerAdapter(&ExampleListener{}), 42 | ) 43 | 44 | _ = client.StartReceiver(context.Background(), func(ctx context.Context, event cloudevents.Event) error { 45 | log.Printf("Received event: %v", event) 46 | return dispatcher.Dispatch(ctx, event) 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /examples/otel/otlp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/go-fries/fries/otel/otlp/v3" 7 | "go.opentelemetry.io/otel/attribute" 8 | ) 9 | 10 | func main() { 11 | ctx := context.TODO() 12 | 13 | // transport 14 | transport := otlp.NewGRPCTransport("localhost:4317", 15 | otlp.WithGRPCTransportInsecure(true), 16 | ) 17 | 18 | // client 19 | client := otlp.NewClient( 20 | otlp.WithServiceName("service-name"), 21 | otlp.WithDeploymentEnvironmentName("production"), 22 | otlp.WithAttributes( 23 | attribute.String("key", "value"), 24 | // ... 25 | ), 26 | otlp.WithTransport(transport), 27 | ) 28 | 29 | if err := client.Configure(ctx); err != nil { 30 | panic(err) 31 | } 32 | 33 | defer client.Shutdown(ctx) //nolint:errcheck 34 | 35 | // do something 36 | } 37 | -------------------------------------------------------------------------------- /filesystem/filesystem_test.go: -------------------------------------------------------------------------------- 1 | package filesystem 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestStorage(t *testing.T) { 11 | var ( 12 | noop = NoopFilesystem{} 13 | ctx = context.Background() 14 | ) 15 | 16 | _, err := noop.Read(ctx, "test") 17 | assert.NoError(t, err) 18 | 19 | assert.NoError(t, noop.Write(ctx, "noop", []byte("noop"))) 20 | assert.NoError(t, noop.Delete(ctx, "noop")) 21 | 22 | has, err := noop.Exists(ctx, "noop") 23 | assert.NoError(t, err) 24 | assert.True(t, has) 25 | 26 | assert.NoError(t, noop.Rename(ctx, "noop", "noop")) 27 | assert.NoError(t, noop.Link(ctx, "noop", "noop")) 28 | assert.NoError(t, noop.Symlink(ctx, "noop", "noop")) 29 | 30 | files, err := noop.Files(ctx, "noop") 31 | assert.NoError(t, err) 32 | assert.Len(t, files, 0) 33 | 34 | allFiles, err := noop.AllFiles(ctx, "noop") 35 | assert.NoError(t, err) 36 | assert.Len(t, allFiles, 0) 37 | 38 | directories, err := noop.Directories(ctx, "noop") 39 | assert.NoError(t, err) 40 | assert.Len(t, directories, 0) 41 | 42 | allDirectories, err := noop.AllDirectories(ctx, "noop") 43 | assert.NoError(t, err) 44 | assert.Len(t, allDirectories, 0) 45 | 46 | isFile, err := noop.IsFile(ctx, "noop") 47 | assert.NoError(t, err) 48 | assert.False(t, isFile) 49 | 50 | isDir, err := noop.IsDir(ctx, "noop") 51 | assert.NoError(t, err) 52 | assert.False(t, isDir) 53 | } 54 | -------------------------------------------------------------------------------- /filesystem/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/filesystem/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /filesystem/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /filesystem/local/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/filesystem/local/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/filesystem/v3 => ../ 6 | 7 | require ( 8 | github.com/go-fries/fries/filesystem/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | gopkg.in/yaml.v3 v3.0.1 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /filesystem/local/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /filesystem/local/testfile/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /filesystem/oss/filesystem_test.go: -------------------------------------------------------------------------------- 1 | package oss 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestFilesystem(t *testing.T) { 10 | assert.NotNil(t, New(nil, "bucket")) 11 | } 12 | -------------------------------------------------------------------------------- /filesystem/oss/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/filesystem/oss/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/filesystem/v3 => ../ 6 | 7 | require ( 8 | github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.2 9 | github.com/go-fries/fries/filesystem/v3 v3.4.0 10 | github.com/stretchr/testify v1.10.0 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/pmezard/go-difflib v1.0.0 // indirect 16 | golang.org/x/time v0.12.0 // indirect 17 | gopkg.in/yaml.v3 v3.0.1 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /filesystem/oss/go.sum: -------------------------------------------------------------------------------- 1 | github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.2 h1:YNsVAVaO3xAfNqnsjcOeZx+htocoFR2Oh8onhVp7PcM= 2 | github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.2.2/go.mod h1:FTzydeQVmR24FI0D6XWUOMKckjXehM/jgMn1xC+DA9M= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 8 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= 10 | golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 13 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 14 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 15 | -------------------------------------------------------------------------------- /filesystem/paths.go: -------------------------------------------------------------------------------- 1 | package filesystem 2 | 3 | import "strings" 4 | 5 | type PathPrefixer struct { 6 | prefix string 7 | separator string 8 | } 9 | 10 | type PathPrefixerOption func(*PathPrefixer) 11 | 12 | func WithPathPrefixerSeparator(separator string) PathPrefixerOption { 13 | return func(p *PathPrefixer) { 14 | p.separator = separator 15 | } 16 | } 17 | 18 | func NewPathPrefixer(prefix string, opts ...PathPrefixerOption) *PathPrefixer { 19 | prefixer := &PathPrefixer{ 20 | prefix: strings.TrimRight(prefix, "\\/"), 21 | separator: "/", 22 | } 23 | for _, opt := range opts { 24 | opt(prefixer) 25 | } 26 | 27 | if prefixer.prefix != "" || prefix == prefixer.separator { 28 | prefixer.prefix += prefixer.separator 29 | } 30 | 31 | return prefixer 32 | } 33 | 34 | func (p *PathPrefixer) Prefix(path string) string { 35 | return p.prefix + strings.TrimLeft(path, "\\/") 36 | } 37 | -------------------------------------------------------------------------------- /filesystem/repository_test.go: -------------------------------------------------------------------------------- 1 | package filesystem 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestNoopRepository(t *testing.T) { 11 | repo := NewRepository(NoopFilesystem{}) 12 | ctx := context.Background() 13 | 14 | assert.NoError(t, repo.Put(ctx, "noop", []byte("noop"))) 15 | assert.NoError(t, repo.Destroy(ctx, "noop")) 16 | 17 | exists, err := repo.Exists(ctx, "noop") 18 | assert.NoError(t, err) 19 | assert.True(t, exists) 20 | 21 | missing, err := repo.Missing(ctx, "noop") 22 | assert.NoError(t, err) 23 | assert.False(t, missing) 24 | 25 | assert.NoError(t, repo.Rename(ctx, "noop", "noop2")) 26 | 27 | assert.NoError(t, repo.Prepend(ctx, "noop", []byte("noop"))) 28 | assert.NoError(t, repo.Append(ctx, "noop", []byte("noop"))) 29 | assert.NoError(t, repo.Copy(ctx, "noop", "noop2")) 30 | } 31 | -------------------------------------------------------------------------------- /filesystem/s3/filesystem_test.go: -------------------------------------------------------------------------------- 1 | package s3 2 | -------------------------------------------------------------------------------- /filesystem/s3/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/filesystem/s3/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/filesystem/v3 => ../ 6 | 7 | require ( 8 | github.com/aws/aws-sdk-go-v2/service/s3 v1.80.0 9 | github.com/aws/smithy-go v1.22.3 10 | github.com/go-fries/fries/filesystem/v3 v3.4.0 11 | ) 12 | 13 | require ( 14 | github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect 15 | github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect 16 | github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect 17 | github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect 18 | github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect 19 | github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect 20 | github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.2 // indirect 21 | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect 22 | github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /foundation/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/foundation/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /foundation/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /gin/README.md: -------------------------------------------------------------------------------- 1 | # Gin Server 2 | 3 | ## Usage 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "github.com/gin-gonic/gin" 10 | "github.com/go-kratos/kratos/v2" 11 | 12 | ginS "github.com/go-kratos-ecosystem/components/v2/gin" 13 | ) 14 | 15 | func main() { 16 | gs := ginS.NewServer( 17 | gin.Default(), 18 | ginS.Addr(":8080"), 19 | ) 20 | 21 | gs.GET("/ping", func(c *gin.Context) { 22 | c.JSON(200, gin.H{ 23 | "message": "pong", 24 | }) 25 | }) 26 | 27 | app := kratos.New( 28 | kratos.Server(gs), 29 | ) 30 | 31 | err := app.Run() 32 | if err != nil { 33 | panic(err) 34 | } 35 | } 36 | ``` -------------------------------------------------------------------------------- /gin/server.go: -------------------------------------------------------------------------------- 1 | package gin 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/gin-gonic/gin" 8 | "github.com/go-kratos/kratos/v2/log" 9 | ) 10 | 11 | type Server struct { 12 | *gin.Engine 13 | 14 | server *http.Server 15 | middlewares []gin.HandlerFunc 16 | 17 | addr string 18 | } 19 | 20 | type Option func(*Server) 21 | 22 | // Deprecated: use Addr 23 | func WithAddr(addr string) Option { 24 | return Addr(addr) 25 | } 26 | 27 | func Addr(addr string) Option { 28 | return func(s *Server) { 29 | s.addr = addr 30 | } 31 | } 32 | 33 | func Middleware(middlewares ...gin.HandlerFunc) Option { 34 | return func(s *Server) { 35 | s.middlewares = append(s.middlewares, middlewares...) 36 | } 37 | } 38 | 39 | func NewServer(e *gin.Engine, opts ...Option) *Server { 40 | srv := &Server{ 41 | Engine: e, 42 | addr: ":8080", 43 | } 44 | 45 | for _, opt := range opts { 46 | opt(srv) 47 | } 48 | 49 | // apply middlewares 50 | if len(srv.middlewares) > 0 { 51 | srv.Use(srv.middlewares...) 52 | } 53 | 54 | srv.server = &http.Server{ 55 | Addr: srv.addr, 56 | Handler: e, 57 | } 58 | 59 | return srv 60 | } 61 | 62 | func (s *Server) Start(_ context.Context) error { 63 | log.Infof("[GIN] server listening on: %s", s.addr) 64 | return s.server.ListenAndServe() 65 | } 66 | 67 | func (s *Server) Stop(ctx context.Context) error { 68 | log.Info("[GIN] server stopping") 69 | return s.server.Shutdown(ctx) 70 | } 71 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/kr/pretty v0.3.1 // indirect 10 | github.com/pmezard/go-difflib v1.0.0 // indirect 11 | github.com/rogpeppe/go-internal v1.14.1 // indirect 12 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 13 | gopkg.in/yaml.v3 v3.0.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /gomod_test.go: -------------------------------------------------------------------------------- 1 | package fries 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "strings" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | var expectedVersion = "go 1.23.0" 14 | 15 | func TestAllGoModVersions(t *testing.T) { 16 | var modFiles []string 17 | 18 | err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error { 19 | require.NoError(t, err) 20 | if !info.IsDir() && filepath.Base(path) == "go.mod" { 21 | modFiles = append(modFiles, path) 22 | } 23 | return nil 24 | }) 25 | require.NoError(t, err) 26 | require.NotEmpty(t, modFiles) 27 | 28 | for _, file := range modFiles { 29 | t.Run(file, func(t *testing.T) { 30 | bytes, err := os.ReadFile(file) 31 | require.NoError(t, err) 32 | 33 | content := string(bytes) 34 | assert.NotContains(t, content, "toolchain") 35 | 36 | contents := strings.Split(content, "\n") 37 | goVersionFound := false 38 | 39 | for _, line := range contents { 40 | line = strings.TrimSpace(line) 41 | if strings.HasPrefix(line, "go ") { 42 | goVersionFound = true 43 | assert.Equal(t, expectedVersion, line) 44 | break 45 | } 46 | } 47 | 48 | assert.True(t, goVersionFound) 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /gorm/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/gorm/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/stretchr/testify v1.10.0 7 | gorm.io/gorm v1.30.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/jinzhu/inflection v1.0.0 // indirect 13 | github.com/jinzhu/now v1.1.5 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | golang.org/x/text v0.25.0 // indirect 16 | gopkg.in/yaml.v3 v3.0.1 // indirect 17 | ) 18 | -------------------------------------------------------------------------------- /gorm/manager.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import "gorm.io/gorm" 4 | 5 | type Manager struct { 6 | *gorm.DB 7 | 8 | connections map[string]*gorm.DB 9 | } 10 | 11 | func NewManager(db *gorm.DB) *Manager { 12 | return &Manager{ 13 | DB: db, 14 | connections: make(map[string]*gorm.DB), 15 | } 16 | } 17 | 18 | func (m *Manager) Register(name string, db *gorm.DB) { 19 | m.connections[name] = db 20 | } 21 | 22 | func (m *Manager) Conn(names ...string) *gorm.DB { 23 | var name string 24 | if len(names) > 0 { 25 | name = names[0] 26 | } 27 | 28 | if name == "" { 29 | return m.DB 30 | } 31 | 32 | if c, ok := m.connections[name]; ok { 33 | return c 34 | } 35 | 36 | panic("gorm: the connection [" + name + "] is not registered.") 37 | } 38 | -------------------------------------------------------------------------------- /gorm/manager_test.go: -------------------------------------------------------------------------------- 1 | package gorm 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "gorm.io/gorm" 8 | ) 9 | 10 | var ( 11 | m *Manager 12 | db1, db2, db3, db4 *gorm.DB 13 | ) 14 | 15 | func init() { 16 | m = NewManager(db1) 17 | m.Register("db2", db2) 18 | m.Register("db3", db3) 19 | m.Register("db4", db4) 20 | } 21 | 22 | func TestManager(t *testing.T) { 23 | assert.Equal(t, db1, m.DB) 24 | assert.Equal(t, db1, m.Conn()) 25 | assert.Equal(t, db2, m.Conn("db2")) 26 | assert.Equal(t, db3, m.Conn("db3")) 27 | assert.Equal(t, db4, m.Conn("db4")) 28 | assert.Panics(t, func() { 29 | m.Conn("db5") 30 | }) 31 | } 32 | 33 | func BenchmarkManager(b *testing.B) { 34 | b.RunParallel(func(pb *testing.PB) { 35 | for pb.Next() { 36 | _ = m.DB 37 | _ = m.Conn() 38 | _ = m.Conn("db2") 39 | _ = m.Conn("db3") 40 | _ = m.Conn("db4") 41 | } 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /gorm/scope/example_test.go: -------------------------------------------------------------------------------- 1 | package scope_test 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/go-fries/fries/gorm/scope/v3" 7 | "gorm.io/gorm" 8 | ) 9 | 10 | func Example_scopes() { 11 | var db *gorm.DB 12 | 13 | db.Scopes( 14 | // when 15 | scope.When(true, func(db *gorm.DB) *gorm.DB { 16 | return db.Where("deleted_at IS NULL") 17 | }), 18 | scope.Unless(true, func(db *gorm.DB) *gorm.DB { 19 | return db.Where("deleted_at IS NOT NULL") 20 | }), 21 | 22 | // Where 23 | scope.Where("name = ?", "Flc"), 24 | scope.WhereBetween("created_at", time.Now(), time.Now()), 25 | scope.WhereNotBetween("created_at", time.Now(), time.Now()), 26 | scope.WhereIn("name", "Flc", "Flc 2"), 27 | scope.WhereNotIn("name", "Flc", "Flc 2"), 28 | scope.WhereLike("name", "Flc%"), 29 | scope.WhereNotLike("name", "Flc%"), 30 | scope.WhereEq("name", "Flc"), 31 | scope.WhereNe("name", "Flc"), 32 | scope.WhereGt("age", 18), 33 | scope.WhereEgt("age", 18), 34 | scope.WhereLt("age", 18), 35 | scope.WhereElt("age", 18), 36 | 37 | // Order 38 | scope.OrderBy("id"), 39 | scope.OrderBy("id", "desc"), 40 | scope.OrderBy("id", "asc"), 41 | scope.OrderByDesc("id"), 42 | scope.OrderByAsc("id"), 43 | scope.OrderByRaw("id desc"), 44 | 45 | // Limit 46 | scope.Limit(10), 47 | scope.Take(10), 48 | 49 | // Offset 50 | scope.Offset(10), 51 | scope.Skip(10), 52 | 53 | // Page 54 | scope.Page(1, 20), 55 | ).Find(&[]struct{}{}) 56 | } 57 | -------------------------------------------------------------------------------- /gorm/scope/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/gorm/scope/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/stretchr/testify v1.10.0 7 | gorm.io/driver/mysql v1.6.0 8 | gorm.io/gorm v1.30.0 9 | ) 10 | 11 | require ( 12 | filippo.io/edwards25519 v1.1.0 // indirect 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/go-sql-driver/mysql v1.9.2 // indirect 15 | github.com/jinzhu/inflection v1.0.0 // indirect 16 | github.com/jinzhu/now v1.1.5 // indirect 17 | github.com/pmezard/go-difflib v1.0.0 // indirect 18 | golang.org/x/text v0.25.0 // indirect 19 | gopkg.in/yaml.v3 v3.0.1 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /gorm/scope/scopes_test.go: -------------------------------------------------------------------------------- 1 | package scope 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "gorm.io/gorm" 8 | ) 9 | 10 | func TestScopes(t *testing.T) { 11 | users := []*User{ 12 | GetUser("ScopeUser1", GetUserOptions{}), 13 | GetUser("ScopeUser2", GetUserOptions{}), 14 | GetUser("ScopeUser3", GetUserOptions{}), 15 | } 16 | 17 | scopes := Scopes{}.Add(func(db *gorm.DB) *gorm.DB { 18 | return db.Where("name in (?)", []string{"ScopeUser1", "ScopeUser2"}) 19 | }) 20 | 21 | CleanUsers() 22 | DB.Create(&users) 23 | 24 | var users1 []User 25 | 26 | DB.Scopes(scopes...).Find(&users1) 27 | assert.Len(t, users1, 2) 28 | assert.Equal(t, "ScopeUser1", users1[0].Name) 29 | assert.Equal(t, "ScopeUser2", users1[1].Name) 30 | } 31 | -------------------------------------------------------------------------------- /hashing/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/hashing/v3 2 | 3 | go 1.23.0 4 | -------------------------------------------------------------------------------- /hashing/go.sum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-fries/fries/87659eefd879e4017e1f3bec8ddf07129a20f9ea/hashing/go.sum -------------------------------------------------------------------------------- /hashing/hasher.go: -------------------------------------------------------------------------------- 1 | package hashing 2 | 3 | type Hasher interface { 4 | // Make a hash value from the given value. 5 | Make(value string) (string, error) 6 | 7 | // MustMake a hash value from the given value. 8 | // If an error occurs, it will panic. 9 | MustMake(value string) string 10 | 11 | // Check the given value matches the given hashed value. 12 | // If you Make() is error, it will return false. 13 | Check(value, hashedValue string) bool 14 | } 15 | -------------------------------------------------------------------------------- /hashing/hashing.go: -------------------------------------------------------------------------------- 1 | package hashing 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | type Hash uint 8 | 9 | const ( 10 | MD5 Hash = 1 + iota 11 | maxHash 12 | ) 13 | 14 | var hashes = make([]func() Hasher, maxHash) 15 | 16 | func (h Hash) Available() bool { 17 | return h < maxHash && hashes[h] != nil 18 | } 19 | 20 | func (h Hash) New() Hasher { 21 | if h > 0 && h < maxHash { 22 | f := hashes[h] 23 | if f != nil { 24 | return f() 25 | } 26 | } 27 | 28 | panic("hashing: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable") 29 | } 30 | 31 | func Register(h Hash, f func() Hasher) { 32 | if h > 0 && h < maxHash { 33 | hashes[h] = f 34 | return 35 | } 36 | 37 | panic("hashing: invalid hash") 38 | } 39 | -------------------------------------------------------------------------------- /hashing/md5/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/hashing/md5/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/hashing/v3 => ../ 6 | 7 | require ( 8 | github.com/go-fries/fries/hashing/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | gopkg.in/yaml.v3 v3.0.1 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /hashing/md5/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /hashing/md5/hasher.go: -------------------------------------------------------------------------------- 1 | package md5 2 | 3 | import ( 4 | "crypto/md5" 5 | "fmt" 6 | 7 | "github.com/go-fries/fries/hashing/v3" 8 | ) 9 | 10 | type hasher struct{} 11 | 12 | var global *hasher 13 | 14 | func New() hashing.Hasher { 15 | if global == nil { 16 | global = &hasher{} 17 | } 18 | 19 | return global 20 | } 21 | 22 | func init() { 23 | hashing.Register(hashing.MD5, New) 24 | } 25 | 26 | // Make generates a new hashed value. 27 | func (h *hasher) Make(value string) (string, error) { 28 | hashedValue := md5.Sum([]byte(value)) 29 | 30 | return fmt.Sprintf("%x", hashedValue), nil 31 | } 32 | 33 | // MustMake generates a new hashed value. 34 | func (h *hasher) MustMake(value string) string { 35 | hashedValue, err := h.Make(value) 36 | if err != nil { 37 | panic(err) 38 | } 39 | 40 | return hashedValue 41 | } 42 | 43 | // Check checks the given value and hashed value. 44 | func (h *hasher) Check(value, hashedValue string) bool { 45 | hv, err := h.Make(value) 46 | if err != nil { 47 | return false 48 | } 49 | 50 | return hv == hashedValue 51 | } 52 | -------------------------------------------------------------------------------- /hashing/md5/hasher_test.go: -------------------------------------------------------------------------------- 1 | package md5 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMd5Hasher(t *testing.T) { 10 | md5 := New() 11 | 12 | value := "123456" 13 | hashedValue, err := md5.Make(value) 14 | 15 | assert.Nil(t, err) 16 | assert.True(t, md5.Check(value, hashedValue)) 17 | 18 | assert.True(t, md5.Check(value, md5.MustMake(value))) 19 | 20 | md5Two := New() 21 | assert.Same(t, md5, md5Two) 22 | } 23 | -------------------------------------------------------------------------------- /http/server/README.md: -------------------------------------------------------------------------------- 1 | # HTTP Server 2 | 3 | A common HTTP service component that supports Kratos Server. 4 | 5 | ## Usage Example 6 | 7 | ```go 8 | package server_test 9 | 10 | import ( 11 | "net/http" 12 | 13 | "github.com/go-kratos/kratos/v2" 14 | 15 | "github.com/go-kratos-ecosystem/components/v2/http/server" 16 | ) 17 | 18 | func Example() { 19 | srv := server.New(&http.Server{ 20 | Addr: ":8080", 21 | Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 22 | w.WriteHeader(http.StatusOK) 23 | _, _ = w.Write([]byte("hello world")) 24 | }), 25 | }) 26 | 27 | app := kratos.New( 28 | kratos.Server(srv), 29 | ) 30 | 31 | if err := app.Run(); err != nil { 32 | panic(err) 33 | } 34 | } 35 | 36 | ``` -------------------------------------------------------------------------------- /http/server/example_test.go: -------------------------------------------------------------------------------- 1 | package server_test 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/go-fries/fries/http/server/v3" 7 | "github.com/go-kratos/kratos/v2" 8 | ) 9 | 10 | func Example() { 11 | srv := server.New(&http.Server{ 12 | Addr: ":8080", 13 | Handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { 14 | w.WriteHeader(http.StatusOK) 15 | _, _ = w.Write([]byte("hello world")) 16 | }), 17 | }) 18 | 19 | app := kratos.New( 20 | kratos.Server(srv), 21 | ) 22 | 23 | if err := app.Run(); err != nil { 24 | panic(err) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /http/server/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/http/server/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/go-kratos/kratos/v2 v2.8.4 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/go-playground/assert/v2 v2.2.0 // indirect 13 | github.com/go-playground/form/v4 v4.2.3 // indirect 14 | github.com/google/go-cmp v0.7.0 // indirect 15 | github.com/google/uuid v1.6.0 // indirect 16 | github.com/kr/text v0.2.0 // indirect 17 | github.com/pmezard/go-difflib v1.0.0 // indirect 18 | github.com/rogpeppe/go-internal v1.14.1 // indirect 19 | golang.org/x/net v0.40.0 // indirect 20 | golang.org/x/sync v0.15.0 // indirect 21 | google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect 22 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 23 | google.golang.org/grpc v1.73.0 // indirect 24 | google.golang.org/protobuf v1.36.6 // indirect 25 | gopkg.in/yaml.v3 v3.0.1 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /http/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/go-kratos/kratos/v2/log" 8 | "github.com/go-kratos/kratos/v2/transport" 9 | ) 10 | 11 | type Server struct { 12 | name string 13 | *http.Server 14 | } 15 | 16 | type Option func(*Server) 17 | 18 | func WithName(name string) Option { 19 | return func(s *Server) { 20 | if name != "" { 21 | s.name = name 22 | } 23 | } 24 | } 25 | 26 | var _ transport.Server = (*Server)(nil) 27 | 28 | func New(srv *http.Server, opts ...Option) *Server { 29 | s := &Server{ 30 | name: "HTTP", 31 | Server: srv, 32 | } 33 | for _, opt := range opts { 34 | opt(s) 35 | } 36 | return s 37 | } 38 | 39 | type HTTPServerOption func(*http.Server) 40 | 41 | func WithHTTPServerAddr(addr string) HTTPServerOption { 42 | return func(s *http.Server) { 43 | s.Addr = addr 44 | } 45 | } 46 | 47 | func NewWithHandler(handler http.Handler, opts ...HTTPServerOption) *Server { 48 | srv := &http.Server{ 49 | Handler: handler, 50 | Addr: ":8080", 51 | } 52 | for _, opt := range opts { 53 | opt(srv) 54 | } 55 | 56 | return New(srv) 57 | } 58 | 59 | func (s *Server) Start(_ context.Context) error { 60 | log.Infof("[%s] server listening on: %s", s.name, s.Addr) 61 | return s.ListenAndServe() 62 | } 63 | 64 | func (s *Server) Stop(ctx context.Context) error { 65 | log.Infof("[%s] server stopping", s.name) 66 | return s.Shutdown(ctx) 67 | } 68 | -------------------------------------------------------------------------------- /hyperf/jet/context.go: -------------------------------------------------------------------------------- 1 | package jet 2 | 3 | import "context" 4 | 5 | type contextClientKey struct{} 6 | 7 | // ContextWithClient returns a new Context that carries value. 8 | func ContextWithClient(ctx context.Context, client *Client) context.Context { 9 | return context.WithValue(ctx, contextClientKey{}, client) 10 | } 11 | 12 | // ClientFromContext returns the Client value stored in ctx, if any. 13 | func ClientFromContext(ctx context.Context) (*Client, bool) { 14 | client, ok := ctx.Value(contextClientKey{}).(*Client) 15 | return client, ok 16 | } 17 | -------------------------------------------------------------------------------- /hyperf/jet/context_test.go: -------------------------------------------------------------------------------- 1 | package jet 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestContext_Client(t *testing.T) { 11 | ctx := context.Background() 12 | 13 | got1, ok1 := ClientFromContext(ctx) 14 | assert.False(t, ok1) 15 | assert.Nil(t, got1) 16 | 17 | client := &Client{} 18 | ctx = ContextWithClient(context.Background(), client) 19 | 20 | got2, ok2 := ClientFromContext(ctx) 21 | assert.True(t, ok2) 22 | assert.Equal(t, client, got2) 23 | } 24 | -------------------------------------------------------------------------------- /hyperf/jet/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/hyperf/jet/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/google/uuid v1.6.0 7 | github.com/stretchr/testify v1.10.0 8 | golang.org/x/text v0.25.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/kr/pretty v0.3.1 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | github.com/rogpeppe/go-internal v1.14.1 // indirect 16 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 17 | gopkg.in/yaml.v3 v3.0.1 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /hyperf/jet/middleware.go: -------------------------------------------------------------------------------- 1 | package jet 2 | 3 | import "context" 4 | 5 | type Handler func(ctx context.Context, service, method string, request any) (response any, err error) 6 | 7 | type Middleware func(Handler) Handler 8 | 9 | // Chain chains the middlewares. 10 | // 11 | // Chain(m1, m2, m3)(xxx) => m1(m2(m3(xxx)) 12 | func Chain(m ...Middleware) Middleware { 13 | return func(next Handler) Handler { 14 | for i := len(m) - 1; i >= 0; i-- { 15 | next = m[i](next) 16 | } 17 | return next 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/logging/README.md: -------------------------------------------------------------------------------- 1 | # Logging - Hyperf jet middleware 2 | 3 | logging middleware for Hyperf jet. 4 | 5 | ## Usage Example 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "context" 12 | 13 | "github.com/go-kratos/kratos/v2/log" 14 | 15 | "github.com/go-kratos-ecosystem/components/v2/hyperf/jet" 16 | "github.com/go-kratos-ecosystem/components/v2/hyperf/jet/middleware/logging" 17 | ) 18 | 19 | func main() { 20 | client, err := jet.NewClient( 21 | jet.WithTransporter(nil), 22 | jet.WithService("Example/User/MoneyService"), 23 | ) 24 | if err != nil { 25 | panic(err) 26 | } 27 | 28 | // base usage 29 | client.Use(logging.New()) // use github.com/go-kratos/kratos/v2/log.DefaultLogger 30 | 31 | // with options 32 | client.Use(logging.New( 33 | logging.Logger(&customLogger{}), 34 | )) 35 | 36 | // call service 37 | client.Invoke(context.Background(), "service", []any{"..."}, nil) 38 | } 39 | 40 | type customLogger struct{} 41 | 42 | var _ log.Logger = (*customLogger)(nil) 43 | 44 | func (c *customLogger) Log(level log.Level, keyvals ...any) error { 45 | // custom log 46 | return nil 47 | } 48 | 49 | ``` 50 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/logging/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/hyperf/jet/middleware/logging/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/hyperf/jet/v3 => ../../ 6 | 7 | require ( 8 | github.com/go-fries/fries/hyperf/jet/v3 v3.4.0 9 | github.com/go-kratos/kratos/v2 v2.8.4 10 | github.com/stretchr/testify v1.10.0 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/google/uuid v1.6.0 // indirect 16 | github.com/kr/text v0.2.0 // indirect 17 | github.com/pmezard/go-difflib v1.0.0 // indirect 18 | golang.org/x/text v0.25.0 // indirect 19 | gopkg.in/yaml.v3 v3.0.1 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/logging/logging.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/go-fries/fries/hyperf/jet/v3" 8 | "github.com/go-kratos/kratos/v2/log" 9 | ) 10 | 11 | type options struct { 12 | logger log.Logger 13 | } 14 | 15 | type Option func(*options) 16 | 17 | func Logger(logger log.Logger) Option { 18 | return func(o *options) { 19 | o.logger = logger 20 | } 21 | } 22 | 23 | func New(opts ...Option) jet.Middleware { 24 | o := options{ 25 | logger: log.DefaultLogger, 26 | } 27 | for _, opt := range opts { 28 | opt(&o) 29 | } 30 | return func(next jet.Handler) jet.Handler { 31 | return func(ctx context.Context, service, method string, request any) (response any, err error) { 32 | defer func(starting time.Time) { 33 | level := log.LevelInfo 34 | if err != nil { 35 | level = log.LevelError 36 | } 37 | 38 | _ = log.WithContext(ctx, o.logger).Log(level, 39 | "kind", "jet", 40 | "service", service, 41 | "method", method, 42 | "request", request, 43 | "response", response, 44 | "error", err, 45 | "latency", time.Since(starting), 46 | ) 47 | }(time.Now()) 48 | return next(ctx, service, method, request) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/recovery/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/hyperf/jet/middleware/recovery/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/hyperf/jet/v3 => ../../ 6 | 7 | require ( 8 | github.com/go-fries/fries/hyperf/jet/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/google/uuid v1.6.0 // indirect 15 | github.com/kr/text v0.2.0 // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | golang.org/x/text v0.25.0 // indirect 18 | gopkg.in/yaml.v3 v3.0.1 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/recovery/recovery.go: -------------------------------------------------------------------------------- 1 | package recovery 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/go-fries/fries/hyperf/jet/v3" 8 | ) 9 | 10 | var DefaultHandler = func(_ context.Context, service, method string, request any, err any) error { 11 | return fmt.Errorf("service: %s, method: %s, request: %v, error: %v", service, method, request, err) 12 | } 13 | 14 | type HandlerFunc func(ctx context.Context, service, method string, request any, err any) error 15 | 16 | type options struct { 17 | handler HandlerFunc 18 | } 19 | 20 | type Option func(*options) 21 | 22 | func Handler(h HandlerFunc) Option { 23 | return func(o *options) { 24 | o.handler = h 25 | } 26 | } 27 | 28 | func New(opts ...Option) jet.Middleware { 29 | return func(next jet.Handler) jet.Handler { 30 | o := options{ 31 | handler: DefaultHandler, 32 | } 33 | for _, opt := range opts { 34 | opt(&o) 35 | } 36 | 37 | return func(ctx context.Context, service, method string, request any) (response any, err error) { 38 | defer func() { 39 | if rerr := recover(); rerr != nil { 40 | err = o.handler(ctx, service, method, request, rerr) 41 | } 42 | }() 43 | return next(ctx, service, method, request) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/recovery/recovery_test.go: -------------------------------------------------------------------------------- 1 | package recovery 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestRecovery(t *testing.T) { 12 | testService := "service" 13 | testMethod := "method" 14 | testRequest := "request" 15 | testError := "error" 16 | 17 | recovery := New( 18 | Handler(func(_ context.Context, service string, method string, request any, err any) error { 19 | assert.Equal(t, testService, service) 20 | assert.Equal(t, testMethod, method) 21 | assert.Equal(t, testRequest, request) 22 | assert.Equal(t, testError, err) 23 | return fmt.Errorf("method: %s, request: %v, error: %v", method, request, err) 24 | }), 25 | ) 26 | 27 | response, err := recovery(func(context.Context, string, string, any) (response any, err error) { 28 | panic(testError) 29 | })(context.Background(), testService, testMethod, testRequest) 30 | assert.Error(t, err) 31 | assert.Nil(t, response) 32 | } 33 | 34 | func TestRecovery_DefaultHandler(t *testing.T) { 35 | recovery := New() 36 | 37 | response, err := recovery(func(context.Context, string, string, any) (response any, err error) { 38 | panic("error") 39 | })(context.Background(), "service", "method", "request") 40 | assert.Error(t, err) 41 | assert.Nil(t, response) 42 | } 43 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/retry/backoff.go: -------------------------------------------------------------------------------- 1 | package retry 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | var DefaultBackoff = LinearBackoff(100 * time.Millisecond) //nolint:mnd 8 | 9 | type BackoffFunc func(attempt int) time.Duration 10 | 11 | func NoBackoff() BackoffFunc { 12 | return func(_ int) time.Duration { 13 | return 0 14 | } 15 | } 16 | 17 | // LinearBackoff returns a backoff function that increases the delay linearly. 18 | func LinearBackoff(delay time.Duration) BackoffFunc { 19 | return func(attempt int) time.Duration { 20 | return delay * time.Duration(attempt) 21 | } 22 | } 23 | 24 | // ExponentialBackoff returns a backoff function that increases the delay exponentially. 25 | func ExponentialBackoff(delay time.Duration) BackoffFunc { 26 | return func(attempt int) time.Duration { 27 | return delay * time.Duration(1< ../timeout 7 | github.com/go-fries/fries/hyperf/jet/v3 => ../../ 8 | ) 9 | 10 | require ( 11 | github.com/go-fries/fries/hyperf/jet/middleware/timeout/v3 v3.4.0 12 | github.com/go-fries/fries/hyperf/jet/v3 v3.4.0 13 | github.com/stretchr/testify v1.10.0 14 | ) 15 | 16 | require ( 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/google/uuid v1.6.0 // indirect 19 | github.com/pmezard/go-difflib v1.0.0 // indirect 20 | golang.org/x/text v0.25.0 // indirect 21 | gopkg.in/yaml.v3 v3.0.1 // indirect 22 | ) 23 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/retry/options.go: -------------------------------------------------------------------------------- 1 | package retry 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/go-fries/fries/hyperf/jet/middleware/timeout/v3" 7 | "github.com/go-fries/fries/hyperf/jet/v3" 8 | ) 9 | 10 | var DefaultAllow AllowFunc = func(err error) bool { 11 | return jet.IsHTTPTransporterServerError(err) && 12 | errors.Is(err, timeout.ErrTimeout) 13 | } 14 | 15 | type AllowFunc func(err error) bool 16 | 17 | func OrAllowFuncs(fs ...AllowFunc) AllowFunc { 18 | return func(err error) bool { 19 | for _, f := range fs { 20 | if f(err) { 21 | return true 22 | } 23 | } 24 | return false 25 | } 26 | } 27 | 28 | type options struct { 29 | attempts int 30 | backoff BackoffFunc 31 | allow AllowFunc // allow retry 32 | } 33 | 34 | type Option func(o *options) 35 | 36 | func Attempts(attempts int) Option { 37 | return func(o *options) { 38 | o.attempts = attempts 39 | } 40 | } 41 | 42 | func Allow(f AllowFunc) Option { 43 | return func(o *options) { 44 | o.allow = f 45 | } 46 | } 47 | 48 | func Backoff(f BackoffFunc) Option { 49 | return func(o *options) { 50 | o.backoff = f 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/timeout/README.md: -------------------------------------------------------------------------------- 1 | # Timeout - Jet Middleware 2 | 3 | Timeout middleware for Jet. 4 | 5 | ## Usage Example 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "context" 12 | "log" 13 | "time" 14 | 15 | "github.com/go-kratos-ecosystem/components/v2/hyperf/jet" 16 | "github.com/go-kratos-ecosystem/components/v2/hyperf/jet/middleware/timeout" 17 | ) 18 | 19 | func main() { 20 | client, err := jet.NewClient( 21 | jet.WithTransporter(nil), 22 | // ... 23 | ) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | // base usage 29 | client.Use(timeout.New()) // default 5s 30 | 31 | // custom timeout 32 | client.Use(timeout.New( 33 | timeout.Timeout(10 * time.Second), 34 | )) 35 | 36 | // call service 37 | client.Invoke(context.Background(), "method", []any{"..."}, nil) 38 | } 39 | ``` -------------------------------------------------------------------------------- /hyperf/jet/middleware/timeout/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/hyperf/jet/middleware/timeout/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/hyperf/jet/v3 => ../../ 6 | 7 | require ( 8 | github.com/go-fries/fries/hyperf/jet/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/google/uuid v1.6.0 // indirect 15 | github.com/kr/text v0.2.0 // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | golang.org/x/text v0.25.0 // indirect 18 | gopkg.in/yaml.v3 v3.0.1 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/timeout/timeout_test.go: -------------------------------------------------------------------------------- 1 | package timeout 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestTimeout(t *testing.T) { 12 | tests := []struct { 13 | name string 14 | timeout time.Duration 15 | sleep time.Duration 16 | want func(t *testing.T, response any, err error) 17 | }{ 18 | { 19 | name: "", 20 | timeout: time.Second * 1, 21 | sleep: 0, 22 | want: func(t *testing.T, response any, err error) { 23 | assert.Equal(t, "test", response) 24 | assert.Nil(t, err) 25 | }, 26 | }, 27 | { 28 | name: "", 29 | timeout: time.Second * 1, 30 | sleep: time.Second * 2, 31 | want: func(t *testing.T, response any, err error) { 32 | assert.Equal(t, ErrTimeout, err) 33 | assert.Nil(t, response) 34 | }, 35 | }, 36 | } 37 | 38 | for _, tt := range tests { 39 | t.Run(tt.name, func(t *testing.T) { 40 | handler := New( 41 | Timeout(tt.timeout), 42 | )(func(_ context.Context, service, method string, req any) (any, error) { 43 | assert.Equal(t, "service", service) 44 | assert.Equal(t, "test", method) 45 | assert.Equal(t, "request", req) 46 | time.Sleep(tt.sleep) 47 | return "test", nil 48 | }) 49 | response, err := handler(context.Background(), "service", "test", "request") 50 | tt.want(t, response, err) 51 | }) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /hyperf/jet/middleware/tracing/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/hyperf/jet/middleware/tracing/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/hyperf/jet/v3 => ../../ 6 | 7 | require ( 8 | github.com/go-fries/fries/hyperf/jet/v3 v3.4.0 9 | github.com/stretchr/testify v1.10.0 10 | go.opentelemetry.io/otel v1.36.0 11 | go.opentelemetry.io/otel/sdk v1.36.0 12 | go.opentelemetry.io/otel/trace v1.36.0 13 | ) 14 | 15 | require ( 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/go-logr/logr v1.4.3 // indirect 18 | github.com/go-logr/stdr v1.2.2 // indirect 19 | github.com/google/uuid v1.6.0 // indirect 20 | github.com/pmezard/go-difflib v1.0.0 // indirect 21 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 22 | go.opentelemetry.io/otel/metric v1.36.0 // indirect 23 | golang.org/x/sys v0.33.0 // indirect 24 | golang.org/x/text v0.25.0 // indirect 25 | gopkg.in/yaml.v3 v3.0.1 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /hyperf/jet/packer.go: -------------------------------------------------------------------------------- 1 | package jet 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | var DefaultPacker Packer = NewJSONPacker() 8 | 9 | type Packer interface { 10 | Pack(any) ([]byte, error) 11 | Unpack([]byte, any) error 12 | } 13 | 14 | // JSONPacker is a json packer 15 | type JSONPacker struct{} 16 | 17 | func NewJSONPacker() *JSONPacker { 18 | return &JSONPacker{} 19 | } 20 | 21 | func (p *JSONPacker) Pack(v any) ([]byte, error) { 22 | return json.Marshal(v) 23 | } 24 | 25 | func (p *JSONPacker) Unpack(data []byte, v any) error { 26 | return json.Unmarshal(data, v) 27 | } 28 | -------------------------------------------------------------------------------- /hyperf/jet/packer_test.go: -------------------------------------------------------------------------------- 1 | package jet 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestPacker_JSONPacker(t *testing.T) { 10 | packer := NewJSONPacker() 11 | 12 | // pack 13 | data, err := packer.Pack(1) 14 | assert.NoError(t, err) 15 | 16 | // unpack 17 | var v int 18 | err = packer.Unpack(data, &v) 19 | assert.NoError(t, err) 20 | assert.Equal(t, 1, v) 21 | } 22 | -------------------------------------------------------------------------------- /internal/tools/main.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | package tools 5 | 6 | import ( 7 | _ "github.com/golangci/golangci-lint/v2/cmd/golangci-lint" 8 | _ "github.com/wadey/gocovmerge" 9 | _ "go.opentelemetry.io/build-tools/multimod" 10 | _ "golang.org/x/exp/cmd/gorelease" 11 | ) 12 | -------------------------------------------------------------------------------- /kratos/log/otel/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/kratos/log/otel/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/v3 => ../../../ 6 | 7 | require ( 8 | github.com/go-fries/fries/v3 v3.4.0 9 | github.com/go-kratos/kratos/v2 v2.8.4 10 | github.com/stretchr/testify v1.10.0 11 | go.opentelemetry.io/otel/log v0.12.2 12 | ) 13 | 14 | require ( 15 | github.com/davecgh/go-spew v1.1.1 // indirect 16 | github.com/go-logr/logr v1.4.3 // indirect 17 | github.com/go-logr/stdr v1.2.2 // indirect 18 | github.com/pmezard/go-difflib v1.0.0 // indirect 19 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 20 | go.opentelemetry.io/otel v1.36.0 // indirect 21 | go.opentelemetry.io/otel/metric v1.36.0 // indirect 22 | go.opentelemetry.io/otel/trace v1.36.0 // indirect 23 | gopkg.in/yaml.v3 v3.0.1 // indirect 24 | ) 25 | -------------------------------------------------------------------------------- /kratos/log/otel/options.go: -------------------------------------------------------------------------------- 1 | package otel 2 | 3 | import ( 4 | "go.opentelemetry.io/otel/log" 5 | "go.opentelemetry.io/otel/log/global" 6 | ) 7 | 8 | type options struct { 9 | name string 10 | provider log.LoggerProvider 11 | } 12 | 13 | type Option interface { 14 | apply(*options) 15 | } 16 | 17 | type optionFunc func(*options) 18 | 19 | func (f optionFunc) apply(o *options) { 20 | f(o) 21 | } 22 | 23 | func newOptions(opts ...Option) *options { 24 | o := &options{ 25 | name: "otel-logger", 26 | provider: global.GetLoggerProvider(), 27 | } 28 | for _, opt := range opts { 29 | opt.apply(o) 30 | } 31 | return o 32 | } 33 | 34 | func WithName(name string) Option { 35 | return optionFunc(func(o *options) { 36 | o.name = name 37 | }) 38 | } 39 | 40 | func WithLoggerProvider(provider log.LoggerProvider) Option { 41 | return optionFunc(func(o *options) { 42 | o.provider = provider 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /kratos/log/stack/README.md: -------------------------------------------------------------------------------- 1 | # Stack Logger 2 | 3 | Stack Logger is a logger for aggregating multiple loggers. 4 | 5 | ## Usage 6 | 7 | ```go 8 | package main 9 | 10 | import ( 11 | "os" 12 | 13 | "github.com/go-fries/fries/kratos/log/stack/v3" 14 | "github.com/go-kratos/kratos/v2/log" 15 | ) 16 | 17 | func main() { 18 | stackLogger := stack.New( 19 | log.NewStdLogger(os.Stdout), 20 | log.NewStdLogger(os.Stderr), // another logger 21 | ) 22 | 23 | _ = stackLogger.Log(log.LevelInfo, "key", "value") 24 | } 25 | ``` -------------------------------------------------------------------------------- /kratos/log/stack/example_test.go: -------------------------------------------------------------------------------- 1 | package stack_test 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/go-fries/fries/kratos/log/stack/v3" 7 | "github.com/go-kratos/kratos/v2/log" 8 | ) 9 | 10 | func Example_new() { 11 | stackLogger := stack.New( 12 | log.NewStdLogger(os.Stdout), 13 | log.NewStdLogger(os.Stderr), // another logger 14 | ) 15 | 16 | _ = stackLogger.Log(log.LevelInfo, "key", "value") 17 | } 18 | -------------------------------------------------------------------------------- /kratos/log/stack/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/kratos/log/stack/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/go-kratos/kratos/v2 v2.8.4 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/kr/text v0.2.0 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.1 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /kratos/log/stack/stack.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/go-kratos/kratos/v2/log" 7 | ) 8 | 9 | type stackLogger []log.Logger 10 | 11 | var _ log.Logger = (stackLogger)(nil) 12 | 13 | func New(loggers ...log.Logger) log.Logger { 14 | return stackLogger(loggers) 15 | } 16 | 17 | func (s stackLogger) Log(level log.Level, keyvals ...any) error { 18 | var errs []error 19 | for _, logger := range s { 20 | if err := logger.Log(level, keyvals...); err != nil { 21 | errs = append(errs, err) 22 | } 23 | } 24 | return errors.Join(errs...) 25 | } 26 | -------------------------------------------------------------------------------- /kratos/log/syslog/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/kratos/log/syslog/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/go-kratos/kratos/v2 v2.8.4 6 | -------------------------------------------------------------------------------- /kratos/log/syslog/go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-kratos/kratos/v2 v2.8.4 h1:eIJLE9Qq9WSoKx+Buy2uPyrahtF/lPh+Xf4MTpxhmjs= 2 | github.com/go-kratos/kratos/v2 v2.8.4/go.mod h1:mq62W2101a5uYyRxe+7IdWubu7gZCGYqSNKwGFiiRcw= 3 | golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= 4 | golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 5 | -------------------------------------------------------------------------------- /kratos/log/syslog/syslog_test.go: -------------------------------------------------------------------------------- 1 | //go:build !windows && !plan9 2 | 3 | package syslog 4 | 5 | import ( 6 | "runtime" 7 | "testing" 8 | 9 | "github.com/go-kratos/kratos/v2/log" 10 | ) 11 | 12 | func TestSyslogLogger(t *testing.T) { 13 | if runtime.GOOS == "windows" { // nolint:staticcheck 14 | t.Skip("skip syslog test") 15 | } 16 | 17 | logger := New(&Config{ 18 | Network: "udp", 19 | Addr: "192.168.8.92:30732", 20 | Tag: "test", 21 | }) 22 | defer logger.Close() //nolint:errcheck 23 | 24 | err := logger.Log(log.LevelDebug, "test", "test") 25 | if err != nil { 26 | t.Fatal(err) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /kratos/middleware/cors/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/kratos/middleware/cors/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/go-kratos/kratos/v2 v2.8.4 6 | 7 | require ( 8 | github.com/go-kratos/aegis v0.2.0 // indirect 9 | github.com/go-playground/form/v4 v4.2.3 // indirect 10 | github.com/google/uuid v1.6.0 // indirect 11 | github.com/gorilla/mux v1.8.1 // indirect 12 | github.com/kr/text v0.2.0 // indirect 13 | golang.org/x/sys v0.33.0 // indirect 14 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 15 | google.golang.org/grpc v1.73.0 // indirect 16 | google.golang.org/protobuf v1.36.6 // indirect 17 | gopkg.in/yaml.v3 v3.0.1 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /kratos/middleware/protovalidate/README.md: -------------------------------------------------------------------------------- 1 | # Proto-Validate 2 | 3 | Proto-Validate is a middleware for [Kratos](https://github.com/go-kratos/kratos). 4 | 5 | The protovalidate uses the [protovalidate-go](https://github.com/bufbuild/protovalidate-go) library to validate the request messages of the gRPC service. 6 | 7 | 8 | ## Usage Example 9 | 10 | ```go 11 | package main 12 | 13 | import ( 14 | "log" 15 | 16 | "github.com/bufbuild/protovalidate-go" 17 | "github.com/go-kratos/kratos/v2" 18 | "github.com/go-kratos/kratos/v2/transport/http" 19 | 20 | middlewareprotovalidate "github.com/go-kratos-ecosystem/components/v2/middleware/protovalidate" 21 | ) 22 | 23 | func main() { 24 | validator, err := protovalidate.New( 25 | protovalidate.WithFailFast(true), 26 | ) 27 | if err != nil { 28 | log.Fatal(err) 29 | } 30 | 31 | app := kratos.New( 32 | http.NewServer( 33 | http.Address(":8000"), 34 | middlewareprotovalidate.Server( 35 | middlewareprotovalidate.Validator(validator), 36 | ), 37 | ), 38 | ) 39 | 40 | app.Run() 41 | } 42 | ``` -------------------------------------------------------------------------------- /kratos/middleware/protovalidate/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/kratos/middleware/protovalidate/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250603165357-b52ab10f4468.1 7 | buf.build/go/protovalidate v0.12.0 8 | github.com/go-kratos/kratos/v2 v2.8.4 9 | github.com/stretchr/testify v1.10.0 10 | google.golang.org/protobuf v1.36.6 11 | ) 12 | 13 | require ( 14 | cel.dev/expr v0.24.0 // indirect 15 | github.com/antlr4-go/antlr/v4 v4.13.1 // indirect 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/google/cel-go v0.25.0 // indirect 18 | github.com/pmezard/go-difflib v1.0.0 // indirect 19 | github.com/stoewer/go-strcase v1.3.0 // indirect 20 | golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect 21 | golang.org/x/sys v0.33.0 // indirect 22 | golang.org/x/text v0.25.0 // indirect 23 | google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect 24 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 25 | google.golang.org/grpc v1.73.0 // indirect 26 | gopkg.in/yaml.v3 v3.0.1 // indirect 27 | ) 28 | -------------------------------------------------------------------------------- /kratos/middleware/protovalidate/internal/buf.gen.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | plugins: 3 | - remote: buf.build/protocolbuffers/go 4 | out: proto 5 | opt: paths=source_relative 6 | - remote: buf.build/grpc/go 7 | out: proto 8 | opt: paths=source_relative -------------------------------------------------------------------------------- /kratos/middleware/protovalidate/internal/buf.lock: -------------------------------------------------------------------------------- 1 | # Generated by buf. DO NOT EDIT. 2 | version: v2 3 | deps: 4 | - name: buf.build/bufbuild/protovalidate 5 | commit: 63bb56e204954558946a641ef0d68910 6 | digest: b5:ec5661b2855484eca2043fe61d27eb22673ab926ccd0e849531752eb17b08402fae1382705cee7f7b42d4d9ec56aff72bba7ec6835902cf6f86323c9ac682d16 7 | -------------------------------------------------------------------------------- /kratos/middleware/protovalidate/internal/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | modules: 3 | - path: proto 4 | deps: 5 | - buf.build/bufbuild/protovalidate 6 | lint: 7 | use: 8 | - DEFAULT 9 | except: 10 | - FIELD_NOT_REQUIRED 11 | - PACKAGE_NO_IMPORT_CYCLE 12 | - SERVICE_SUFFIX 13 | rpc_allow_same_request_response: true 14 | rpc_allow_google_protobuf_empty_requests: true 15 | rpc_allow_google_protobuf_empty_responses: true 16 | breaking: 17 | use: 18 | - FILE -------------------------------------------------------------------------------- /kratos/middleware/protovalidate/internal/proto/protovalidate/v1/person.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package protovalidate.v1; 4 | 5 | import "buf/validate/validate.proto"; 6 | 7 | option go_package = "protovalidate/v1;protovalidatepb"; 8 | 9 | message Person { 10 | uint64 id = 1 [(buf.validate.field).uint64.gt = 999]; 11 | 12 | string email = 2 [(buf.validate.field).string.email = true]; 13 | 14 | string name = 3 [(buf.validate.field).string = { 15 | pattern: "^[[:alpha:]]+( [[:alpha:]]+)*$" 16 | max_bytes: 256 17 | }]; 18 | 19 | Coordinates home = 4; 20 | } 21 | 22 | message Coordinates { 23 | double lat = 1 [(buf.validate.field).double = { 24 | gte: -90 25 | lte: 90 26 | }]; 27 | double lng = 2 [(buf.validate.field).double = { 28 | gte: -180 29 | lte: 180 30 | }]; 31 | } -------------------------------------------------------------------------------- /kratos/middleware/slowlog/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/kratos/middleware/slowlog/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/go-kratos/kratos/v2 v2.8.4 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/go-playground/form/v4 v4.2.3 // indirect 13 | github.com/kr/text v0.2.0 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | golang.org/x/sys v0.33.0 // indirect 16 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 17 | google.golang.org/grpc v1.73.0 // indirect 18 | google.golang.org/protobuf v1.36.6 // indirect 19 | gopkg.in/yaml.v3 v3.0.1 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /kratos/middleware/tracing/README.md: -------------------------------------------------------------------------------- 1 | # Tracing Middleware 2 | 3 | The tracing middleware provides a way to trace the execution of a request through the application. It is based on the [OpenTelemetry](http://opentelemetry.io/) standard and can be used with any tracer that implements this standard. 4 | 5 | The package is forked from [tracing](https://github.com/go-kratos/kratos/tree/8b8dc4b0f8bebb76939780f59734c20c265669c5/middleware/tracing) and optimized on this basis. Thanks to the original author for his contribution. 6 | 7 | ## Usage Example 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "github.com/go-kratos/kratos/v2" 14 | "github.com/go-kratos/kratos/v2/transport/http" 15 | 16 | "github.com/go-kratos-ecosystem/components/v2/middleware/tracing" 17 | ) 18 | 19 | func main() { 20 | app := kratos.New( 21 | kratos.Name("tracing"), 22 | kratos.Server( 23 | http.NewServer( 24 | http.Address(":8001"), 25 | http.Middleware(tracing.Server()), 26 | ), 27 | ), 28 | ) 29 | 30 | if err := app.Run(); err != nil { 31 | panic(err) 32 | } 33 | } 34 | ``` 35 | 36 | ## License 37 | 38 | - The MIT License ([MIT](https://github.com/go-kratos-ecosystem/components/blob/2.x/LICENSE)). 39 | - [Kratos](https://github.com/go-kratos/kratos) License File: [License File](https://github.com/go-kratos/kratos/blob/8b8dc4b0f8bebb76939780f59734c20c265669c5/LICENSE) -------------------------------------------------------------------------------- /kratos/middleware/tracing/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/kratos/middleware/tracing/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/go-kratos/kratos/v2 v2.8.4 7 | go.opentelemetry.io/otel v1.36.0 8 | go.opentelemetry.io/otel/sdk v1.36.0 9 | go.opentelemetry.io/otel/trace v1.36.0 10 | google.golang.org/grpc v1.73.0 11 | google.golang.org/protobuf v1.36.6 12 | ) 13 | 14 | require ( 15 | github.com/go-kratos/aegis v0.2.0 // indirect 16 | github.com/go-logr/logr v1.4.3 // indirect 17 | github.com/go-logr/stdr v1.2.2 // indirect 18 | github.com/go-playground/assert/v2 v2.2.0 // indirect 19 | github.com/go-playground/form/v4 v4.2.3 // indirect 20 | github.com/google/uuid v1.6.0 // indirect 21 | github.com/gorilla/mux v1.8.1 // indirect 22 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 23 | go.opentelemetry.io/otel/metric v1.36.0 // indirect 24 | golang.org/x/net v0.40.0 // indirect 25 | golang.org/x/sync v0.15.0 // indirect 26 | golang.org/x/sys v0.33.0 // indirect 27 | google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect 28 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 29 | gopkg.in/yaml.v3 v3.0.1 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /kratos/middleware/tracing/internal/buf.gen.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | plugins: 3 | - remote: buf.build/protocolbuffers/go 4 | out: proto 5 | opt: paths=source_relative 6 | - remote: buf.build/grpc/go 7 | out: proto 8 | opt: paths=source_relative -------------------------------------------------------------------------------- /kratos/middleware/tracing/internal/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | modules: 3 | - path: proto 4 | lint: 5 | use: 6 | - DEFAULT 7 | except: 8 | - FIELD_NOT_REQUIRED 9 | - PACKAGE_NO_IMPORT_CYCLE 10 | - SERVICE_SUFFIX 11 | rpc_allow_same_request_response: true 12 | rpc_allow_google_protobuf_empty_requests: true 13 | rpc_allow_google_protobuf_empty_responses: true 14 | breaking: 15 | use: 16 | - FILE -------------------------------------------------------------------------------- /kratos/middleware/tracing/internal/proto/tracing/v1/hello.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package tracing.v1; 4 | 5 | option go_package = "tracing/v1;tracingpb"; 6 | 7 | message HelloRequest { 8 | string name = 1; 9 | } -------------------------------------------------------------------------------- /kratos/middleware/tracing/metadata.go: -------------------------------------------------------------------------------- 1 | package tracing 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/go-kratos/kratos/v2" 7 | "github.com/go-kratos/kratos/v2/metadata" 8 | "go.opentelemetry.io/otel/propagation" 9 | ) 10 | 11 | const serviceHeader = "x-md-service-name" 12 | 13 | // Metadata is tracing metadata propagator 14 | type Metadata struct{} 15 | 16 | var _ propagation.TextMapPropagator = Metadata{} 17 | 18 | // Inject sets metadata key-values from ctx into the carrier. 19 | func (b Metadata) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { 20 | app, ok := kratos.FromContext(ctx) 21 | if ok { 22 | carrier.Set(serviceHeader, app.Name()) 23 | } 24 | } 25 | 26 | // Extract returns a copy of parent with the metadata from the carrier added. 27 | func (b Metadata) Extract(parent context.Context, carrier propagation.TextMapCarrier) context.Context { 28 | name := carrier.Get(serviceHeader) 29 | if name == "" { 30 | return parent 31 | } 32 | if md, ok := metadata.FromServerContext(parent); ok { 33 | md.Set(serviceHeader, name) 34 | return parent 35 | } 36 | md := metadata.New() 37 | md.Set(serviceHeader, name) 38 | return metadata.NewServerContext(parent, md) 39 | } 40 | 41 | // Fields returns the keys who's values are set with Inject. 42 | func (b Metadata) Fields() []string { 43 | return []string{serviceHeader} 44 | } 45 | -------------------------------------------------------------------------------- /kratos/middleware/tracing/statshandler.go: -------------------------------------------------------------------------------- 1 | package tracing 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "go.opentelemetry.io/otel/trace" 8 | "google.golang.org/grpc/peer" 9 | "google.golang.org/grpc/stats" 10 | ) 11 | 12 | // ClientHandler is tracing ClientHandler 13 | type ClientHandler struct{} 14 | 15 | // HandleConn exists to satisfy gRPC stats.Handler. 16 | func (c *ClientHandler) HandleConn(_ context.Context, _ stats.ConnStats) { 17 | fmt.Println("Handle connection.") 18 | } 19 | 20 | // TagConn exists to satisfy gRPC stats.Handler. 21 | func (c *ClientHandler) TagConn(ctx context.Context, _ *stats.ConnTagInfo) context.Context { 22 | return ctx 23 | } 24 | 25 | // HandleRPC implements per-RPC tracing and stats instrumentation. 26 | func (c *ClientHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) { 27 | if _, ok := rs.(*stats.OutHeader); !ok { 28 | return 29 | } 30 | p, ok := peer.FromContext(ctx) 31 | if !ok { 32 | return 33 | } 34 | span := trace.SpanFromContext(ctx) 35 | if span.SpanContext().IsValid() { 36 | span.SetAttributes(peerAttr(p.Addr.String())...) 37 | } 38 | } 39 | 40 | // TagRPC implements per-RPC context management. 41 | func (c *ClientHandler) TagRPC(ctx context.Context, _ *stats.RPCTagInfo) context.Context { 42 | return ctx 43 | } 44 | -------------------------------------------------------------------------------- /locker/README.md: -------------------------------------------------------------------------------- 1 | # Locker 2 | 3 | ## Usage 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "context" 10 | "time" 11 | 12 | "github.com/redis/go-redis/v9" 13 | 14 | "github.com/go-kratos-ecosystem/components/v2/cache" 15 | redisStore "github.com/go-kratos-ecosystem/components/v2/cache/redis" 16 | redisLocker "github.com/go-kratos-ecosystem/components/v2/locker/redis" 17 | ) 18 | 19 | func main() { 20 | client := redis.NewClient(&redis.Options{ 21 | Addr: "localhost:6379", 22 | }) 23 | 24 | // ex1: 直接用 25 | locker := redisLocker.NewLocker(client, redisLocker.WithName("lock"), redisLocker.WithTTL(5*time.Minute)) 26 | _ = locker.Try(context.Background(), func() { 27 | // do something 28 | }) 29 | 30 | // ex2: 基于缓存用 31 | repository := cache.NewRepository( 32 | redisStore.New(client, redisStore.Prefix("cache")), 33 | ) 34 | 35 | _ = repository.Lock("lock", 5*time.Minute).Try(context.Background(), func() { 36 | // do something 37 | }) 38 | } 39 | 40 | ``` -------------------------------------------------------------------------------- /locker/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/locker/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/google/uuid v1.6.0 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /locker/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 4 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 8 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 12 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 13 | -------------------------------------------------------------------------------- /locker/locker_test.go: -------------------------------------------------------------------------------- 1 | package locker 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestLocker_NoopLocker(t *testing.T) { 12 | l := NoopLocker{} 13 | ctx := context.Background() 14 | 15 | assert.NoError(t, l.Try(ctx, func() {})) 16 | assert.NoError(t, l.Until(ctx, time.Second, func() {})) 17 | 18 | o, err := l.Get(ctx) 19 | assert.NoError(t, err) 20 | assert.Nil(t, o) 21 | 22 | assert.NoError(t, l.Release(ctx, nil)) 23 | assert.NoError(t, l.ForceRelease(ctx)) 24 | 25 | o, err = l.LockedOwner(ctx) 26 | assert.NoError(t, err) 27 | assert.Nil(t, o) 28 | } 29 | -------------------------------------------------------------------------------- /locker/owner.go: -------------------------------------------------------------------------------- 1 | package locker 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/google/uuid" 7 | ) 8 | 9 | type Owner interface { 10 | // Name returns the name of the owner. 11 | Name() string 12 | 13 | // Release releases the lock. 14 | Release(ctx context.Context) error 15 | } 16 | 17 | type owner struct { 18 | name string 19 | locker Locker 20 | } 21 | 22 | type OwnerOption func(*owner) 23 | 24 | func WithOwnerName(name string) OwnerOption { 25 | return func(o *owner) { 26 | o.name = name 27 | } 28 | } 29 | 30 | func NewOwner(locker Locker, opts ...OwnerOption) Owner { 31 | o := &owner{ 32 | name: uuid.New().String(), 33 | locker: locker, 34 | } 35 | for _, opt := range opts { 36 | opt(o) 37 | } 38 | return o 39 | } 40 | 41 | func (o *owner) Name() string { 42 | return o.name 43 | } 44 | 45 | func (o *owner) Release(ctx context.Context) error { 46 | return o.locker.Release(ctx, o) 47 | } 48 | -------------------------------------------------------------------------------- /locker/owner_test.go: -------------------------------------------------------------------------------- 1 | package locker 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestOwner_owner(t *testing.T) { 11 | o := NewOwner(NoopLocker{}, WithOwnerName("test")) 12 | assert.Equal(t, "test", o.Name()) 13 | assert.NoError(t, o.Release(context.Background())) 14 | } 15 | -------------------------------------------------------------------------------- /locker/redis/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/locker/redis/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/locker/v3 => ../ 6 | 7 | require ( 8 | github.com/go-fries/fries/locker/v3 v3.4.0 9 | github.com/google/uuid v1.6.0 10 | github.com/redis/go-redis/v9 v9.9.0 11 | github.com/stretchr/testify v1.10.0 12 | ) 13 | 14 | require ( 15 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 18 | github.com/pmezard/go-difflib v1.0.0 // indirect 19 | gopkg.in/yaml.v3 v3.0.1 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /mysql/canal/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/mysql/canal/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/go-mysql-org/go-mysql v1.12.0 7 | golang.org/x/sync v0.15.0 8 | ) 9 | 10 | require ( 11 | filippo.io/edwards25519 v1.1.0 // indirect 12 | github.com/BurntSushi/toml v1.5.0 // indirect 13 | github.com/Masterminds/semver v1.5.0 // indirect 14 | github.com/goccy/go-json v0.10.5 // indirect 15 | github.com/google/uuid v1.6.0 // indirect 16 | github.com/klauspost/compress v1.18.0 // indirect 17 | github.com/pingcap/errors v0.11.5-0.20250523034308-74f78ae071ee // indirect 18 | github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 // indirect 19 | github.com/pingcap/log v1.1.1-0.20250514022801-14f3b4ca066e // indirect 20 | github.com/pingcap/tidb/pkg/parser v0.0.0-20250531022214-e7b038b99132 // indirect 21 | github.com/shopspring/decimal v1.4.0 // indirect 22 | github.com/stretchr/testify v1.10.0 // indirect 23 | go.uber.org/atomic v1.11.0 // indirect 24 | go.uber.org/multierr v1.11.0 // indirect 25 | go.uber.org/zap v1.27.0 // indirect 26 | golang.org/x/text v0.25.0 // indirect 27 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /mysql/canal/positioner.go: -------------------------------------------------------------------------------- 1 | package canal 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/go-mysql-org/go-mysql/mysql" 8 | ) 9 | 10 | var ErrPositionNotFound = errors.New("canal: position not found") 11 | 12 | type Positioner interface { 13 | Get(ctx context.Context) (mysql.Position, error) 14 | Set(ctx context.Context, pos mysql.Position) error 15 | } 16 | 17 | // positionListener is a listener that listens for position sync events and updates the positioner. 18 | // This listener will be automatically injected into Canal by default to update relevant information. 19 | type positionListener struct { 20 | positioner Positioner 21 | } 22 | 23 | var _ PosSyncedListener = (*positionListener)(nil) 24 | 25 | func newPositionListener(positioner Positioner) *positionListener { 26 | return &positionListener{ 27 | positioner: positioner, 28 | } 29 | } 30 | 31 | func (p *positionListener) OnPosSynced(ctx context.Context, event *PosSyncedEvent) error { 32 | return p.positioner.Set(ctx, event.Pos) 33 | } 34 | -------------------------------------------------------------------------------- /mysql/canal/positioner/redis/options.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/go-fries/fries/codec/v3" 7 | ) 8 | 9 | type BaseAndBufferedOption interface { 10 | Option 11 | BufferedOption 12 | } 13 | 14 | type prefixOption struct { 15 | prefix string 16 | } 17 | 18 | var _ BaseAndBufferedOption = (*prefixOption)(nil) 19 | 20 | func WithPrefix(prefix string) BaseAndBufferedOption { 21 | return &prefixOption{ 22 | prefix: prefix, 23 | } 24 | } 25 | 26 | func (p *prefixOption) apply(positioner *Positioner) { 27 | prefix := strings.TrimSuffix(p.prefix, ":") 28 | if prefix != "" { 29 | positioner.prefix = prefix + ":" 30 | } 31 | } 32 | 33 | func (p *prefixOption) applyBuffered(positioner *BufferedPositioner) { 34 | p.apply(positioner.Positioner) 35 | } 36 | 37 | type codecOption struct { 38 | codec codec.Codec 39 | } 40 | 41 | var _ BaseAndBufferedOption = (*codecOption)(nil) 42 | 43 | func WithCodec(codec codec.Codec) BaseAndBufferedOption { 44 | return &codecOption{ 45 | codec: codec, 46 | } 47 | } 48 | 49 | func (c *codecOption) apply(positioner *Positioner) { 50 | positioner.codec = c.codec 51 | } 52 | 53 | func (c *codecOption) applyBuffered(positioner *BufferedPositioner) { 54 | positioner.codec = c.codec 55 | } 56 | -------------------------------------------------------------------------------- /mysql/canal/server/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/mysql/canal/server/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/mysql/canal/v3 => ../ 6 | 7 | require ( 8 | github.com/go-fries/fries/mysql/canal/v3 v3.4.0 9 | github.com/go-kratos/kratos/v2 v2.8.4 10 | ) 11 | 12 | require ( 13 | filippo.io/edwards25519 v1.1.0 // indirect 14 | github.com/BurntSushi/toml v1.5.0 // indirect 15 | github.com/Masterminds/semver v1.5.0 // indirect 16 | github.com/go-mysql-org/go-mysql v1.12.0 // indirect 17 | github.com/go-playground/form/v4 v4.2.1 // indirect 18 | github.com/goccy/go-json v0.10.5 // indirect 19 | github.com/google/uuid v1.6.0 // indirect 20 | github.com/klauspost/compress v1.18.0 // indirect 21 | github.com/pingcap/errors v0.11.5-0.20250523034308-74f78ae071ee // indirect 22 | github.com/pingcap/failpoint v0.0.0-20240528011301-b51a646c7c86 // indirect 23 | github.com/pingcap/log v1.1.1-0.20250514022801-14f3b4ca066e // indirect 24 | github.com/pingcap/tidb/pkg/parser v0.0.0-20250531022214-e7b038b99132 // indirect 25 | github.com/shopspring/decimal v1.4.0 // indirect 26 | go.uber.org/atomic v1.11.0 // indirect 27 | go.uber.org/multierr v1.11.0 // indirect 28 | go.uber.org/zap v1.27.0 // indirect 29 | golang.org/x/sync v0.15.0 // indirect 30 | golang.org/x/text v0.25.0 // indirect 31 | google.golang.org/protobuf v1.36.6 // indirect 32 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect 33 | gopkg.in/yaml.v3 v3.0.1 // indirect 34 | ) 35 | -------------------------------------------------------------------------------- /mysql/canal/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/go-fries/fries/mysql/canal/v3" 7 | "github.com/go-kratos/kratos/v2/log" 8 | "github.com/go-kratos/kratos/v2/transport" 9 | ) 10 | 11 | type Server struct { 12 | canal *canal.Canal 13 | } 14 | 15 | var _ transport.Server = (*Server)(nil) 16 | 17 | func New(canal *canal.Canal) *Server { 18 | return &Server{ 19 | canal: canal, 20 | } 21 | } 22 | 23 | func (s *Server) Start(ctx context.Context) error { 24 | log.Infof("[Canal] server starting") 25 | return s.canal.Start(ctx) 26 | } 27 | 28 | func (s *Server) Stop(ctx context.Context) error { 29 | log.Infof("[Canal] server stopping") 30 | return s.canal.Stop(ctx) 31 | } 32 | -------------------------------------------------------------------------------- /otel/otlp/README.md: -------------------------------------------------------------------------------- 1 | # OTLP Configuration 2 | 3 | This package provides a configuration for the OpenTelemetry Protocol (OTLP) exporter. 4 | 5 | ## Installation 6 | 7 | ```shell 8 | go get github.com/go-fries/fries/otel/otlp/v3 9 | ``` 10 | 11 | ## Usage Example 12 | 13 | ```go 14 | package main 15 | 16 | import ( 17 | "context" 18 | 19 | "github.com/go-fries/fries/otel/otlp/v3" 20 | "go.opentelemetry.io/otel/attribute" 21 | ) 22 | 23 | func main() { 24 | ctx := context.TODO() 25 | 26 | // transport 27 | transport := otlp.NewGRPCTransport("localhost:4317", 28 | otlp.WithGRPCTransportInsecure(true), 29 | ) 30 | 31 | // client 32 | client := otlp.NewClient( 33 | otlp.WithServiceName("service-name"), 34 | otlp.WithDeploymentEnvironmentName("production"), 35 | otlp.WithAttributes( 36 | attribute.String("key", "value"), 37 | // ... 38 | ), 39 | otlp.WithTransport(transport), 40 | ) 41 | 42 | if err := client.Configure(ctx); err != nil { 43 | panic(err) 44 | } 45 | 46 | defer client.Shutdown(ctx) 47 | 48 | // do something 49 | } 50 | ``` -------------------------------------------------------------------------------- /otel/otlp/hook.go: -------------------------------------------------------------------------------- 1 | package otlp 2 | 3 | import ( 4 | "context" 5 | 6 | hostmetrics "go.opentelemetry.io/contrib/instrumentation/host" 7 | runtimemetrics "go.opentelemetry.io/contrib/instrumentation/runtime" 8 | ) 9 | 10 | // DefaultHooks are the hooks that are enabled by default. 11 | var DefaultHooks = []Hook{ 12 | &RuntimeMetricsHook{}, 13 | &HostMetricsHook{}, 14 | } 15 | 16 | type Hook interface { 17 | // Configured is called after the client is fully configured. 18 | Configured(ctx context.Context, client *Client) error 19 | } 20 | 21 | // RuntimeMetricsHook is a hook that starts the runtime metrics collection. 22 | type RuntimeMetricsHook struct{} 23 | 24 | func (r *RuntimeMetricsHook) Configured(context.Context, *Client) error { 25 | return runtimemetrics.Start() 26 | } 27 | 28 | // HostMetricsHook is a hook that starts the host metrics collection. 29 | type HostMetricsHook struct{} 30 | 31 | func (h *HostMetricsHook) Configured(context.Context, *Client) error { 32 | return hostmetrics.Start() 33 | } 34 | -------------------------------------------------------------------------------- /otel/otlp/provider.go: -------------------------------------------------------------------------------- 1 | package otlp 2 | 3 | import ( 4 | "context" 5 | 6 | foundation "github.com/go-fries/fries/foundation/v3" 7 | ) 8 | 9 | type Provider struct { 10 | client *Client 11 | } 12 | 13 | var _ foundation.Provider = (*Provider)(nil) 14 | 15 | func NewProvider(client *Client) *Provider { 16 | return &Provider{ 17 | client: client, 18 | } 19 | } 20 | 21 | func (p *Provider) Bootstrap(ctx context.Context) (context.Context, error) { 22 | return ctx, p.client.Configure(ctx) 23 | } 24 | 25 | func (p *Provider) Terminate(ctx context.Context) (context.Context, error) { 26 | return ctx, p.client.Shutdown(ctx) 27 | } 28 | -------------------------------------------------------------------------------- /recovery/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/recovery/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /recovery/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /recovery/recovery.go: -------------------------------------------------------------------------------- 1 | package recovery 2 | 3 | type Recovery struct { 4 | handler func(err any) 5 | } 6 | 7 | type Option func(o *Recovery) 8 | 9 | func WithHandler(handler func(err any)) Option { 10 | return func(r *Recovery) { 11 | r.handler = handler 12 | } 13 | } 14 | 15 | func New(opts ...Option) *Recovery { 16 | r := &Recovery{ 17 | handler: func(err any) { 18 | panic(err) 19 | }, 20 | } 21 | 22 | for _, opt := range opts { 23 | opt(r) 24 | } 25 | 26 | return r 27 | } 28 | 29 | func (r *Recovery) Wrap(f func()) { 30 | if r.handler != nil { 31 | defer func() { 32 | if err := recover(); err != nil { 33 | r.handler(err) 34 | } 35 | }() 36 | } 37 | 38 | f() 39 | } 40 | -------------------------------------------------------------------------------- /recovery/recovery_test.go: -------------------------------------------------------------------------------- 1 | package recovery 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestRecovery_Wrap(t *testing.T) { 10 | fn := func() { 11 | panic("test") 12 | } 13 | 14 | // default 15 | r := New() 16 | assert.Panics(t, func() { 17 | r.Wrap(fn) 18 | }) 19 | 20 | // with handler 21 | r = New(WithHandler(func(err any) { 22 | assert.Equal(t, "test", err) 23 | })) 24 | 25 | assert.NotPanics(t, func() { 26 | r.Wrap(fn) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /redis/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/redis/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/redis/go-redis/v9 v9.9.0 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | gopkg.in/yaml.v3 v3.0.1 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /redis/manager.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import "github.com/redis/go-redis/v9" 4 | 5 | type Manager struct { 6 | redis.UniversalClient 7 | 8 | connections map[string]redis.UniversalClient 9 | } 10 | 11 | func New(db redis.UniversalClient) *Manager { 12 | return &Manager{ 13 | UniversalClient: db, 14 | connections: make(map[string]redis.UniversalClient), 15 | } 16 | } 17 | 18 | func (m *Manager) Register(name string, db redis.UniversalClient) { 19 | m.connections[name] = db 20 | } 21 | 22 | func (m *Manager) Conn(names ...string) redis.UniversalClient { 23 | var name string 24 | if len(names) > 0 { 25 | name = names[0] 26 | } 27 | 28 | if name == "" { 29 | return m.UniversalClient 30 | } 31 | 32 | if c, ok := m.connections[name]; ok { 33 | return c 34 | } 35 | 36 | panic("redis: the connection [" + name + "] is not registered.") 37 | } 38 | -------------------------------------------------------------------------------- /redis/manager_test.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/redis/go-redis/v9" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestManager(t *testing.T) { 13 | ctx := context.Background() 14 | rdb := redis.NewClient(&redis.Options{ 15 | Addr: "localhost:6379", 16 | }) 17 | 18 | m := New(rdb) 19 | 20 | m.Register("rdb2", rdb) 21 | 22 | assert.Equal(t, rdb, m.UniversalClient) 23 | assert.Equal(t, rdb, m.Conn()) 24 | assert.Equal(t, rdb, m.Conn("rdb2")) 25 | 26 | assert.Panics(t, func() { 27 | m.Conn("rdb3") 28 | }) 29 | 30 | var ( 31 | key1 = "redis:manager:key1" 32 | key2 = "redis:manager:key2" 33 | key3 = "redis:manager:key3" 34 | ) 35 | 36 | m.Set(ctx, key1, "value1", time.Second*10) 37 | m.Conn().Set(ctx, key2, "value2", time.Second*10) 38 | m.Conn("rdb2").Set(ctx, key3, "value3", time.Second*10) 39 | 40 | // default connection 41 | val, err := m.Get(ctx, key1).Result() 42 | assert.NoError(t, err) 43 | assert.Equal(t, "value1", val) 44 | 45 | // empty name connection 46 | val, err = m.Conn().Get(ctx, key2).Result() 47 | assert.NoError(t, err) 48 | assert.Equal(t, "value2", val) 49 | 50 | // use named connection 51 | val, err = m.Conn("rdb2").Get(ctx, key3).Result() 52 | assert.NoError(t, err) 53 | assert.Equal(t, "value3", val) 54 | } 55 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | ":configMigration" 6 | ], 7 | "labels": [ 8 | "dependencies" 9 | ], 10 | "ignorePaths": [], 11 | "separateMajorMinor": true, 12 | "postUpdateOptions": [ 13 | "gomodTidy" 14 | ], 15 | "constraints": { 16 | "go": "1.23.0" 17 | }, 18 | "packageRules": [ 19 | { 20 | "matchManagers": ["gomod"], 21 | "matchDepTypes": ["indirect"], 22 | "enabled": true 23 | }, 24 | { 25 | "matchPackageNames": ["go.opentelemetry.io/build-tools/**"], 26 | "groupName": "go.opentelemetry.io/build-tools" 27 | }, 28 | { 29 | "matchPackageNames": ["github.com/pingcap/tidb/**"], 30 | "groupName": "github.com/pingcap/tidb", 31 | "schedule": ["* * 1 * *"] 32 | }, 33 | { 34 | "matchPackageNames": ["golang.org/x/**"], 35 | "groupName": "golang.org/x" 36 | }, 37 | { 38 | "matchPackageNames": ["go.opentelemetry.io/otel/**"], 39 | "groupName": "go.opentelemetry.io/otel" 40 | }, 41 | { 42 | "matchPackageNames": ["google.golang.org/genproto/googleapis/**"], 43 | "groupName": "googleapis" 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /signal/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/signal/v3 2 | 3 | go 1.23.0 4 | 5 | replace github.com/go-fries/fries/contract/v3 => ../contract 6 | 7 | require ( 8 | github.com/go-fries/fries/contract/v3 v3.4.0 9 | github.com/go-kratos/kratos/v2 v2.8.4 10 | github.com/stretchr/testify v1.10.0 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/kr/text v0.2.0 // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | golang.org/x/sync v0.15.0 // indirect 18 | gopkg.in/yaml.v3 v3.0.1 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /signal/handler.go: -------------------------------------------------------------------------------- 1 | package signal 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | type Handler interface { 8 | Listen() []os.Signal 9 | Handle(os.Signal) 10 | } 11 | -------------------------------------------------------------------------------- /support/collection/README.md: -------------------------------------------------------------------------------- 1 | # Collection 2 | 3 | ## Example 4 | 5 | ```go 6 | package main 7 | 8 | import "github.com/go-kratos-ecosystem/components/v2/collection" 9 | 10 | func main() { 11 | // int 12 | c := collection.New([]int{1, 2, 3}) 13 | c.Add(4) //nolint:gomnd 14 | c.Items() 15 | c.All() 16 | c.Len() 17 | c.Map(func(i int, _ int) int { 18 | return i * 2 19 | }) 20 | c.Filter(func(v int, _ int) bool { 21 | return v > 4 22 | }) 23 | c.Where(func(v int, _ int) bool { 24 | return v > 4 25 | }) 26 | c.Reduce(func(a, b int) int { 27 | return a + b 28 | }) 29 | // .... 30 | 31 | // string 32 | c2 := collection.New([]string{"a", "b", "c"}) 33 | c2.Add("d") 34 | 35 | // and so on 36 | } 37 | ``` -------------------------------------------------------------------------------- /support/contexts/contexts.go: -------------------------------------------------------------------------------- 1 | package contexts 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type Handler func(ctx context.Context) (context.Context, error) 8 | 9 | // Deprecated: Use Handler instead. 10 | type Func Handler 11 | 12 | // Pipe returns a Provider that chains the provided Providers. 13 | func Pipe(ctx context.Context, fns ...Handler) (context.Context, error) { 14 | var err error 15 | for _, fn := range fns { 16 | if fn != nil { 17 | if ctx, err = fn(ctx); err != nil { 18 | return ctx, err 19 | } 20 | } 21 | } 22 | return ctx, nil 23 | } 24 | 25 | // Chain is a reverse Pipe. 26 | func Chain(ctx context.Context, fns ...Handler) (context.Context, error) { 27 | var err error 28 | for i := len(fns) - 1; i >= 0; i-- { 29 | if fns[i] != nil { 30 | if ctx, err = fns[i](ctx); err != nil { 31 | return ctx, err 32 | } 33 | } 34 | } 35 | return ctx, nil 36 | } 37 | -------------------------------------------------------------------------------- /support/contexts/values.go: -------------------------------------------------------------------------------- 1 | package contexts 2 | 3 | import "context" 4 | 5 | func Value[T any](ctx context.Context, key any) (T, bool) { 6 | v, ok := ctx.Value(key).(T) 7 | return v, ok 8 | } 9 | 10 | func MustValue[T any](ctx context.Context, key any) T { 11 | v, ok := Value[T](ctx, key) 12 | if !ok { 13 | panic("contexts: key not exists") 14 | } 15 | return v 16 | } 17 | -------------------------------------------------------------------------------- /support/contexts/values_test.go: -------------------------------------------------------------------------------- 1 | package contexts 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestValue(t *testing.T) { 11 | ctx := context.Background() 12 | 13 | type ( 14 | key1 struct{} 15 | key2 struct{} 16 | key3 struct{} 17 | key4 struct{} 18 | ) 19 | 20 | ctx1 := context.WithValue(ctx, key1{}, "test") 21 | assert.Equal(t, "test", MustValue[string](ctx1, key1{})) 22 | 23 | ctx2 := context.WithValue(ctx, key2{}, 1) 24 | assert.Equal(t, 1, MustValue[int](ctx2, key2{})) 25 | 26 | ctx3 := context.WithValue(ctx, key3{}, 1.1) 27 | assert.Equal(t, 1.1, MustValue[float64](ctx3, key3{})) 28 | 29 | assert.Panics(t, func() { 30 | MustValue[string](ctx, key4{}) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /support/coordinator/README.md: -------------------------------------------------------------------------------- 1 | # Coordinator 2 | 3 | ## Usage 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "sync" 11 | 12 | "github.com/go-kratos-ecosystem/components/v2/coordinator" 13 | ) 14 | 15 | func main() { 16 | var wg sync.WaitGroup 17 | wg.Add(3) //nolint:gomnd 18 | 19 | go func() { 20 | defer wg.Done() 21 | if <-coordinator.Until("foo").Done(); true { 22 | fmt.Println("foo") 23 | } 24 | }() 25 | 26 | go func() { 27 | defer wg.Done() 28 | if <-coordinator.Until("foo").Done(); true { 29 | fmt.Println("foo 2") 30 | } 31 | }() 32 | 33 | go func() { 34 | defer wg.Done() 35 | if <-coordinator.Until("bar").Done(); true { 36 | fmt.Println("bar") 37 | } 38 | }() 39 | 40 | coordinator.Until("foo").Close() 41 | coordinator.Until("bar").Close() 42 | 43 | wg.Wait() 44 | } 45 | 46 | ``` -------------------------------------------------------------------------------- /support/coordinator/coordinator.go: -------------------------------------------------------------------------------- 1 | package coordinator 2 | 3 | import "sync" 4 | 5 | type Coordinator struct { 6 | c chan struct{} 7 | once sync.Once 8 | } 9 | 10 | func NewCoordinator() *Coordinator { 11 | return &Coordinator{ 12 | c: make(chan struct{}), 13 | } 14 | } 15 | 16 | func (c *Coordinator) Done() <-chan struct{} { 17 | return c.c 18 | } 19 | 20 | func (c *Coordinator) Close() { 21 | c.once.Do(func() { 22 | close(c.c) 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /support/coordinator/coordinator_test.go: -------------------------------------------------------------------------------- 1 | package coordinator 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestCoordinator(t *testing.T) { 10 | c := NewCoordinator() 11 | var wg sync.WaitGroup 12 | 13 | wg.Add(1) 14 | 15 | go func() { 16 | defer wg.Done() 17 | 18 | timer := time.NewTimer(1 * time.Second) 19 | defer timer.Stop() 20 | 21 | for { 22 | select { 23 | case <-c.Done(): 24 | return 25 | case <-timer.C: 26 | t.Error("timeout") 27 | return 28 | } 29 | } 30 | }() 31 | 32 | c.Close() 33 | wg.Wait() 34 | } 35 | 36 | func TestCoordinator2(t *testing.T) { 37 | c := NewCoordinator() 38 | var wg sync.WaitGroup 39 | 40 | wg.Add(1) 41 | 42 | go func() { 43 | defer wg.Done() 44 | 45 | timer := time.NewTimer(1 * time.Second) 46 | defer timer.Stop() 47 | 48 | for { 49 | select { 50 | case <-c.Done(): 51 | t.Error("timeout") 52 | return 53 | case <-timer.C: 54 | return 55 | } 56 | } 57 | }() 58 | 59 | time.Sleep(2 * time.Second) 60 | 61 | c.Close() 62 | wg.Wait() 63 | } 64 | -------------------------------------------------------------------------------- /support/coordinator/manager_test.go: -------------------------------------------------------------------------------- 1 | package coordinator 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestManager(t *testing.T) { 11 | wg := sync.WaitGroup{} 12 | ch := make(chan struct{}, 10) 13 | 14 | c1 := Until("foo") 15 | c2 := Until("foo") 16 | 17 | assert.Same(t, c1, c2) 18 | assert.Equal(t, 0, len(ch)) 19 | 20 | wg.Add(2) 21 | go func() { 22 | defer wg.Done() 23 | 24 | if <-c1.Done(); true { 25 | ch <- struct{}{} 26 | return 27 | } 28 | }() 29 | go func() { 30 | defer wg.Done() 31 | 32 | if <-c2.Done(); true { 33 | ch <- struct{}{} 34 | return 35 | } 36 | }() 37 | 38 | c1.Close() 39 | 40 | wg.Wait() 41 | assert.Equal(t, 2, len(ch)) 42 | 43 | // Clear all coordinators 44 | Clear() 45 | 46 | c3 := Until("foo") 47 | assert.NotSame(t, c1, c3) 48 | 49 | // Close foo coordinators 50 | wg.Add(1) 51 | go func() { 52 | defer wg.Done() 53 | 54 | if <-c3.Done(); true { 55 | ch <- struct{}{} 56 | return 57 | } 58 | }() 59 | assert.Equal(t, 2, len(ch)) 60 | Close("foo") 61 | wg.Wait() 62 | assert.Equal(t, 3, len(ch)) 63 | 64 | // Close non-exist coordinator 65 | assert.NotPanics(t, func() { 66 | Close("bar") 67 | }) 68 | } 69 | -------------------------------------------------------------------------------- /support/debug/dump.go: -------------------------------------------------------------------------------- 1 | package debug 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/davecgh/go-spew/spew" 7 | ) 8 | 9 | // Dump dumps the given values. 10 | // It is a wrapper for spew.Dump(https://github.com/davecgh/go-spew) 11 | // This is useful for debugging. 12 | func Dump(v ...any) { 13 | spew.Dump(v...) 14 | } 15 | 16 | // Sdump the given values and returns the result. 17 | // It's a wrapper for spew.Sdump(https://github.com/davecgh/go-spew) 18 | // This is useful for debugging. 19 | func Sdump(v ...any) string { 20 | return spew.Sdump(v...) 21 | } 22 | 23 | // Fdump the given values to the given writer. 24 | // It's a wrapper for spew.Fdump(https://github.com/davecgh/go-spew) 25 | // This is useful for debugging. 26 | func Fdump(w io.Writer, v ...any) { 27 | spew.Fdump(w, v...) 28 | } 29 | -------------------------------------------------------------------------------- /support/debug/dump_test.go: -------------------------------------------------------------------------------- 1 | package debug 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | func TestDump(_ *testing.T) { 10 | Dump("foo", []byte("1234567890"), &struct { 11 | Name string 12 | }{ 13 | Name: "foo", 14 | }, func() { 15 | panic("foo") 16 | }) 17 | 18 | fmt.Println(Sdump("foo", []byte("1234567890"), &struct { 19 | Name string 20 | }{ 21 | Name: "foo", 22 | })) 23 | 24 | Fdump(os.Stdout, "foo", []byte("1234567890"), &struct { 25 | Name string 26 | }{ 27 | Name: "foo", 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /support/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/support/v3 2 | 3 | go 1.23.0 4 | 5 | replace ( 6 | github.com/go-fries/fries/constraints/v3 => ../constraints 7 | github.com/go-fries/fries/errors/v3 => ../errors 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 12 | github.com/go-fries/fries/constraints/v3 v3.4.0 13 | github.com/go-fries/fries/errors/v3 v3.4.0 14 | github.com/google/uuid v1.6.0 15 | github.com/stretchr/testify v1.10.0 16 | ) 17 | 18 | require ( 19 | github.com/go-kratos/kratos/v2 v2.8.4 // indirect 20 | github.com/pmezard/go-difflib v1.0.0 // indirect 21 | golang.org/x/sys v0.33.0 // indirect 22 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect 23 | google.golang.org/grpc v1.73.0 // indirect 24 | google.golang.org/protobuf v1.36.6 // indirect 25 | gopkg.in/yaml.v3 v3.0.1 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /support/maps/README.md: -------------------------------------------------------------------------------- 1 | # Maps 2 | 3 | ## Example 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/go-kratos-ecosystem/components/v2/maps" 12 | ) 13 | 14 | func main() { 15 | m := maps.M{} 16 | 17 | m.Merge(map[string]any{ 18 | "name": "Flc", 19 | "age": 18, //nolint:gomnd 20 | "sex": "man", 21 | "address": "China", 22 | "phone": "123456789", 23 | }) 24 | 25 | m.When(true, func(m maps.Maps) maps.Maps { 26 | return m.Set("first name", "wu"). 27 | Set("last name", "Flc"). 28 | Set("age", 19) //nolint:gomnd 29 | }) 30 | 31 | fmt.Println(m.Maps()) 32 | 33 | // output: 34 | // map[address:China age:19 first name:wu last name:Flc name:Flc phone:123456789 sex:man] 35 | } 36 | ``` -------------------------------------------------------------------------------- /support/proxy_value.go: -------------------------------------------------------------------------------- 1 | package support 2 | 3 | type Proxy[T any] struct { 4 | value T 5 | } 6 | 7 | func NewProxy[T any](value T) *Proxy[T] { 8 | return &Proxy[T]{ 9 | value: value, 10 | } 11 | } 12 | 13 | func (p *Proxy[T]) Tap(callbacks ...func(T)) *Proxy[T] { 14 | for _, callback := range callbacks { 15 | if callback != nil { 16 | callback(p.value) 17 | } 18 | } 19 | return p 20 | } 21 | 22 | func (p *Proxy[T]) With(callbacks ...func(T) T) *Proxy[T] { 23 | for _, callback := range callbacks { 24 | if callback != nil { 25 | p.value = callback(p.value) 26 | } 27 | } 28 | return p 29 | } 30 | 31 | func (p *Proxy[T]) When(condition bool, callbacks ...func(T) T) *Proxy[T] { 32 | if condition { 33 | return p.With(callbacks...) 34 | } 35 | return p 36 | } 37 | 38 | func (p *Proxy[T]) Unless(condition bool, callbacks ...func(T) T) *Proxy[T] { 39 | return p.When(!condition, callbacks...) 40 | } 41 | 42 | func (p *Proxy[T]) Transform(callback func(T) T) *Proxy[T] { 43 | if callback != nil { 44 | p.value = callback(p.value) 45 | } 46 | return p 47 | } 48 | 49 | func (p *Proxy[T]) Value() T { 50 | return p.value 51 | } 52 | -------------------------------------------------------------------------------- /timezone/context.go: -------------------------------------------------------------------------------- 1 | package timezone 2 | 3 | import ( 4 | "context" 5 | "time" 6 | ) 7 | 8 | type contextKey struct{} 9 | 10 | func NewContext(ctx context.Context, local *time.Location) context.Context { 11 | return context.WithValue(ctx, contextKey{}, local) 12 | } 13 | 14 | func FromContext(ctx context.Context) (*time.Location, bool) { 15 | local, ok := ctx.Value(contextKey{}).(*time.Location) 16 | return local, ok 17 | } 18 | -------------------------------------------------------------------------------- /timezone/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/timezone/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /timezone/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /timezone/provider.go: -------------------------------------------------------------------------------- 1 | package timezone 2 | 3 | import ( 4 | "context" 5 | "time" 6 | ) 7 | 8 | var ( 9 | UTC = time.UTC 10 | PRC, _ = time.LoadLocation("Asia/Shanghai") 11 | Taipei, _ = time.LoadLocation("Asia/Taipei") 12 | ) 13 | 14 | func MustLoadLocation(name string) *time.Location { 15 | loc, err := time.LoadLocation(name) 16 | if err != nil { 17 | panic(err) 18 | } 19 | return loc 20 | } 21 | 22 | type Provider struct { 23 | local *time.Location 24 | } 25 | 26 | func NewProvider(local *time.Location) *Provider { 27 | return &Provider{local: local} 28 | } 29 | 30 | func (p *Provider) Bootstrap(ctx context.Context) (context.Context, error) { 31 | time.Local = p.local 32 | return NewContext(ctx, p.local), nil 33 | } 34 | 35 | func (p *Provider) Terminate(ctx context.Context) (context.Context, error) { 36 | return ctx, nil 37 | } 38 | -------------------------------------------------------------------------------- /timezone/provider_test.go: -------------------------------------------------------------------------------- 1 | package timezone 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestProvider_Vars(t *testing.T) { 12 | assert.Equal(t, time.UTC, UTC) 13 | assert.Equal(t, "Asia/Shanghai", PRC.String()) 14 | assert.Equal(t, "Asia/Taipei", Taipei.String()) 15 | } 16 | 17 | func TestMustLoadLocation(t *testing.T) { 18 | assert.Panics(t, func() { 19 | MustLoadLocation("invalid") 20 | }) 21 | assert.Equal(t, "Asia/Shanghai", MustLoadLocation("Asia/Shanghai").String()) 22 | } 23 | 24 | func TestProvider(t *testing.T) { 25 | assert.Equal(t, "Local", time.Local.String()) 26 | 27 | p := NewProvider(PRC) 28 | 29 | ctx, err := p.Bootstrap(context.Background()) 30 | assert.NoError(t, err) 31 | assert.Equal(t, "Asia/Shanghai", time.Local.String()) 32 | 33 | l1, ok := FromContext(ctx) 34 | assert.True(t, ok) 35 | assert.Equal(t, "Asia/Shanghai", l1.String()) 36 | 37 | ctx2, err := p.Terminate(ctx) 38 | assert.NoError(t, err) 39 | l2, ok := FromContext(ctx2) 40 | assert.True(t, ok) 41 | assert.Equal(t, "Asia/Shanghai", l2.String()) 42 | } 43 | -------------------------------------------------------------------------------- /udp/README.md: -------------------------------------------------------------------------------- 1 | # UDP 2 | 3 | ## Server 4 | 5 | ```go 6 | package main 7 | 8 | import ( 9 | "log" 10 | 11 | "github.com/go-kratos/kratos/v2" 12 | 13 | "github.com/go-kratos-ecosystem/components/v2/udp" 14 | ) 15 | 16 | func main() { 17 | err := kratos.New( 18 | kratos.Server( 19 | udp.NewServer(":12190", udp.WithHandler(func(msg *udp.Message) { 20 | log.Printf("receive message: %s", msg.Body) 21 | }), udp.WithRecoveryHandler(func(msg *udp.Message, err any) { 22 | log.Println(err) 23 | }), udp.WithReadChanSize(10240)), 24 | ), 25 | ).Run() 26 | 27 | if err != nil { 28 | log.Fatal(err) 29 | } 30 | } 31 | 32 | ``` -------------------------------------------------------------------------------- /udp/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/udp/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/go-kratos/kratos/v2 v2.8.4 6 | 7 | require ( 8 | github.com/go-playground/form/v4 v4.2.3 // indirect 9 | github.com/kr/text v0.2.0 // indirect 10 | google.golang.org/protobuf v1.36.6 // indirect 11 | gopkg.in/yaml.v3 v3.0.1 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /udp/server_test.go: -------------------------------------------------------------------------------- 1 | package udp 2 | 3 | import ( 4 | "context" 5 | "net" 6 | "sync" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | func TestServer(t *testing.T) { 12 | var ( 13 | server *Server 14 | wg sync.WaitGroup 15 | done = make(chan []byte, 1) 16 | ) 17 | 18 | wg.Add(2) 19 | 20 | go func() { 21 | defer wg.Done() 22 | 23 | server = NewServer(":12190", WithHandler(func(msg *Message) { 24 | done <- msg.Body 25 | }), WithRecoveryHandler(func(_ *Message, err any) { 26 | t.Log(err) 27 | }), WithBufSize(1024)) 28 | 29 | go server.Start(context.Background()) //nolint:errcheck 30 | 31 | time.Sleep(time.Second * 5) 32 | _ = server.Stop(context.Background()) 33 | }() 34 | 35 | go func() { 36 | defer wg.Done() 37 | 38 | time.Sleep(time.Second * 3) 39 | 40 | c, err := net.Dial("udp", ":12190") 41 | if err != nil { 42 | t.Error(err) 43 | return 44 | } 45 | defer c.Close() //nolint:errcheck 46 | 47 | _, err = c.Write([]byte("test")) 48 | if err != nil { 49 | t.Error(err) 50 | return 51 | } 52 | }() 53 | 54 | wg.Wait() 55 | 56 | buf := <-done 57 | if string(buf) != "test" { 58 | t.Fatal("buf not equal test") 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package fries 2 | 3 | func Version() string { 4 | return "3.4.0" 5 | } 6 | -------------------------------------------------------------------------------- /version_test.go: -------------------------------------------------------------------------------- 1 | package fries_test 2 | 3 | import ( 4 | "regexp" 5 | "testing" 6 | 7 | "github.com/go-fries/fries/v3" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | // regex taken from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string 12 | var versionRegex = regexp.MustCompile(`^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)` + 13 | `(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)` + 14 | `(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?` + 15 | `(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`) 16 | 17 | func TestVersionSemver(t *testing.T) { 18 | v := fries.Version() 19 | assert.NotNil(t, versionRegex.FindStringSubmatch(v), "version is not semver: %s", v) 20 | } 21 | -------------------------------------------------------------------------------- /x/README.md: -------------------------------------------------------------------------------- 1 | # X 2 | 3 | The packages in this directory are not stable versions and may change at any time without backward compatibility, or even be removed. 4 | 5 | Please use them with caution!! -------------------------------------------------------------------------------- /x/container/container.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | ) 7 | 8 | var ErrKeyNotFound = errors.New("the key is not found") 9 | 10 | type Container interface { 11 | Set(key any, value any) 12 | Get(key any) (any, error) 13 | } 14 | 15 | type container struct { 16 | data map[any]any 17 | mutex sync.RWMutex 18 | } 19 | 20 | func New() Container { 21 | return &container{ 22 | data: make(map[any]any), 23 | } 24 | } 25 | 26 | func (c *container) Set(key any, value any) { 27 | c.mutex.Lock() 28 | defer c.mutex.Unlock() 29 | 30 | c.data[key] = value 31 | } 32 | 33 | func (c *container) Get(key any) (any, error) { 34 | c.mutex.RLock() 35 | defer c.mutex.RUnlock() 36 | 37 | if v, ok := c.data[key]; ok { 38 | return v, nil 39 | } 40 | return nil, ErrKeyNotFound 41 | } 42 | -------------------------------------------------------------------------------- /x/container/global.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | import ( 4 | "errors" 5 | "sync/atomic" 6 | ) 7 | 8 | var ErrTypeMismatch = errors.New("type mismatch") 9 | 10 | var global atomic.Value 11 | 12 | func SetContainer(c Container) { 13 | global.Store(c) 14 | } 15 | 16 | func GetContainer() Container { 17 | if global.Load() == nil { 18 | SetContainer(New()) 19 | } 20 | return global.Load().(Container) 21 | } 22 | 23 | func Set[T any](key any, value T) { 24 | GetContainer().Set(key, value) 25 | } 26 | 27 | func Get[T any](key any) (T, error) { 28 | v, err := GetContainer().Get(key) 29 | if err != nil { 30 | var zero T 31 | return zero, err 32 | } 33 | if vv, ok := v.(T); ok { 34 | return vv, nil 35 | } 36 | var zero T 37 | return zero, ErrTypeMismatch 38 | } 39 | 40 | func MustGet[T any](key any) T { 41 | v, err := Get[T](key) 42 | if err != nil { 43 | panic(err) 44 | } 45 | return v 46 | } 47 | -------------------------------------------------------------------------------- /x/container/global_test.go: -------------------------------------------------------------------------------- 1 | package container 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestGlobal_SetAndGet(t *testing.T) { 11 | Set("key", "value") 12 | v, err := Get[string]("key") 13 | require.NoError(t, err) 14 | assert.Equal(t, "value", v) 15 | 16 | non, err := Get[int]("key-unknown") 17 | require.ErrorIs(t, err, ErrKeyNotFound) 18 | assert.Equal(t, 0, non) 19 | 20 | v2, err := Get[int]("key") 21 | require.ErrorIs(t, err, ErrTypeMismatch) 22 | assert.Equal(t, 0, v2) 23 | 24 | assert.Equal(t, "value", MustGet[string]("key")) 25 | assert.Panics(t, func() { 26 | MustGet[int]("key") 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /x/container/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/x/container/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /x/container/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /x/pagination/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/x/pagination/v3 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /x/pagination/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /x/prints/basic_test.go: -------------------------------------------------------------------------------- 1 | package prints 2 | 3 | import "testing" 4 | 5 | func TestInfo(*testing.T) { 6 | Line("Line: Hello World!", "Hello Go!") //nolint:errcheck 7 | Linef("Linef: %s %s\n", "Hello World!", "Hello Go!") //nolint:errcheck 8 | NewLine() //nolint:errcheck 9 | Info("Info: Hello World!", "Hello Go!") //nolint:errcheck 10 | Infof("Infof: %s %s\n", "Hello World!", "Hello Go!") //nolint:errcheck 11 | Comment("Comment: Hello World!", "Hello Go!") //nolint:errcheck 12 | Commentf("Commentf: %s %s\n", "Hello World!", "Hello Go!") //nolint:errcheck 13 | Error("Error: Hello World!", "Hello Go!") //nolint:errcheck 14 | Errorf("Errorf: %s %s\n", "Hello World!", "Hello Go!") //nolint:errcheck 15 | Warn("Warn: Hello World!", "Hello Go!") //nolint:errcheck 16 | Warnf("Warnf: %s %s\n", "Hello World!", "Hello Go!") //nolint:errcheck 17 | Alert("Alert: Hello World!", "Hello Go!") //nolint:errcheck 18 | Alertf("Alertf: %s %s\n", "Hello World!", "Hello Go!") //nolint:errcheck 19 | } 20 | -------------------------------------------------------------------------------- /x/prints/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-fries/fries/x/prints/v3 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/cheggaaa/pb/v3 v3.1.7 7 | github.com/fatih/color v1.18.0 8 | github.com/stretchr/testify v1.10.0 9 | golang.org/x/term v0.32.0 10 | ) 11 | 12 | require ( 13 | github.com/VividCortex/ewma v1.2.0 // indirect 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/mattn/go-colorable v0.1.14 // indirect 16 | github.com/mattn/go-isatty v0.0.20 // indirect 17 | github.com/mattn/go-runewidth v0.0.16 // indirect 18 | github.com/pmezard/go-difflib v1.0.0 // indirect 19 | github.com/rivo/uniseg v0.4.7 // indirect 20 | golang.org/x/sys v0.33.0 // indirect 21 | gopkg.in/yaml.v3 v3.0.1 // indirect 22 | ) 23 | -------------------------------------------------------------------------------- /x/prints/output.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-fries/fries/87659eefd879e4017e1f3bec8ddf07129a20f9ea/x/prints/output.jpg -------------------------------------------------------------------------------- /x/prints/progressbar.go: -------------------------------------------------------------------------------- 1 | package prints 2 | 3 | import "github.com/cheggaaa/pb/v3" 4 | 5 | var ( 6 | Full = pb.Full 7 | Default = pb.Default 8 | Simple = pb.Simple 9 | 10 | FullTemplate = WithTemplate(Full) 11 | DefaultTemplate = WithTemplate(Default) 12 | SimpleTemplate = WithTemplate(Simple) 13 | ) 14 | 15 | type ProgressBar struct { 16 | *pb.ProgressBar 17 | 18 | template pb.ProgressBarTemplate 19 | } 20 | 21 | type ProgressBarOption func(*ProgressBar) 22 | 23 | func WithTemplate(template pb.ProgressBarTemplate) ProgressBarOption { 24 | return func(o *ProgressBar) { 25 | o.template = template 26 | } 27 | } 28 | 29 | func NewProgressBar(total int, opts ...ProgressBarOption) *ProgressBar { 30 | p := &ProgressBar{} 31 | 32 | for _, opt := range opts { 33 | opt(p) 34 | } 35 | 36 | if p.template != "" { 37 | p.ProgressBar = p.template.Start(total) 38 | } else { 39 | p.ProgressBar = pb.StartNew(total) 40 | } 41 | 42 | return p 43 | } 44 | 45 | func WithProgressBar(total int, fc func(bar *ProgressBar), opts ...ProgressBarOption) { 46 | bar := NewProgressBar(total, opts...) 47 | fc(bar) 48 | bar.Finish() 49 | } 50 | -------------------------------------------------------------------------------- /x/prints/progressbar_test.go: -------------------------------------------------------------------------------- 1 | package prints 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cheggaaa/pb/v3" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestNewProgressBar(t *testing.T) { 11 | assert.Equal(t, pb.Full, Full) 12 | assert.Equal(t, pb.Simple, Simple) 13 | assert.Equal(t, pb.Default, Default) 14 | 15 | p1 := NewProgressBar(100) 16 | for i := 1; i <= 100; i++ { 17 | p1.Increment() 18 | } 19 | p1.Finish() 20 | 21 | p2 := NewProgressBar(100, WithTemplate(Full)) 22 | for i := 1; i <= 100; i++ { 23 | p2.Increment() 24 | } 25 | p2.Finish() 26 | } 27 | 28 | func TestWithProgressBar(*testing.T) { 29 | WithProgressBar(100, func(p *ProgressBar) { 30 | for i := 1; i <= 100; i++ { 31 | p.Increment() 32 | } 33 | }) 34 | } 35 | --------------------------------------------------------------------------------