Merge pull request #63 from foomo/fix/struct-error

fix: struct error
This commit is contained in:
Kevin Franklin Kim 2025-03-06 16:18:43 +01:00 committed by GitHub
commit f8e193bcd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 334 additions and 112 deletions

21
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,21 @@
# Contributing
If you want to submit a pull request to fix a bug or enhance an existing
feature, please first open an issue and link to that issue when you
submit your pull request.
If you have any questions about a possible submission, feel free to open
an issue too.
### Pull request process
1. Fork this repository
2. Create a branch in your fork to implement the changes. We recommend using
the issue number as part of your branch name, e.g. `1234-fixes`
3. Ensure that any documentation is updated with the changes that are required
by your fix.
4. Ensure that any samples are updated if the base image has been changed.
5. Submit the pull request. *Do not leave the pull request blank*. Explain exactly
what your changes are meant to do and provide simple steps on how to validate
your changes. Ensure that you reference the issue you created as well.
The pull request will be review before it is merged.

17
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,17 @@
---
name: Bug Report
about: Report a bug you encountered
labels: bug
---
**What happened**:
**What you expected to happen**:
**How to reproduce it (as minimally and precisely as possible)**:
**Anything else we need to know?**:
**Environment**:
- Affected Version:
- OS (e.g: `cat /etc/os-release`):
- Others:

8
.github/ISSUE_TEMPLATE/enhancement.md vendored Normal file
View File

@ -0,0 +1,8 @@
---
name: Enhancement Request
about: Suggest an enhancement
labels: enhancement
---
**What would you like to be added**:
**Why is this needed**:

