From 3f42f2ed014200fdfd4fe1c1c05c9dc8c6809054 Mon Sep 17 00:00:00 2001 From: "Caesar M. Tsai" Date: Tue, 31 Dec 2024 15:36:49 +0800 Subject: [PATCH 01/11] feat: Encode function can optimize byte array handling (#42) In scenarios where byte array JSON messages are forwarded (e.g., from MQ), the previous approach required unmarshalling into an object before encoding for SSE. The updated logic allows []byte to be passed directly, simplifying message forwarding and reducing unnecessary conversions. // before byteData := messageFromMQ() data := make(map[string]any) json.Unmarshal(byteData, &data) sse.Encode(new(bytes.Buffer), sse.Event{ Data: data, }) // after byteData := messageFromMQ() sse.Encode(new(bytes.Buffer), sse.Event{ Data: byteData, }) --- sse-encoder.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sse-encoder.go b/sse-encoder.go index 3761b0d..0d26c82 100644 --- a/sse-encoder.go +++ b/sse-encoder.go @@ -72,6 +72,14 @@ func writeRetry(w stringWriter, retry uint) { func writeData(w stringWriter, data interface{}) error { w.WriteString("data:") + + bData, ok := data.([]byte) + if ok { + dataReplacer.WriteString(w, string(bData)) + w.WriteString("\n\n") + return nil + } + switch kindOfData(data) { case reflect.Struct, reflect.Slice, reflect.Map: err := json.NewEncoder(w).Encode(data) From 744c7182dd69da61c0a9a0f30d9604c662569be4 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 31 Dec 2024 15:38:12 +0800 Subject: [PATCH 02/11] chore: update dependencies and improve test configurations - Update `testify` dependency from version `1.8.0` to `1.10.0` in `go.mod` Signed-off-by: Bo-Yi Wu --- go.mod | 2 +- go.sum | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 7f65e28..e090522 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/gin-contrib/sse go 1.13 -require github.com/stretchr/testify v1.8.0 +require github.com/stretchr/testify v1.10.0 diff --git a/go.sum b/go.sum index 5164829..3ebac7b 100644 --- a/go.sum +++ b/go.sum @@ -5,9 +5,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From de96a1faf5a4054a31a50b5bd1571f7a48ce8a5e Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 31 Dec 2024 15:39:25 +0800 Subject: [PATCH 03/11] ci: add and enhance CI workflows for Go projects and code analysis - Remove Dependabot configuration file - Add CodeQL analysis workflow for code scanning - Add CodeQL workflow with scheduled runs and matrix configuration for Go language - Rename Go workflow to "Run Tests" - Update Go workflow branches configuration - Upgrade actions and tools versions in Go workflow - Expand Go workflow matrix to include multiple OS and Go versions - Add GoReleaser workflow for automated releases Signed-off-by: Bo-Yi Wu --- .github/dependabot.yml | 5 -- .github/workflows/codeql-analysis.yml | 71 +++++++++++++++++++++++ .github/workflows/codeql.yml | 54 ++++++++++++++++++ .github/workflows/go.yml | 81 +++++++++++++++------------ .github/workflows/goreleaser.yml | 33 +++++++++++ 5 files changed, 204 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/goreleaser.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 827f529..632e8eb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,3 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - version: 2 updates: - package-ecosystem: github-actions diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..f9979e2 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,71 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [master] + pull_request: + # The branches below must be a subset of the branches above + branches: [master] + schedule: + - cron: "37 2 * * 5" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["go"] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..f3ceec8 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,54 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [master] + pull_request: + # The branches below must be a subset of the branches above + branches: [master] + schedule: + - cron: "41 23 * * 6" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["go"] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 336a519..6e074d8 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -1,55 +1,66 @@ -name: Go +name: Run Tests on: push: - branches: [ master ] + branches: + - master pull_request: - branches: [ master ] + branches: + - master jobs: lint: runs-on: ubuntu-latest steps: - name: Setup go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: 1.16 + go-version: "^1" - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup golangci-lint - uses: golangci/golangci-lint-action@v3.2.0 + uses: golangci/golangci-lint-action@v6 with: - version: v1.41.1 - args: --verbose - build: - runs-on: ubuntu-latest + args: --verbose + test: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + go: [1.21, 1.22, 1.23] + include: + - os: ubuntu-latest + go-build: ~/.cache/go-build + - os: macos-latest + go-build: ~/Library/Caches/go-build + name: ${{ matrix.os }} @ Go ${{ matrix.go }} + runs-on: ${{ matrix.os }} env: GO111MODULE: on - strategy: - matrix: - go-version: [1.13, 1.14, 1.15, 1.16, 1.17] + GOPROXY: https://proxy.golang.org steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3.2.5 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- + - name: Set up Go ${{ matrix.go }} + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go }} - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: ${{ matrix.go-version }} + - name: Checkout Code + uses: actions/checkout@v4 + with: + ref: ${{ github.ref }} - - name: Build - run: go build -v ./... + - uses: actions/cache@v4 + with: + path: | + ${{ matrix.go-build }} + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Run Tests + run: | + go test -v -covermode=atomic -coverprofile=coverage.out - - name: Test - run: go test -race -v -count=1 -coverprofile=coverage.out ./... - - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - flags: go-${{ matrix.go-version }} + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.os }},go-${{ matrix.go }} diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml new file mode 100644 index 0000000..b00b7a0 --- /dev/null +++ b/.github/workflows/goreleaser.yml @@ -0,0 +1,33 @@ +name: Goreleaser + +on: + push: + tags: + - "*" + +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + check-latest: true + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + # either 'goreleaser' (default) or 'goreleaser-pro' + distribution: goreleaser + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From cffc294e1b315e34116f0a19101122e0448c56f2 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 31 Dec 2024 15:41:35 +0800 Subject: [PATCH 04/11] docs: improve test coverage and update CI configurations - Update badge text from "Build Status" to "Run Tests" - Change code block language from unspecified to `sh` Signed-off-by: Bo-Yi Wu --- README.md | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index cebe482..cfe2c82 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Server-Sent Events [![Go Reference](https://pkg.go.dev/badge/github.com/gin-contrib/sse.svg)](https://pkg.go.dev/github.com/gin-contrib/sse) -[![Build Status](https://github.com/gin-contrib/sse/actions/workflows/go.yml/badge.svg)](https://github.com/gin-contrib/sse/actions/workflows/go.yml) +[![Run Tests](https://github.com/gin-contrib/sse/actions/workflows/go.yml/badge.svg)](https://github.com/gin-contrib/sse/actions/workflows/go.yml) [![codecov](https://codecov.io/gh/gin-contrib/sse/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sse) [![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sse)](https://goreportcard.com/report/github.com/gin-contrib/sse) @@ -16,32 +16,33 @@ Server-sent events (SSE) is a technology where a browser receives automatic upda import "github.com/gin-contrib/sse" func httpHandler(w http.ResponseWriter, req *http.Request) { - // data can be a primitive like a string, an integer or a float - sse.Encode(w, sse.Event{ - Event: "message", - Data: "some data\nmore data", - }) + // data can be a primitive like a string, an integer or a float + sse.Encode(w, sse.Event{ + Event: "message", + Data: "some data\nmore data", + }) - // also a complex type, like a map, a struct or a slice - sse.Encode(w, sse.Event{ - Id: "124", - Event: "message", - Data: map[string]interface{}{ - "user": "manu", - "date": time.Now().Unix(), - "content": "hi!", - }, - }) + // also a complex type, like a map, a struct or a slice + sse.Encode(w, sse.Event{ + Id: "124", + Event: "message", + Data: map[string]interface{}{ + "user": "manu", + "date": time.Now().Unix(), + "content": "hi!", + }, + }) } ``` -``` + +```sh event: message data: some data\\nmore data id: 124 event: message data: {"content":"hi!","date":1431540810,"user":"manu"} - + ``` ## Content-Type @@ -49,7 +50,8 @@ data: {"content":"hi!","date":1431540810,"user":"manu"} ```go fmt.Println(sse.ContentType) ``` -``` + +```sh text/event-stream ``` From 59293461664ec000d19768fd8f319d37fb407d17 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 31 Dec 2024 15:42:39 +0800 Subject: [PATCH 05/11] ci: update GitHub workflows and improve test configurations - Update Codecov action from version `v4` to `v5` in GitHub workflow Signed-off-by: Bo-Yi Wu --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6e074d8..6c25889 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -61,6 +61,6 @@ jobs: go test -v -covermode=atomic -coverprofile=coverage.out - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: flags: ${{ matrix.os }},go-${{ matrix.go }} From f8a6bb093d80707b5fd0db9340903bd5140fa851 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 31 Dec 2024 15:44:08 +0800 Subject: [PATCH 06/11] build: configure release process and changelog management - Add `.goreleaser.yaml` configuration file - Skip build process for library projects - Configure changelog to use GitHub with categorized groups for features, bug fixes, enhancements, refactors, build process updates, documentation updates, and others Signed-off-by: Bo-Yi Wu --- .goreleaser.yaml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .goreleaser.yaml diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..4c910ad --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,29 @@ +builds: + - # If true, skip the build. + # Useful for library projects. + # Default is false + skip: true + +changelog: + use: github + groups: + - title: Features + regexp: "^.*feat[(\\w)]*:+.*$" + order: 0 + - title: "Bug fixes" + regexp: "^.*fix[(\\w)]*:+.*$" + order: 1 + - title: "Enhancements" + regexp: "^.*chore[(\\w)]*:+.*$" + order: 2 + - title: "Refactor" + regexp: "^.*refactor[(\\w)]*:+.*$" + order: 3 + - title: "Build process updates" + regexp: ^.*?(build|ci)(\(.+\))??!?:.+$ + order: 4 + - title: "Documentation updates" + regexp: ^.*?docs?(\(.+\))??!?:.+$ + order: 4 + - title: Others + order: 999 From b0e321a937f720938d451c689c10a34d91fb93e9 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 31 Dec 2024 15:45:48 +0800 Subject: [PATCH 07/11] ci: refactor GitHub Actions workflows for improved efficiency - Add a GitHub Actions workflow for Bearer PR Check - Add Bearer action to Go workflow - Remove macOS from Go workflow operating systems - Remove redundant checkout step from Go workflow Signed-off-by: Bo-Yi Wu --- .github/workflows/bearer.yml | 35 ++++++++++++++++++++++++++++++++ .github/workflows/go.yml | 16 ++++++++++----- .github/workflows/goreleaser.yml | 1 + 3 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/bearer.yml diff --git a/.github/workflows/bearer.yml b/.github/workflows/bearer.yml new file mode 100644 index 0000000..8dd39ab --- /dev/null +++ b/.github/workflows/bearer.yml @@ -0,0 +1,35 @@ +name: Bearer PR Check + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + pull-requests: write + +jobs: + rule_check: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - uses: reviewdog/action-setup@v1 + with: + reviewdog_version: latest + + - name: Run Report + id: report + uses: bearer/bearer-action@v2 + with: + format: rdjson + output: rd.json + diff: true + + - name: Run reviewdog + if: always() + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cat rd.json | reviewdog -f=rdjson -reporter=github-pr-review diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 6c25889..45b698f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -12,26 +12,32 @@ jobs: lint: runs-on: ubuntu-latest steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup go uses: actions/setup-go@v5 with: go-version: "^1" - - name: Checkout repository - uses: actions/checkout@v4 + - name: Setup golangci-lint uses: golangci/golangci-lint-action@v6 with: args: --verbose + + - name: Bearer + uses: bearer/bearer-action@v2 + with: + diff: true + test: strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest] go: [1.21, 1.22, 1.23] include: - os: ubuntu-latest go-build: ~/.cache/go-build - - os: macos-latest - go-build: ~/Library/Caches/go-build name: ${{ matrix.os }} @ Go ${{ matrix.go }} runs-on: ${{ matrix.os }} env: diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index b00b7a0..ddf1036 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -22,6 +22,7 @@ jobs: with: go-version-file: go.mod check-latest: true + - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: From b4b7d1b5c1fc3f188fecd6456b7aa5686685dfbe Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Wed, 12 Feb 2025 09:42:10 +0800 Subject: [PATCH 08/11] ci: update GitHub Actions and improve test configurations - Add Go version 1.24 to the GitHub Actions workflow Signed-off-by: Bo-Yi Wu --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 45b698f..e71b3e9 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -34,7 +34,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - go: [1.21, 1.22, 1.23] + go: [1.21, 1.22, 1.23, 1.24] include: - os: ubuntu-latest go-build: ~/.cache/go-build From 47d15604054cab2282581f35131c51dde9f392af Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 8 Apr 2025 08:31:24 +0800 Subject: [PATCH 09/11] chore: update Go version to 1.23 and adjust dependencies accordingly - Remove support for Go versions 1.21 and 1.22 in the GitHub workflow - Update Go version to 1.23 in go.mod - Add indirect dependencies: go-spew, go-difflib, and yaml.v3 in go.mod Signed-off-by: Bo-Yi Wu --- .github/workflows/go.yml | 2 +- go.mod | 8 +++++++- go.sum | 9 --------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index e71b3e9..47cf1f5 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -34,7 +34,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - go: [1.21, 1.22, 1.23, 1.24] + go: [1.23, 1.24] include: - os: ubuntu-latest go-build: ~/.cache/go-build diff --git a/go.mod b/go.mod index e090522..42b87bd 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,11 @@ module github.com/gin-contrib/sse -go 1.13 +go 1.23 require github.com/stretchr/testify v1.10.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index 3ebac7b..713a0b4 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,10 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From c719ab6b536bc0fdc42eb41a579b8cf1f8f4bbad Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 8 Apr 2025 08:38:00 +0800 Subject: [PATCH 10/11] chore: improve linting and error handling across the codebase - Update golangci-lint-action to version 7 in GitHub workflow - Specify version 2.0 for golangci-lint-action in GitHub workflow - Set golangci-lint configuration version to "2" - Enable specific linters and disable default linters in golangci configuration - Add exclusions and formatters configurations in golangci configuration - Replace deprecated `ioutil.ReadAll` with `io.ReadAll` in sse-decoder.go - Use grouped variable declaration for `contentType` and `noCache` in sse-encoder.go - Add error handling for `WriteString` operations in sse-encoder.go - Add `nolint:exhaustive` comment for `kindOfData` switch statement in sse-encoder.go - Adjust test assertions for better readability in sse_test.go - Add error handling for `Encode` function calls in tests and benchmarks Signed-off-by: Bo-Yi Wu --- .github/workflows/go.yml | 3 ++- .golangci.yml | 49 +++++++++++++++++++++++++++++++++++++++- sse-decoder.go | 11 +++++---- sse-encoder.go | 38 ++++++++++++++++--------------- sse_test.go | 19 +++++++++------- 5 files changed, 87 insertions(+), 33 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 47cf1f5..0b14dbe 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -21,8 +21,9 @@ jobs: go-version: "^1" - name: Setup golangci-lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v7 with: + version: v2.0 args: --verbose - name: Bearer diff --git a/.golangci.yml b/.golangci.yml index 4c44c5f..47094ac 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,50 @@ +version: "2" linters: - disable: + default: none + enable: + - bodyclose + - dogsled + - dupl - errcheck + - exhaustive + - gochecknoinits + - goconst + - gocritic + - gocyclo + - goprintffuncname + - gosec + - govet + - ineffassign + - lll + - misspell + - nakedret + - noctx + - nolintlint + - rowserrcheck + - staticcheck + - unconvert + - unparam + - unused + - whitespace + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - gofumpt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/sse-decoder.go b/sse-decoder.go index fd49b9c..8ca065b 100644 --- a/sse-decoder.go +++ b/sse-decoder.go @@ -7,7 +7,6 @@ package sse import ( "bytes" "io" - "io/ioutil" ) type decoder struct { @@ -22,7 +21,8 @@ func Decode(r io.Reader) ([]Event, error) { func (d *decoder) dispatchEvent(event Event, data string) { dataLength := len(data) if dataLength > 0 { - //If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer. + // If the data buffer's last character is a U+000A LINE FEED (LF) character, + // then remove the last character from the data buffer. data = data[:dataLength-1] dataLength-- } @@ -37,7 +37,7 @@ func (d *decoder) dispatchEvent(event Event, data string) { } func (d *decoder) decode(r io.Reader) ([]Event, error) { - buf, err := ioutil.ReadAll(r) + buf, err := io.ReadAll(r) if err != nil { return nil, err } @@ -96,7 +96,8 @@ func (d *decoder) decode(r io.Reader) ([]Event, error) { currentEvent.Id = string(value) case "retry": // If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), - // then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer. + // then interpret the field value as an integer in base ten, and set the event stream's + // reconnection time to that integer. // Otherwise, ignore the field. currentEvent.Id = string(value) case "data": @@ -105,7 +106,7 @@ func (d *decoder) decode(r io.Reader) ([]Event, error) { // then append a single U+000A LINE FEED (LF) character to the data buffer. dataBuffer.WriteString("\n") default: - //Otherwise. The field is ignored. + // Otherwise. The field is ignored. continue } } diff --git a/sse-encoder.go b/sse-encoder.go index 0d26c82..9ebb49f 100644 --- a/sse-encoder.go +++ b/sse-encoder.go @@ -20,8 +20,10 @@ import ( const ContentType = "text/event-stream;charset=utf-8" -var contentType = []string{ContentType} -var noCache = []string{"no-cache"} +var ( + contentType = []string{ContentType} + noCache = []string{"no-cache"} +) var fieldReplacer = strings.NewReplacer( "\n", "\\n", @@ -48,48 +50,48 @@ func Encode(writer io.Writer, event Event) error { func writeId(w stringWriter, id string) { if len(id) > 0 { - w.WriteString("id:") - fieldReplacer.WriteString(w, id) - w.WriteString("\n") + _, _ = w.WriteString("id:") + _, _ = fieldReplacer.WriteString(w, id) + _, _ = w.WriteString("\n") } } func writeEvent(w stringWriter, event string) { if len(event) > 0 { - w.WriteString("event:") - fieldReplacer.WriteString(w, event) - w.WriteString("\n") + _, _ = w.WriteString("event:") + _, _ = fieldReplacer.WriteString(w, event) + _, _ = w.WriteString("\n") } } func writeRetry(w stringWriter, retry uint) { if retry > 0 { - w.WriteString("retry:") - w.WriteString(strconv.FormatUint(uint64(retry), 10)) - w.WriteString("\n") + _, _ = w.WriteString("retry:") + _, _ = w.WriteString(strconv.FormatUint(uint64(retry), 10)) + _, _ = w.WriteString("\n") } } func writeData(w stringWriter, data interface{}) error { - w.WriteString("data:") + _, _ = w.WriteString("data:") bData, ok := data.([]byte) if ok { - dataReplacer.WriteString(w, string(bData)) - w.WriteString("\n\n") + _, _ = dataReplacer.WriteString(w, string(bData)) + _, _ = w.WriteString("\n\n") return nil } - switch kindOfData(data) { + switch kindOfData(data) { //nolint:exhaustive case reflect.Struct, reflect.Slice, reflect.Map: err := json.NewEncoder(w).Encode(data) if err != nil { return err } - w.WriteString("\n") + _, _ = w.WriteString("\n") default: - dataReplacer.WriteString(w, fmt.Sprint(data)) - w.WriteString("\n\n") + _, _ = dataReplacer.WriteString(w, fmt.Sprint(data)) + _, _ = w.WriteString("\n\n") } return nil } diff --git a/sse_test.go b/sse_test.go index 553ba29..6df102d 100644 --- a/sse_test.go +++ b/sse_test.go @@ -170,22 +170,25 @@ func TestEncodeFloat(t *testing.T) { func TestEncodeStream(t *testing.T) { w := new(bytes.Buffer) - Encode(w, Event{ + _ = Encode(w, Event{ Event: "float", Data: 1.5, }) - Encode(w, Event{ + _ = Encode(w, Event{ Id: "123", Data: map[string]interface{}{"foo": "bar", "bar": "foo"}, }) - Encode(w, Event{ + _ = Encode(w, Event{ Id: "124", Event: "chat", Data: "hi! dude", }) - assert.Equal(t, w.String(), "event:float\ndata:1.5\n\nid:123\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\nid:124\nevent:chat\ndata:hi! dude\n\n") + assert.Equal(t, w.String(), + "event:float\ndata:1.5\n\n"+ + "id:123\ndata:{\"bar\":\"foo\",\"foo\":\"bar\"}\n\n"+ + "id:124\nevent:chat\ndata:hi! dude\n\n") } func TestRenderSSE(t *testing.T) { @@ -207,7 +210,7 @@ func BenchmarkResponseWriter(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - (Event{ + _ = (Event{ Event: "new_message", Data: "hi! how are you? I am fine. this is a long stupid message!!!", }).Render(w) @@ -219,7 +222,7 @@ func BenchmarkFullSSE(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - Encode(buf, Event{ + _ = Encode(buf, Event{ Event: "new_message", Id: "13435", Retry: 10, @@ -234,7 +237,7 @@ func BenchmarkNoRetrySSE(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - Encode(buf, Event{ + _ = Encode(buf, Event{ Event: "new_message", Id: "13435", Data: "hi! how are you? I am fine. this is a long stupid message!!!", @@ -248,7 +251,7 @@ func BenchmarkSimpleSSE(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - Encode(buf, Event{ + _ = Encode(buf, Event{ Event: "new_message", Data: "hi! how are you? I am fine. this is a long stupid message!!!", }) From 92464755282db4dd120d064c6dd8f7f433fe3db8 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 8 Apr 2025 08:39:14 +0800 Subject: [PATCH 11/11] refactor: refactor codebase for improved performance and maintainability - Simplify variable initialization in `decode` method - Correct method call in `WriteString` function Signed-off-by: Bo-Yi Wu --- sse-decoder.go | 2 +- writer.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sse-decoder.go b/sse-decoder.go index 8ca065b..da2c2d4 100644 --- a/sse-decoder.go +++ b/sse-decoder.go @@ -43,7 +43,7 @@ func (d *decoder) decode(r io.Reader) ([]Event, error) { } var currentEvent Event - var dataBuffer *bytes.Buffer = new(bytes.Buffer) + dataBuffer := new(bytes.Buffer) // TODO (and unit tests) // Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair, // a single U+000A LINE FEED (LF) character, diff --git a/writer.go b/writer.go index 6f9806c..724d9d0 100644 --- a/writer.go +++ b/writer.go @@ -12,7 +12,7 @@ type stringWrapper struct { } func (w stringWrapper) WriteString(str string) (int, error) { - return w.Writer.Write([]byte(str)) + return w.Write([]byte(str)) } func checkWriter(writer io.Writer) stringWriter {