19
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,19 @@
### Type of Change
- [ ] New feature
- [ ] Bug fix
- [ ] Documentation update
- [ ] Refactoring
- [ ] Hotfix
- [ ] Security patch
### Description
_[Provide a detailed explanation of the changes you have made. Include the reasons behind these changes and any relevant context. Link any related issues.]_
### Related Issue
_[If this pull request addresses an issue, please link to it here (e.g., Fixes #123).]_
### Checklist
- [ ] My code adheres to the coding and style guidelines of the project.
- [ ] I have performed a self-review of my own code.
- [ ] I have commented my code, particularly in hard-to-understand areas.
- [ ] I have made corresponding changes to the documentation.

45
.github/SECURITY.md vendored Normal file
View File

@ -0,0 +1,45 @@
# Security Guidelines
## How security is managed on this project
The foomo team and community take security seriously and wants to ensure that
we maintain a secure environment and provide secure solutions for the open
source community. To help us achieve these goals, please note the
following before using this software:
- Review the software license to understand the contributor's obligations in
terms of warranties and suitability for purpose
- For any questions or concerns about security, you can
[create an issue][new-issue] or [report a vulnerability][new-sec-issue]
- We request that you work with our security team and opt for
responsible disclosure using the guidelines below
- All security related issues and pull requests you make should be tagged with
"security" for easy identification
- Please monitor this repository and update your environment in a timely manner
as we release patches and updates
## Responsibly Disclosing Security Bugs
If you find a security bug in this repository, please work with contributors
following responsible disclosure principles and these guidelines:
- Do not submit a normal issue or pull request in our public repository, instead
[report it directly][new-sec-issue].
- We will review your submission and may follow up for additional details
- If you have a patch, we will review it and approve it privately; once approved
for release you can submit it as a pull request publicly in the repository (we
give credit where credit is due)
- We will keep you informed during our investigation, feel free to check in for
a status update
- We will release the fix and publicly disclose the issue as soon as possible,
but want to ensure we due properly due diligence before releasing
- Please do not publicly blog or post about the security issue until after we
have updated the public repo so that other downstream users have an opportunity
to patch
## Contact / Misc
If you have any questions, please reach out directly by [creating an issue][new-issue].
[new-issue]: https://github.com/foomo/gotsrpc/issues/new/choose
[new-sec-issue]: https://github.com/foomo/gotsrpc/security/advisories/new

View File

@ -1,6 +1,10 @@
# Minimum golangci-lint version required: v1.42.0
# yaml-language-server: $schema=https://golangci-lint.run/jsonschema/golangci.jsonschema.json
# https://golangci-lint.run/usage/configuration/
run:
timeout: 5m
go: 1.23.0
build-tags: [safe]
modules-download-mode: readonly
linters-settings:
revive:
@ -43,103 +47,120 @@ linters-settings:
bson: camel
linters:
disable-all: true
enable:
# Enabled by default linters:
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
- gosimple # (megacheck): Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false]
- govet # (vet, vetshadow): Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: false, auto-fix: false]
## Default linters
- errcheck # errcheck is a program for checking for unchecked errors in Go code. These unchecked errors can be critical bugs in some cases [fast: false, auto-fix: false]
- gosimple # (megacheck) Linter for Go source code that specializes in simplifying code [fast: false, auto-fix: false]
- govet # (vet, vetshadow) Vet examines Go source code and reports suspicious constructs. It is roughly the same as 'go vet' and uses its passes. [fast: false, auto-fix: false]
- ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false]
- staticcheck # (megacheck): It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false]
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code [fast: false, auto-fix: false]
- unused # (megacheck): Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false]
# Disabled by default linters:
#- canonicalheader # canonicalheader checks whether net/http.Header uses canonical header [fast: false, auto-fix: false]
#- dupword # checks for duplicate words in the source code [fast: true, auto-fix: false]
#- fatcontext # detects nested contexts in loops and function literals [fast: false, auto-fix: false]
#- iface # Detect the incorrect use of interfaces, helping developers avoid interface pollution. [fast: false, auto-fix: false]
#- interfacebloat # A linter that checks the number of methods inside an interface. [fast: true, auto-fix: false]
#- perfsprint # Checks that fmt.Sprintf can be replaced with a faster alternative. [fast: false, auto-fix: false]
#- reassign # Checks that package variables are not reassigned [fast: false, auto-fix: false]
#- recvcheck # checks for receiver type consistency [fast: false, auto-fix: false]
#- sloglint # ensure consistent code style when using log/slog [fast: false, auto-fix: false]
#- tagalign # check that struct tags are well aligned [fast: true, auto-fix: true]
#- zerologlint # Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg` [fast: false, auto-fix: false]
- staticcheck # (megacheck) It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary. The author of staticcheck doesn't support or approve the use of staticcheck as a library inside golangci-lint. [fast: false, auto-fix: false]
- unused # (megacheck) Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false]
## Recommended linters
- asasalint # check for pass []any as any in variadic func(...any) [fast: false, auto-fix: false]
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
- asciicheck # checks that all code identifiers does not have non-ASCII symbols in the name [fast: true, auto-fix: false]
- bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
- bodyclose # checks whether HTTP response body is closed successfully [fast: false, auto-fix: false]
- canonicalheader # checks whether net/http.Header uses canonical header [fast: false, auto-fix: false]
#- containedctx # containedctx is a linter that detects struct contained context.Context field [fast: true, auto-fix: false]
#- contextcheck # check the function whether to use a non-inherited context [fast: false, auto-fix: false]
#- cyclop # checks function and package cyclomatic complexity [fast: false, auto-fix: false]
#- contextcheck # check whether the function uses a non-inherited context [fast: false, auto-fix: false]
- copyloopvar # (go >= 1.22) copyloopvar is a linter detects places where loop variables are copied [fast: true, auto-fix: false]
- decorder # check declaration order and count of types, constants, variables and functions [fast: true, auto-fix: false]
#- depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
#- dupl # Tool for code clone detection [fast: true, auto-fix: false]
- durationcheck # check for two durations multiplied together [fast: false, auto-fix: false]
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted. [fast: false, auto-fix: false]
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and reports occations, where the check for the returned error can be omitted. [fast: false, auto-fix: false]
- errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. [fast: false, auto-fix: false]
- errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. [fast: false, auto-fix: false]
- exhaustive # check exhaustiveness of enum switch statements [fast: false, auto-fix: false]
#- exhaustruct # Checks if all structure fields are initialized [fast: false, auto-fix: false]
- exptostd # Detects functions from golang.org/x/exp/ that can be replaced by std functions. [auto-fix]
- fatcontext # detects nested contexts in loops and function literals [fast: false, auto-fix: false]
#- forbidigo # Forbids identifiers [fast: true, auto-fix: false]
- forcetypeassert # finds forced type assertions [fast: true, auto-fix: false]
#- funlen # Tool for detection of long functions [fast: true, auto-fix: false]
#- gci # Gci controls golang package import order and makes it always deterministic. [fast: true, auto-fix: false]
#- gochecknoglobals # check that no global variables exist [fast: true, auto-fix: false]
#- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
#- gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
- gocheckcompilerdirectives # Checks that go compiler directive comments (//go:) are valid. [fast: true, auto-fix: false]
- gochecksumtype # Run exhaustiveness checks on Go "sum types" [fast: false, auto-fix: false]
#- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false]
#- gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
#- godot # Check if comments end in a period [fast: true, auto-fix: true]
#- godox # Tool for detection of FIXME, TODO and other comment keywords [fast: true, auto-fix: false]
#- err113: Go linter to check the errors handling expressions [fast: false, auto-fix: false]
- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: true]
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true]
#- gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true]
- goheader # Checks is file header matches to pattern [fast: true, auto-fix: false]
- goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt. [fast: true, auto-fix: true]
#- mnd: An analyzer to detect magic numbers. [fast: true, auto-fix: false]
#- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
- goheader # Checks is file header matches to pattern [fast: true, auto-fix: true]
- goimports # Check import statements are formatted according to the 'goimport' command. Reformat imports in autofix mode. [fast: true, auto-fix: true]
- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false]
- goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false]
- gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false]
- grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false]
- goprintffuncname # Checks that printf-like functions are named with `f` at the end. [fast: true, auto-fix: false]
- gosec # (gas) Inspects source code for security problems [fast: false, auto-fix: false]
#- gosmopolitan # Report certain i18n/l10n anti-patterns in your Go codebase [fast: false, auto-fix: false]
- grouper # Analyze expression groups. [fast: true, auto-fix: false]
- iface # Detect the incorrect use of interfaces, helping developers avoid interface pollution. [fast: false, auto-fix: false]
- importas # Enforces consistent import aliases [fast: false, auto-fix: false]
#- ireturn # Accept Interfaces, Return Concrete Types [fast: false, auto-fix: false]
#- lll # Reports long lines [fast: true, auto-fix: false]
- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
- inamedparam # reports interfaces with unnamed method parameters [fast: true, auto-fix: false]
- loggercheck # (logrlint) Checks key value pairs for common logger libraries (kitlog,klog,logr,zap). [fast: false, auto-fix: false]
- makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
#- nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
#- nestif # Reports deeply nested if statements [fast: true, auto-fix: false]
- mirror # reports wrong mirror patterns of bytes/strings usage [fast: false, auto-fix: true]
- misspell # Finds commonly misspelled English words [fast: true, auto-fix: true]
- musttag # enforce field tags in (un)marshaled structs [fast: false, auto-fix: false]
#- nakedret # Checks that functions with naked returns are not longer than a maximum size (can be zero). [fast: true, auto-fix: false]
- nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false]
- nilnesserr # Reports constructs that checks for err != nil, but returns a different nil value error.
- nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false]
#- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity [fast: true, auto-fix: false]
- noctx # noctx finds sending http request without context.Context [fast: false, auto-fix: false]
- nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false]
- noctx # Finds sending http request without context.Context [fast: false, auto-fix: false]
- nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: true]
#- nonamedreturns # Reports all named returns [fast: false, auto-fix: false]
- nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL. [fast: true, auto-fix: false]
#- paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test [fast: false, auto-fix: false]
#- prealloc # Finds slice declarations that could potentially be pre-allocated [fast: true, auto-fix: false]
#- paralleltest # Detects missing usage of t.Parallel() method in your Go test [fast: false, auto-fix: false]
- predeclared # find code that shadows one of Go's predeclared identifiers [fast: true, auto-fix: false]
- promlinter # Check Prometheus metrics naming via promlint [fast: true, auto-fix: false]
- reassign # Checks that package variables are not reassigned [fast: false, auto-fix: false]
- recvcheck # checks for receiver type consistency [fast: false, auto-fix: false]
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false]
- rowserrcheck # checks whether Err of rows is checked successfully [fast: false, auto-fix: false]
- sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. [fast: false, auto-fix: false]
- rowserrcheck # checks whether Rows.Err of rows is checked successfully [fast: false, auto-fix: false]
- spancheck # Checks for mistakes with OpenTelemetry/Census spans. [fast: false, auto-fix: false]
- sqlclosecheck # Checks that sql.Rows, sql.Stmt, sqlx.NamedStmt, pgx.Query are closed. [fast: false, auto-fix: false]
- stylecheck # Stylecheck is a replacement for golint [fast: false, auto-fix: false]
#- tagliatelle # Checks the struct tags. [fast: true, auto-fix: false]
- testableexamples # linter checks if examples are testable (have an expected output) [fast: true, auto-fix: false]
- testifylint # Checks usage of github.com/stretchr/testify. [fast: false, auto-fix: false]
#- testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false]
- thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false]
- tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes [fast: false, auto-fix: false]
- thelper # thelper detects tests helpers which is not start with t.Helper() method. [fast: false, auto-fix: false]
- tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes. [fast: false, auto-fix: false]
- unconvert # Remove unnecessary type conversions [fast: false, auto-fix: false]
#- unparam # Reports unused function parameters [fast: false, auto-fix: false]
- usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library. [fast: true, auto-fix: false]
#- varnamelen # checks that the length of a variable's name matches its scope [fast: false, auto-fix: false]
- wastedassign # wastedassign finds wasted assignment statements. [fast: false, auto-fix: false]
- whitespace # Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true]
#- wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false]
#- wsl # Whitespace Linter - Forces you to use empty lines! [fast: true, auto-fix: false]
- usetesting # Reports uses of functions with replacement inside the testing package. [auto-fix]
- wastedassign # Finds wasted assignment statements [fast: false, auto-fix: false]
- whitespace # Whitespace is a linter that checks for unnecessary newlines at the start and end of functions, if, for, etc. [fast: true, auto-fix: true]
## Discouraged linters
#- cyclop # checks function and package cyclomatic complexity [fast: false, auto-fix: false]
#- depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
#- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
#- dupl # Tool for code clone detection [fast: true, auto-fix: false]
#- dupword # checks for duplicate words in the source code [fast: true, auto-fix: false]
#- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) [fast: true, auto-fix: false]
#- err113 # Go linter to check the errors handling expressions [fast: false, auto-fix: false]
#- exhaustruct # Checks if all structure fields are initialized [fast: false, auto-fix: false]
#- funlen # Tool for detection of long functions [fast: true, auto-fix: false]
#- gci # Gci controls Go package import order and makes it always deterministic. [fast: true, auto-fix: true]
#- ginkgolinter # enforces standards of using ginkgo and gomega [fast: false, auto-fix: false]
#- gochecknoglobals # Check that no global variables exist. [fast: false, auto-fix: false]
#- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
#- gocognit # Computes and checks the cognitive complexity of functions [fast: true, auto-fix: false]
#- gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false]
#- godot # Check if comments end in a period [fast: true, auto-fix: true]
#- godox # Tool for detection of comment keywords [fast: true, auto-fix: false]
#- gofumpt # Gofumpt checks whether code was gofumpt-ed. [fast: true, auto-fix: true]
#- interfacebloat # A linter that checks the number of methods inside an interface. [fast: true, auto-fix: false]
#- intrange # (go >= 1.22) intrange is a linter to find places where for loops could make use of an integer range. [fast: true, auto-fix: false]
#- ireturn # Accept Interfaces, Return Concrete Types [fast: false, auto-fix: false]
#- lll # Reports long lines [fast: true, auto-fix: false]
#- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
#- nestif # Reports deeply nested if statements [fast: true, auto-fix: false]
#- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity [fast: true, auto-fix: false]
#- mnd # An analyzer to detect magic numbers. [fast: true, auto-fix: false]
#- perfsprint # Checks that fmt.Sprintf can be replaced with a faster alternative. [fast: false, auto-fix: false]
#- prealloc # Finds slice declarations that could potentially be pre-allocated [fast: true, auto-fix: false]
#- protogetter # Reports direct reads from proto message fields when getters should be used [fast: false, auto-fix: true]
#- sloglint # ensure consistent code style when using log/slog [fast: false, auto-fix: false]
#- tagalign # check that struct tags are well aligned [fast: true, auto-fix: true]
#- tagliatelle # Checks the struct tags. [fast: true, auto-fix: false]
#- unparam # Reports unused function parameters [fast: false, auto-fix: false]
#- varnamelen # checks that the length of a variable's name matches its scope [fast: false, auto-fix: false]
#- wrapcheck # Checks that errors returned from external packages are wrapped [fast: false, auto-fix: false]
#- wsl # add or remove empty lines [fast: true, auto-fix: false]
#- zerologlint # Detects the wrong usage of `zerolog` that a user forgets to dispatch with `Send` or `Msg` [fast: false, auto-fix: false]

View File

@ -1,5 +1,5 @@
# .goreleaser.yml
# Build customization
version: 2
builds:
- binary: gotsrpc
main: ./cmd/gotsrpc/gotsrpc.go
@ -32,7 +32,6 @@ changelog:
use: github-native
brews:
# Reporitory to push the tap to.
- repository:
owner: foomo
name: homebrew-tap

View File

@ -35,7 +35,7 @@ Release downloads:
## How to Contribute
Make a pull request...
Please refer to the [CONTRIBUTING](.gihub/CONTRIBUTING.md) details and follow the [CODE_OF_CONDUCT](.gihub/CODE_OF_CONDUCT.md) and [SECURITY](.github/SECURITY.md) guidelines.
## License

View File

@ -12,7 +12,7 @@ import (
)
const (
HeaderServiceToService = "X-Foomo-S2S"
HeaderServiceToService = "X-Foomo-S2s"
)
// ClientTransport to use for calls

View File

@ -6,20 +6,21 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_newRequest(t *testing.T) {
t.Run("custom headers", func(t *testing.T) {
headers := http.Header{}
headers.Set("test", "test")
headers.Set("Test", "test")
request, err := newRequest(context.Background(), "/test", "text/html", nil, headers)
assert.NoError(t, err)
assert.Equal(t, "test", request.Header.Get("test"))
require.NoError(t, err)
assert.Equal(t, "test", request.Header.Get("Test"))
})
t.Run("default", func(t *testing.T) {
request, err := newRequest(context.Background(), "/test", "text/html", nil, nil)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "/test", request.URL.Path)
assert.Equal(t, "text/html", request.Header.Get("Accept"))
assert.Equal(t, "text/html", request.Header.Get("Content-Type"))

View File

@ -6,6 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const sampleConf = `---
@ -70,13 +71,13 @@ func TestLoadConfig(t *testing.T) {
func TestLoadConfigFile_GomodAbsolute(t *testing.T) {
config, err := LoadConfigFile("testdata/gomod.absolute.yml")
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "/go/src/github.com/foomo/gotsrpc", config.Module.Path)
}
func TestLoadConfigFile_GomodRelative(t *testing.T) {
config, err := LoadConfigFile("testdata/gomod.relative.yml")
assert.NoError(t, err)
require.NoError(t, err)
fmt.Println(config.Module.Path)
assert.True(t, strings.HasSuffix(config.Module.Path, "gotsrpc/config/demo"))
}

View File

@ -34,11 +34,15 @@ func NewError(err error) *Error {
// retrieve error details
errType := reflect.TypeOf(err)
errElem := errType
if errType.Kind() == reflect.Ptr {
errElem = errType.Elem()
}
inst := &Error{
Msg: err.Error(),
Type: errType.String(),
Pkg: errType.Elem().PkgPath(),
Pkg: errElem.PkgPath(),
Data: err,
}
@ -80,9 +84,9 @@ func (e *Error) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%s.(%s)\n", e.Pkg, e.Type)
_, _ = fmt.Fprintf(s, "%s.(%s)\n", e.Pkg, e.Type)
if e.Data != nil {
fmt.Fprintf(s, "Data: %v\n", e.Data)
_, _ = fmt.Fprintf(s, "Data: %v\n", e.Data)
}
}
fallthrough
@ -106,10 +110,14 @@ func (e *Error) Is(err error) bool {
}
errType := reflect.TypeOf(err)
errElem := errType
if errType.Kind() == reflect.Ptr {
errElem = errType.Elem()
}
if e.Msg == err.Error() &&
errType.String() == e.Type &&
errType.Elem().PkgPath() == e.Pkg {
errElem.PkgPath() == e.Pkg {
return true
}

View File

@ -10,6 +10,14 @@ import (
type (
ScalarError string
StructError struct {
Msg string
Map map[string]string
Slice []string
Struct struct {
A string
}
}
CustomError struct {
Msg string
Map map[string]string
@ -33,6 +41,19 @@ func (e *ScalarError) Error() string {
return string(*e)
}
func NewStructError(msg string) StructError {
return StructError{
Msg: msg,
Map: map[string]string{"a": "b"},
Slice: []string{"a", "b"},
Struct: struct{ A string }{A: "b"},
}
}
func (e StructError) Error() string {
return e.Msg
}
func NewCustomError(msg string) *CustomError {
return &CustomError{
Msg: msg,
@ -86,6 +107,10 @@ func (h *Handler) TypedError(w http.ResponseWriter, r *http.Request) (e error) {
return ErrTyped
}
func (h *Handler) StructError(w http.ResponseWriter, r *http.Request) (e error) {
return NewStructError("struct error")
}
func (h *Handler) ScalarError(w http.ResponseWriter, r *http.Request) (e error) {
return NewScalarError(ScalarErrorOne)
}

View File

@ -147,6 +147,28 @@ func call() {
}
}
{
fmt.Println("--- StructError ----------------")
var structErr backend.StructError
var gotsrpcErr *gotsrpc.Error
serviceErr, err := c.StructError(ctx)
if err != nil {
panic("client error should be nil")
} else if serviceErr == nil {
panic("service error should not be nil")
} else if serviceErr != nil {
fmt.Printf("%s\n", serviceErr)
fmt.Printf("%q\n", serviceErr)
fmt.Printf("%+v\n", serviceErr)
}
if errors.As(serviceErr, &gotsrpcErr) {
fmt.Println(gotsrpcErr)
}
if errors.As(serviceErr, &structErr) {
fmt.Println(structErr)
}
}
{
fmt.Println("--- CustomError ----------------")
var customErr *backend.CustomError

View File

@ -17,6 +17,7 @@ const (
ServiceGoTSRPCProxyScalar = "Scalar"
ServiceGoTSRPCProxyScalarError = "ScalarError"
ServiceGoTSRPCProxyStruct = "Struct"
ServiceGoTSRPCProxyStructError = "StructError"
ServiceGoTSRPCProxyTypedCustomError = "TypedCustomError"
ServiceGoTSRPCProxyTypedError = "TypedError"
ServiceGoTSRPCProxyTypedScalarError = "TypedScalarError"
@ -164,6 +165,24 @@ func (p *ServiceGoTSRPCProxy) ServeHTTP(w http.ResponseWriter, r *http.Request)
}
gotsrpc.Monitor(w, r, args, rets, callStats)
return
case ServiceGoTSRPCProxyStructError:
var (
args []interface{}
rets []interface{}
)
executionStart := time.Now()
rw := gotsrpc.ResponseWriter{ResponseWriter: w}
structErrorE := p.service.StructError(&rw, r)
callStats.Execution = time.Since(executionStart)
if rw.Status() == http.StatusOK {
rets = []interface{}{structErrorE}
if err := gotsrpc.Reply(rets, callStats, r, w); err != nil {
gotsrpc.ErrorCouldNotReply(w)
return
}
}
gotsrpc.Monitor(w, r, args, rets, callStats)
return
case ServiceGoTSRPCProxyTypedCustomError:
var (
args []interface{}

View File

@ -17,6 +17,7 @@ type ServiceGoTSRPCClient interface {
Scalar(ctx go_context.Context) (e *ScalarError, clientErr error)
ScalarError(ctx go_context.Context) (e error, clientErr error)
Struct(ctx go_context.Context) (e *StructError, clientErr error)
StructError(ctx go_context.Context) (e error, clientErr error)
TypedCustomError(ctx go_context.Context) (e error, clientErr error)
TypedError(ctx go_context.Context) (e error, clientErr error)
TypedScalarError(ctx go_context.Context) (e error, clientErr error)
@ -105,6 +106,16 @@ func (tsc *HTTPServiceGoTSRPCClient) Struct(ctx go_context.Context) (e *StructEr
return
}
func (tsc *HTTPServiceGoTSRPCClient) StructError(ctx go_context.Context) (e error, clientErr error) {
args := []interface{}{}
reply := []interface{}{&e}
clientErr = tsc.Client.Call(ctx, tsc.URL, tsc.EndPoint, "StructError", args, reply)
if clientErr != nil {
clientErr = pkg_errors.WithMessage(clientErr, "failed to call backend.ServiceGoTSRPCProxy StructError")
}
return
}
func (tsc *HTTPServiceGoTSRPCClient) TypedCustomError(ctx go_context.Context) (e error, clientErr error) {
args := []interface{}{}
reply := []interface{}{&e}

View File

@ -54,6 +54,7 @@ type Service interface {
Scalar(w http.ResponseWriter, r *http.Request) (e *ScalarError)
MultiScalar(w http.ResponseWriter, r *http.Request) (e *MultiScalar)
Struct(w http.ResponseWriter, r *http.Request) (e *StructError)
StructError(w http.ResponseWriter, r *http.Request) (e error)
TypedError(w http.ResponseWriter, r *http.Request) (e error)
ScalarError(w http.ResponseWriter, r *http.Request) (e error)
CustomError(w http.ResponseWriter, r *http.Request) (e error)

14
go.mod
View File

@ -7,12 +7,12 @@ require (
github.com/iancoleman/strcase v0.2.0 // Be aware of https://github.com/iancoleman/strcase/pull/49
github.com/mitchellh/mapstructure v1.5.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_golang v1.21.1
github.com/stretchr/testify v1.10.0
github.com/ugorji/go/codec v1.2.12
github.com/valyala/gorpc v0.0.0-20160519171614-908281bef774
golang.org/x/mod v0.23.0
golang.org/x/tools v0.30.0
golang.org/x/mod v0.24.0
golang.org/x/tools v0.31.0
gopkg.in/yaml.v2 v2.4.0
)
@ -23,10 +23,10 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

32
go.sum
View File

@ -9,8 +9,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -23,12 +23,12 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
@ -39,16 +39,16 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/valyala/gorpc v0.0.0-20160519171614-908281bef774 h1:SUHFQHAaySqF0YHCmmm0EIFooFZpDPpi5KTom7YJ07c=
github.com/valyala/gorpc v0.0.0-20160519171614-908281bef774/go.mod h1:8uNqM1i7pr0jO7gdvbNCgsSa8Ki2vMh7JCQxO9BlF90=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -120,7 +120,7 @@ func Reply(response []interface{}, stats *CallStats, r *http.Request, w http.Res
if len(response) > 0 {
errResp := response[len(response)-1]
if v, ok := errResp.(error); ok && v != nil {
if !reflect.ValueOf(v).IsNil() {
if !reflect.ValueOf(v).IsZero() {
stats.ErrorCode = 1
stats.ErrorType = fmt.Sprintf("%T", v)
stats.ErrorMessage = v.Error()

View File

@ -33,7 +33,7 @@ var msgpackClientHandle = &clientHandle{
beforeEncodeReply: func(resp *[]interface{}) error {
for k, v := range *resp {
if e, ok := v.(error); ok {
if r := reflect.ValueOf(e); !r.IsNil() {
if r := reflect.ValueOf(e); !r.IsZero() {
(*resp)[k] = NewError(e)
}
}
@ -43,7 +43,11 @@ var msgpackClientHandle = &clientHandle{
beforeDecodeReply: func(reply []interface{}) ([]interface{}, error) {
ret := make([]interface{}, len(reply))
for k, v := range reply {
if reflect.TypeOf(v).Elem().Implements(errorType) {
val := reflect.TypeOf(v)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Implements(errorType) {
var e *Error
ret[k] = e
} else {