From a29f85833c8972f0c7c35dcaada1ef05552bb16b Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 11 Apr 2024 18:58:13 +0800 Subject: [PATCH] fix lint issues and move net/dial files to net (#31) --- .github/workflows/golangci-lint.yml | 41 ++++++++ .golangci.yml | 136 +++++++++++++++++++++++++ control/limit/limiter.go | 11 +- crypto/crypto_test.go | 7 +- crypto/encode.go | 4 +- errors/errors.go | 2 +- io/io.go | 7 +- io/io_test.go | 17 +++- log/global.go | 28 +++-- log/log.go | 38 ++++--- log/log_test.go | 16 +++ log/output_console_test.go | 3 +- log/output_rotatefile.go | 24 +++-- log/output_rotatefile_test.go | 3 +- msg/json/msg.go | 4 +- msg/json/pack.go | 6 +- msg/json/pack_test.go | 24 ++--- msg/json/process_test.go | 5 +- net/{dial => }/dial.go | 12 +-- net/{dial/option.go => dial_option.go} | 43 ++------ net/{dial => }/dial_test.go | 2 +- net/mux/mux.go | 24 ++--- net/mux/mux_test.go | 52 ++++------ net/mux/rule.go | 40 ++++---- net/{dial => }/util.go | 2 +- net/{dial => }/util_test.go | 2 +- pool/buf.go | 45 ++++++-- pool/buf_test.go | 28 +++-- pool/snappy.go | 6 +- 29 files changed, 417 insertions(+), 215 deletions(-) create mode 100644 .github/workflows/golangci-lint.yml create mode 100644 .golangci.yml rename net/{dial => }/dial.go (92%) rename net/{dial/option.go => dial_option.go} (90%) rename net/{dial => }/dial_test.go (98%) rename net/{dial => }/util.go (96%) rename net/{dial => }/util_test.go (99%) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 0000000..1ff39e1 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,41 @@ +name: golangci-lint +on: + push: + branches: + - master + pull_request: +permissions: + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + pull-requests: read +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: '1.22' + cache: false + - name: golangci-lint + uses: golangci/golangci-lint-action@v4 + with: + # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version + version: v1.57 + + # Optional: golangci-lint command line arguments. + # args: --issues-exit-code=0 + + # Optional: show only new issues if it's a pull request. The default value is `false`. + # only-new-issues: true + + # Optional: if set to true then the all caching functionality will be complete disabled, + # takes precedence over all other caching options. + # skip-cache: true + + # Optional: if set to true then the action don't cache or restore ~/go/pkg. + # skip-pkg-cache: true + + # Optional: if set to true then the action don't cache or restore ~/.cache/go-build. + # skip-build-cache: true diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..fc26e9b --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,136 @@ +service: + golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly + +run: + concurrency: 4 + # timeout for analysis, e.g. 30s, 5m, default is 1m + deadline: 20m + build-tags: + - integ + - integfuzz + +linters: + disable-all: true + enable: + - unused + - errcheck + - exportloopref + - gocritic + - gofumpt + - goimports + - revive + - gosimple + - govet + - ineffassign + - lll + - misspell + - staticcheck + - stylecheck + - typecheck + - unconvert + - unparam + - gci + - gosec + - asciicheck + - prealloc + - predeclared + - makezero + fast: false + +linters-settings: + errcheck: + # report about not checking of errors in type assetions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: false + + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: false + govet: + # report about shadowed variables + check-shadowing: false + maligned: + # print struct with more effective memory layout or not, false by default + suggest-new: true + misspell: + # Correct spellings using locale preferences for US or UK. + # Default is to use a neutral variety of English. + # Setting locale to US will correct the British spelling of 'colour' to 'color'. + locale: US + ignore-words: + - cancelled + - marshalled + lll: + # max line length, lines longer will be reported. Default is 120. + # '\t' is counted as 1 character by default, and can be changed with the tab-width option + line-length: 160 + # tab width in spaces. Default to 1. + tab-width: 1 + gocritic: + disabled-checks: + - exitAfterDefer + unused: + check-exported: false + unparam: + # Inspect exported functions, default is false. Set to true if no external program/library imports your code. + # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find external interfaces. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + gci: + sections: + - standard + - default + - prefix(github.com/fatedier/golib/) + gosec: + severity: "low" + confidence: "low" + excludes: + - G505 + +issues: + # List of regexps of issue texts to exclude, empty list by default. + # But independently from this option we use default exclude patterns, + # it can be disabled by `exclude-use-default: false`. To list all + # excluded by default patterns execute `golangci-lint run --help` + # exclude: + # - composite literal uses unkeyed fields + + exclude-rules: + # Exclude some linters from running on test files. + - path: _test\.go$|^tests/|^samples/ + linters: + - errcheck + - maligned + - linters: + - revive + text: "unused-parameter" + - linters: + - unparam + text: "is always" + - linters: + - staticcheck + text: "SA6002" + - linters: + - staticcheck + text: "snappy.NewWriter is deprecated" + + exclude-dirs: + - genfiles$ + - vendor$ + - bin$ + exclude-files: + - ".*\\.pb\\.go" + - ".*\\.gen\\.go" + + # Independently from option `exclude` we use default exclude patterns, + # it can be disabled by this option. To list all + # excluded by default patterns execute `golangci-lint run --help`. + # Default value for this option is true. + exclude-use-default: true + + # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + max-per-linter: 0 + + # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. + max-same-issues: 0 diff --git a/control/limit/limiter.go b/control/limit/limiter.go index 3e8ef3e..ae03f6d 100644 --- a/control/limit/limiter.go +++ b/control/limit/limiter.go @@ -95,11 +95,9 @@ func (l *Limiter) Acquire(timeout time.Duration) (err error) { if timeout == 0 { // no timeout limit - select { - case _, ok := <-l.poolCh: - if !ok { - err = ErrClosed - } + _, ok := <-l.poolCh + if !ok { + err = ErrClosed } } else { select { @@ -121,11 +119,10 @@ func (l *Limiter) Release() { }); err != nil { atomic.AddInt64(&l.current, -1) } - } func (l *Limiter) SetLimit(num int64) { - gerr.PanicToError(func() { + _ = gerr.PanicToError(func() { l.limitCh <- num }) } diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 0e3a60c..16b4666 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -25,7 +25,10 @@ import ( func TestCryptoWriterAndReader(t *testing.T) { assert := assert.New(t) - text := "1234567890abcdefghigklmnopqrstuvwxyzeeeeeeeeeeeeeeeeeeeeeewwwwwwwwwwwwwwwwwwwwwwwwwwzzzzzzzzzzzzzzzzzzzzzzzzdddddddddddddddddddddddddddddddddddddrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrllllllllllllllllllllllllllllllllllqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeewwwwwwwwwwwwwwwwwwwwww" + text := "1234567890abcdefghigklmnopqrstuvwxyzeeeeeeeeeeeeeeeeeeeeeewwwwwwwwwwwwwwwwwwwwwwwwww" + + "zzzzzzzzzzzzzzzzzzzzzzzzdddddddddddddddddddddddddddddddddddddrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr" + + "llllllllllllllllllllllllllllllllllqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" + + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeewwwwwwwwwwwwwwwwwwwwww" key := "123456" buffer := bytes.NewBuffer(nil) @@ -37,7 +40,7 @@ func TestCryptoWriterAndReader(t *testing.T) { c := bytes.NewBuffer(nil) io.Copy(c, decReader) - assert.Equal(text, string(c.Bytes())) + assert.Equal(text, c.String()) } func TestCryptoEncodeAndDecode(t *testing.T) { diff --git a/crypto/encode.go b/crypto/encode.go index f93cfe5..b10c5f9 100644 --- a/crypto/encode.go +++ b/crypto/encode.go @@ -24,9 +24,7 @@ import ( "golang.org/x/crypto/pbkdf2" ) -var ( - DefaultSalt = "crypto" -) +var DefaultSalt = "crypto" // NewWriter returns a new Writer that encrypts bytes to w. func NewWriter(w io.Writer, key []byte) (*Writer, error) { diff --git a/errors/errors.go b/errors/errors.go index d818ef3..b71983a 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -21,7 +21,7 @@ import ( func PanicToError(fn func()) (err error) { defer func() { if r := recover(); r != nil { - err = fmt.Errorf("Panic error: %v", r) + err = fmt.Errorf("panic error: %v", r) } }() diff --git a/io/io.go b/io/io.go index dc5fcc9..aec318a 100644 --- a/io/io.go +++ b/io/io.go @@ -18,9 +18,10 @@ import ( "io" "sync" + "github.com/golang/snappy" + "github.com/fatedier/golib/crypto" "github.com/fatedier/golib/pool" - "github.com/golang/snappy" ) // Join two io.ReadWriteCloser and do some operations. @@ -64,8 +65,8 @@ func WithCompression(rwc io.ReadWriteCloser) io.ReadWriteCloser { sr := snappy.NewReader(rwc) sw := snappy.NewWriter(rwc) return WrapReadWriteCloser(sr, sw, func() error { - err := rwc.Close() - return err + _ = sw.Close() + return rwc.Close() }) } diff --git a/io/io_test.go b/io/io_test.go index f12b651..55bec82 100644 --- a/io/io_test.go +++ b/io/io_test.go @@ -28,8 +28,10 @@ func TestJoin(t *testing.T) { n int err error ) - text1 := "A document that gives tips for writing clear, idiomatic Go code. A must read for any new Go programmer. It augments the tour and the language specification, both of which should be read first." - text2 := "A document that specifies the conditions under which reads of a variable in one goroutine can be guaranteed to observe values produced by writes to the same variable in a different goroutine." + text1 := "A document that gives tips for writing clear, idiomatic Go code. A must read for any new Go programmer." + + " It augments the tour and the language specification, both of which should be read first." + text2 := "A document that specifies the conditions under which reads of a variable in one goroutine can be guaranteed" + + " to observe values produced by writes to the same variable in a different goroutine." // Forward bytes directly. pr, pw := io.Pipe() @@ -104,8 +106,13 @@ func TestWithEncryption(t *testing.T) { n int err error ) - text1 := "Go is expressive, concise, clean, and efficient. Its concurrency mechanisms make it easy to write programs that get the most out of multicore and networked machines, while its novel type system enables flexible and modular program construction. Go compiles quickly to machine code yet has the convenience of garbage collection and the power of run-time reflection. It's a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language." - text2 := "An interactive introduction to Go in three sections. The first section covers basic syntax and data structures; the second discusses methods and interfaces; and the third introduces Go's concurrency primitives. Each section concludes with a few exercises so you can practice what you've learned. You can take the tour online or install it locally with" + text1 := "Go is expressive, concise, clean, and efficient. Its concurrency mechanisms make it easy to write programs" + + "that get the most out of multicore and networked machines, while its novel type system enables flexible and modular program construction." + + " Go compiles quickly to machine code yet has the convenience of garbage collection and the power of run-time reflection." + + " It's a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language." + text2 := "An interactive introduction to Go in three sections. The first section covers basic syntax and data structures; " + + "the second discusses methods and interfaces; and the third introduces Go's concurrency primitives." + + " Each section concludes with a few exercises so you can practice what you've learned. You can take the tour online or install it locally with" key := "authkey" // Forward enrypted bytes. @@ -140,6 +147,6 @@ func TestWithEncryption(t *testing.T) { assert.NoError(err) assert.Equal(text1, string(buf[:n])) - n, err = conn1.Read(buf) + _, err = conn1.Read(buf) assert.NoError(err) } diff --git a/log/global.go b/log/global.go index e3019c5..8ba2841 100644 --- a/log/global.go +++ b/log/global.go @@ -3,41 +3,49 @@ package log var DefaultLogger = New() func Trace(args ...interface{}) { - DefaultLogger.log(TraceLevel, "", args...) + DefaultLogger.log(TraceLevel, 0, "", args...) } func Debug(args ...interface{}) { - DefaultLogger.log(DebugLevel, "", args...) + DefaultLogger.log(DebugLevel, 0, "", args...) } func Info(args ...interface{}) { - DefaultLogger.log(InfoLevel, "", args...) + DefaultLogger.log(InfoLevel, 0, "", args...) } func Warn(args ...interface{}) { - DefaultLogger.log(WarnLevel, "", args...) + DefaultLogger.log(WarnLevel, 0, "", args...) } func Error(args ...interface{}) { - DefaultLogger.log(ErrorLevel, "", args...) + DefaultLogger.log(ErrorLevel, 0, "", args...) +} + +func Log(level Level, offset int, args ...interface{}) { + DefaultLogger.log(level, offset, "", args...) } func Tracef(msg string, args ...interface{}) { - DefaultLogger.log(TraceLevel, msg, args...) + DefaultLogger.log(TraceLevel, 0, msg, args...) } func Debugf(msg string, args ...interface{}) { - DefaultLogger.log(DebugLevel, msg, args...) + DefaultLogger.log(DebugLevel, 0, msg, args...) } func Infof(msg string, args ...interface{}) { - DefaultLogger.log(InfoLevel, msg, args...) + DefaultLogger.log(InfoLevel, 0, msg, args...) } func Warnf(msg string, args ...interface{}) { - DefaultLogger.log(WarnLevel, msg, args...) + DefaultLogger.log(WarnLevel, 0, msg, args...) } func Errorf(msg string, args ...interface{}) { - DefaultLogger.log(ErrorLevel, msg, args...) + DefaultLogger.log(ErrorLevel, 0, msg, args...) +} + +func Logf(level Level, offset int, msg string, args ...interface{}) { + DefaultLogger.log(level, offset, msg, args...) } diff --git a/log/log.go b/log/log.go index c63c393..5cc04fb 100644 --- a/log/log.go +++ b/log/log.go @@ -13,7 +13,7 @@ import ( "github.com/fatedier/golib/clock" ) -type LogWriter interface { +type Writer interface { WriteLog([]byte, Level, time.Time) (n int, err error) } @@ -68,46 +68,54 @@ func (l *Logger) clone() *Logger { } func (l *Logger) Trace(args ...interface{}) { - l.log(TraceLevel, "", args...) + l.log(TraceLevel, 0, "", args...) } func (l *Logger) Debug(args ...interface{}) { - l.log(DebugLevel, "", args...) + l.log(DebugLevel, 0, "", args...) } func (l *Logger) Info(args ...interface{}) { - l.log(InfoLevel, "", args...) + l.log(InfoLevel, 0, "", args...) } func (l *Logger) Warn(args ...interface{}) { - l.log(WarnLevel, "", args...) + l.log(WarnLevel, 0, "", args...) } func (l *Logger) Error(args ...interface{}) { - l.log(ErrorLevel, "", args...) + l.log(ErrorLevel, 0, "", args...) +} + +func (l *Logger) Log(level Level, offset int, args ...interface{}) { + l.log(level, offset, "", args...) } func (l *Logger) Tracef(msg string, args ...interface{}) { - l.log(TraceLevel, msg, args...) + l.log(TraceLevel, 0, msg, args...) } func (l *Logger) Debugf(msg string, args ...interface{}) { - l.log(DebugLevel, msg, args...) + l.log(DebugLevel, 0, msg, args...) } func (l *Logger) Infof(msg string, args ...interface{}) { - l.log(InfoLevel, msg, args...) + l.log(InfoLevel, 0, msg, args...) } func (l *Logger) Warnf(msg string, args ...interface{}) { - l.log(WarnLevel, msg, args...) + l.log(WarnLevel, 0, msg, args...) } func (l *Logger) Errorf(msg string, args ...interface{}) { - l.log(ErrorLevel, msg, args...) + l.log(ErrorLevel, 0, msg, args...) +} + +func (l *Logger) Logf(level Level, offset int, msg string, args ...interface{}) { + l.log(level, offset, msg, args...) } -func (l *Logger) log(level Level, msg string, args ...interface{}) { +func (l *Logger) log(level Level, offset int, msg string, args ...interface{}) { if !l.level.Enabled(level) { return } @@ -129,14 +137,14 @@ func (l *Logger) log(level Level, msg string, args ...interface{}) { buffer.WriteByte(' ') if l.callerEnabled { - buffer.WriteString(getCallerPrefix(3 + l.callerSkip)) + buffer.WriteString(getCallerPrefix(3 + l.callerSkip + offset)) buffer.WriteByte(' ') } buffer.WriteString(getMessage(msg, args)) buffer.WriteByte('\n') - if lw, ok := l.out.(LogWriter); ok { + if lw, ok := l.out.(Writer); ok { l.outMu.Lock() defer l.outMu.Unlock() _, _ = lw.WriteLog(buffer.Bytes(), level, when) @@ -144,7 +152,7 @@ func (l *Logger) log(level Level, msg string, args ...interface{}) { } l.outMu.Lock() defer l.outMu.Unlock() - l.out.Write(buffer.Bytes()) + _, _ = l.out.Write(buffer.Bytes()) } func getMessage(template string, fmtArgs []interface{}) string { diff --git a/log/log_test.go b/log/log_test.go index 395d35b..d9607fb 100644 --- a/log/log_test.go +++ b/log/log_test.go @@ -40,3 +40,19 @@ func BenchmarkLog(b *testing.B) { logger.Debugf("debug %d", i) } } + +func TestLogOffset(t *testing.T) { + require := require.New(t) + testBuffer := bytes.NewBuffer(nil) + logger := New( + WithLevel(DebugLevel), + WithCaller(true), + WithOutput(testBuffer), + ) + wrapLog := func() { + logger.Log(InfoLevel, 1, "test") + } + wrapLog() + + require.Contains(testBuffer.String(), "log/log_test.go:55") +} diff --git a/log/output_console_test.go b/log/output_console_test.go index e66cca6..17fc652 100644 --- a/log/output_console_test.go +++ b/log/output_console_test.go @@ -5,8 +5,9 @@ import ( "testing" "time" - testingclock "github.com/fatedier/golib/clock/testing" "github.com/stretchr/testify/require" + + testingclock "github.com/fatedier/golib/clock/testing" ) func TestConsoleWriter(t *testing.T) { diff --git a/log/output_rotatefile.go b/log/output_rotatefile.go index 71aa560..6e23de9 100644 --- a/log/output_rotatefile.go +++ b/log/output_rotatefile.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "path/filepath" "slices" @@ -114,7 +113,7 @@ func (fw *RotateFileWriter) openExistingOrNew() error { return fmt.Errorf("get stat of logfile error: %s", err) } - file, err := os.OpenFile(fw.cfg.FileName, os.O_APPEND|os.O_WRONLY, 0644) + file, err := os.OpenFile(fw.cfg.FileName, os.O_APPEND|os.O_WRONLY, 0o644) if err != nil { return fw.openNew() } @@ -123,12 +122,12 @@ func (fw *RotateFileWriter) openExistingOrNew() error { } func (fw *RotateFileWriter) openNew() error { - err := os.MkdirAll(fw.dir(), 0755) + err := os.MkdirAll(fw.dir(), 0o755) if err != nil { return fmt.Errorf("mkdir directories [%s] for new logfile error: %s", fw.dir(), err) } - mode := os.FileMode(0600) + mode := os.FileMode(0o600) info, err := os.Stat(fw.cfg.FileName) if err == nil { mode = info.Mode() @@ -192,7 +191,7 @@ func (fw *RotateFileWriter) dailyRotate() { // Rotate the log file at 0 hour of the day. if nextHour.Hour() == 0 { - fw.Rotate() + _ = fw.Rotate() // Ensure it's executed only once, even if the waiting period crosses midnight. time.Sleep(time.Minute) } @@ -205,7 +204,7 @@ type logFileInfo struct { } func (fw *RotateFileWriter) oldLogFiles() ([]logFileInfo, error) { - files, err := ioutil.ReadDir(fw.dir()) + entries, err := os.ReadDir(fw.dir()) if err != nil { return nil, fmt.Errorf("read log file directory error: %s", err) } @@ -215,12 +214,17 @@ func (fw *RotateFileWriter) oldLogFiles() ([]logFileInfo, error) { ext := filepath.Ext(filename) prefix := filename[:len(filename)-len(ext)] + "." - for _, f := range files { - if f.IsDir() { + for _, entry := range entries { + if entry.IsDir() { continue } - if t, err := fw.parseTimeFromBackupName(f.Name(), prefix, ext); err == nil { - fileInfos = append(fileInfos, logFileInfo{info: f, t: t}) + info, err := entry.Info() + if err != nil { + continue + } + + if t, err := fw.parseTimeFromBackupName(entry.Name(), prefix, ext); err == nil { + fileInfos = append(fileInfos, logFileInfo{info: info, t: t}) continue } } diff --git a/log/output_rotatefile_test.go b/log/output_rotatefile_test.go index 3796294..faaac44 100644 --- a/log/output_rotatefile_test.go +++ b/log/output_rotatefile_test.go @@ -6,8 +6,9 @@ import ( "testing" "time" - testingclock "github.com/fatedier/golib/clock/testing" "github.com/stretchr/testify/require" + + testingclock "github.com/fatedier/golib/clock/testing" ) func TestRotateFileWriter_RotateDaily(t *testing.T) { diff --git a/msg/json/msg.go b/msg/json/msg.go index e3cd983..d16d4f4 100644 --- a/msg/json/msg.go +++ b/msg/json/msg.go @@ -18,9 +18,7 @@ import ( "reflect" ) -var ( - defaultMaxMsgLength int64 = 10240 -) +var defaultMaxMsgLength int64 = 10240 // Message wraps socket packages for communicating between frpc and frps. type Message interface{} diff --git a/msg/json/pack.go b/msg/json/pack.go index 27d1454..5e64517 100644 --- a/msg/json/pack.go +++ b/msg/json/pack.go @@ -59,8 +59,8 @@ func (msgCtl *MsgCtl) Pack(msg Message) ([]byte, error) { } buffer := bytes.NewBuffer(nil) - buffer.WriteByte(typeByte) - binary.Write(buffer, binary.BigEndian, int64(len(content))) - buffer.Write(content) + _ = buffer.WriteByte(typeByte) + _ = binary.Write(buffer, binary.BigEndian, int64(len(content))) + _, _ = buffer.Write(content) return buffer.Bytes(), nil } diff --git a/msg/json/pack_test.go b/msg/json/pack_test.go index 525da9f..5abc95a 100644 --- a/msg/json/pack_test.go +++ b/msg/json/pack_test.go @@ -25,8 +25,10 @@ import ( type TestStruct struct{} -type Ping struct{} -type Pong struct{} +type ( + Ping struct{} + Pong struct{} +) type Login struct { User string `json:"user"` @@ -49,19 +51,15 @@ func init() { func TestPack(t *testing.T) { assert := assert.New(t) - var ( - msg Message - buffer []byte - err error - ) + var msg Message // error type msg = &TestStruct{} - buffer, err = msgCtl.Pack(msg) + _, err := msgCtl.Pack(msg) assert.Equal(err, ErrMsgType) // correct msg = &Ping{} - buffer, err = msgCtl.Pack(msg) + buffer, err := msgCtl.Pack(msg) assert.NoError(err) b := bytes.NewBuffer(nil) b.WriteByte(TypePing) @@ -73,16 +71,12 @@ func TestPack(t *testing.T) { func TestUnPack(t *testing.T) { assert := assert.New(t) - var ( - msg Message - err error - ) // error message type - msg, err = msgCtl.UnPack('-', []byte("{}")) + _, err := msgCtl.UnPack('-', []byte("{}")) assert.Error(err) // correct - msg, err = msgCtl.UnPack(TypePong, []byte("{}")) + msg, err := msgCtl.UnPack(TypePong, []byte("{}")) assert.NoError(err) assert.Equal(reflect.TypeOf(msg).Elem(), reflect.TypeOf(Pong{})) } diff --git a/msg/json/process_test.go b/msg/json/process_test.go index 4c0d13d..330160a 100644 --- a/msg/json/process_test.go +++ b/msg/json/process_test.go @@ -27,9 +27,7 @@ type StartWorkConn struct { ProxyName string `json:"proxy_name"` } -var ( - TypeStartWorkConn byte = '4' -) +var TypeStartWorkConn byte = '4' func init() { msgCtl.RegisterMsg(TypeStartWorkConn, StartWorkConn{}) @@ -107,5 +105,4 @@ func TestProcess(t *testing.T) { assert.Error(err) msgCtl.SetMaxMsgLength(defaultMaxMsgLength) - return } diff --git a/net/dial/dial.go b/net/dial.go similarity index 92% rename from net/dial/dial.go rename to net/dial.go index 1b224e7..b73c88e 100644 --- a/net/dial/dial.go +++ b/net/dial.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package dial +package net import ( "context" @@ -36,7 +36,7 @@ func DialContext(ctx context.Context, addr string, opts ...DialOption) (c net.Co // call before dial hooks dialMetas := make(DialMetas) - ctx = context.WithValue(ctx, ctxKey, dialMetas) + ctx = context.WithValue(ctx, dialCtxKey, dialMetas) for _, v := range op.beforeHooks { ctx = v.Hook(ctx, addr) @@ -44,7 +44,7 @@ func DialContext(ctx context.Context, addr string, opts ...DialOption) (c net.Co if op.proxyAddr != "" { support := false - for _, v := range supportProxyTypes { + for _, v := range supportedDialProxyTypes { if op.proxyType == v { support = true break @@ -79,7 +79,7 @@ func DialContext(ctx context.Context, addr string, opts ...DialOption) (c net.Co for _, v := range op.afterHooks { ctx, c, err = v.Hook(ctx, c, addr) if err != nil { - // Close last valid connection if any error occured + // Close last valid connection if any error occurred lastSuccConn.Close() return nil, err } @@ -120,8 +120,8 @@ func dialKCPServer(addr string) (c net.Conn, err error) { kcpConn.SetWindowSize(128, 512) kcpConn.SetMtu(1350) kcpConn.SetACKNoDelay(false) - kcpConn.SetReadBuffer(4194304) - kcpConn.SetWriteBuffer(4194304) + _ = kcpConn.SetReadBuffer(4194304) + _ = kcpConn.SetWriteBuffer(4194304) c = kcpConn return } diff --git a/net/dial/option.go b/net/dial_option.go similarity index 90% rename from net/dial/option.go rename to net/dial_option.go index 5c69ded..36e005a 100644 --- a/net/dial/option.go +++ b/net/dial_option.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package dial +package net import ( "bufio" @@ -30,9 +30,7 @@ import ( "golang.org/x/net/proxy" ) -var ( - supportProxyTypes = []string{"socks5", "http", "ntlm"} -) +var supportedDialProxyTypes = []string{"socks5", "http", "ntlm"} type ProxyAuth struct { Username string @@ -45,15 +43,15 @@ func (m DialMetas) Value(key interface{}) interface{} { return m[key] } -type metaKey string +type dialMetaKey string const ( - ctxKey metaKey = "meta" - proxyAuthKey metaKey = "proxyAuth" + dialCtxKey dialMetaKey = "meta" + proxyAuthKey dialMetaKey = "proxyAuth" ) func GetDialMetasFromContext(ctx context.Context) DialMetas { - metas, ok := ctx.Value(ctxKey).(DialMetas) + metas, ok := ctx.Value(dialCtxKey).(DialMetas) if !ok || metas == nil { metas = make(DialMetas) } @@ -64,7 +62,6 @@ type dialOptions struct { proxyType string proxyAddr string protocol string - tlsConfig *tls.Config laddr string // only use ip, port is random timeout time.Duration keepAlive time.Duration @@ -88,7 +85,7 @@ const ( type AfterHookFunc func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) type AfterHook struct { - // smaller value will be called first, 0 is reserverd for private use. + // smaller value will be called first, 0 is reserved for private use. // If caller set this 0, use DefaultAfterHookPriority instead. Priority uint64 Hook AfterHookFunc @@ -221,26 +218,6 @@ func WithAfterHook(hook AfterHook) DialOption { }) } -func newSocks5ProxyAfterHook(addr string, op dialOptions) AfterHook { - return AfterHook{ - Priority: 0, - Hook: func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) { - conn, err := socks5ProxyAfterHook(ctx, c, addr) - return ctx, conn, err - }, - } -} - -func newNTLMHTTPProxyAfterHook(addr string, op dialOptions) AfterHook { - return AfterHook{ - Priority: 0, - Hook: func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) { - conn, err := ntlmHTTPProxyAfterHook(ctx, c, addr) - return ctx, conn, err - }, - } -} - type funcDialContext func(ctx context.Context, networkd string, addr string) (c net.Conn, err error) func (fdc funcDialContext) DialContext(ctx context.Context, network string, addr string) (c net.Conn, err error) { @@ -290,7 +267,7 @@ func httpProxyAfterHook(ctx context.Context, conn net.Conn, addr string) (net.Co req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(proxyAuth.Username+":"+proxyAuth.Passwd))) } req.Header.Set("User-Agent", "Mozilla/5.0") - req.Write(conn) + _ = req.Write(conn) resp, err := http.ReadResponse(bufio.NewReader(conn), req) if err != nil { @@ -322,7 +299,7 @@ func ntlmHTTPProxyAfterHook(ctx context.Context, conn net.Conn, addr string) (ne req.Header.Add("Proxy-Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(negotiateMessage)) } - req.Write(conn) + _ = req.Write(conn) resp, err := http.ReadResponse(bufio.NewReader(conn), req) if err != nil { return nil, err @@ -348,7 +325,7 @@ func ntlmHTTPProxyAfterHook(ctx context.Context, conn net.Conn, addr string) (ne } req.Header.Add("Proxy-Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(authenticateMessage)) - req.Write(conn) + _ = req.Write(conn) resp, err = http.ReadResponse(bufio.NewReader(conn), req) if err != nil { return nil, err diff --git a/net/dial/dial_test.go b/net/dial_test.go similarity index 98% rename from net/dial/dial_test.go rename to net/dial_test.go index 8ee608b..e9b02ec 100644 --- a/net/dial/dial_test.go +++ b/net/dial_test.go @@ -1,4 +1,4 @@ -package dial +package net import ( "net" diff --git a/net/mux/mux.go b/net/mux/mux.go index 2529e62..c5c3626 100644 --- a/net/mux/mux.go +++ b/net/mux/mux.go @@ -83,12 +83,12 @@ func (mux *Mux) Listen(priority int, needBytesNum uint32, fn MatchFunc) net.List return ln } -func (mux *Mux) ListenHttp(priority int) net.Listener { - return mux.Listen(priority, HttpNeedBytesNum, HttpMatchFunc) +func (mux *Mux) ListenHTTP(priority int) net.Listener { + return mux.Listen(priority, HTTPNeedBytesNum, HTTPMatchFunc) } -func (mux *Mux) ListenHttps(priority int) net.Listener { - return mux.Listen(priority, HttpsNeedBytesNum, HttpsMatchFunc) +func (mux *Mux) ListenHTTPS(priority int) net.Listener { + return mux.Listen(priority, HTTPSNeedBytesNum, HTTPSMatchFunc) } func (mux *Mux) DefaultListener() net.Listener { @@ -122,9 +122,7 @@ func (mux *Mux) release(ln *listener) bool { func (mux *Mux) copyLns() []*listener { lns := make([]*listener, 0, len(mux.lns)) - for _, l := range mux.lns { - lns = append(lns, l) - } + lns = append(lns, mux.lns...) return lns } @@ -171,9 +169,9 @@ func (mux *Mux) handleConn(conn net.Conn) { if mux.keepAlive != 0 { if tcpConn, ok := conn.(*net.TCPConn); ok { if mux.keepAlive > 0 { - tcpConn.SetKeepAlivePeriod(mux.keepAlive) + _ = tcpConn.SetKeepAlivePeriod(mux.keepAlive) } else { - tcpConn.SetKeepAlive(false) + _ = tcpConn.SetKeepAlive(false) } } } @@ -181,13 +179,13 @@ func (mux *Mux) handleConn(conn net.Conn) { sharedConn, rd := gnet.NewSharedConnSize(conn, int(maxNeedBytesNum)) data := make([]byte, maxNeedBytesNum) - conn.SetReadDeadline(time.Now().Add(DefaultTimeout)) + _ = conn.SetReadDeadline(time.Now().Add(DefaultTimeout)) _, err := io.ReadFull(rd, data) if err != nil { conn.Close() return } - conn.SetReadDeadline(time.Time{}) + _ = conn.SetReadDeadline(time.Time{}) for _, ln := range lns { if match := ln.matchFn(data); match { @@ -214,7 +212,6 @@ func (mux *Mux) handleConn(conn net.Conn) { // No listeners for this connection, close it. conn.Close() - return } type listener struct { @@ -224,8 +221,7 @@ type listener struct { needBytesNum uint32 matchFn MatchFunc - c chan net.Conn - mu sync.RWMutex + c chan net.Conn } // Accept waits for and returns the next connection to the listener. diff --git a/net/mux/mux_test.go b/net/mux/mux_test.go index d8e0905..be18ee2 100644 --- a/net/mux/mux_test.go +++ b/net/mux/mux_test.go @@ -2,7 +2,7 @@ package mux import ( "bufio" - "io/ioutil" + "io" "net" "net/http" "net/http/httptest" @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" ) -func runHttpSvr(ln net.Listener) *httptest.Server { +func runHTTPSvr(ln net.Listener) *httptest.Server { svr := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("http service")) })) @@ -21,7 +21,7 @@ func runHttpSvr(ln net.Listener) *httptest.Server { return svr } -func runHttpsSvr(ln net.Listener) *httptest.Server { +func runHTTPSSvr(ln net.Listener) *httptest.Server { svr := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("https service")) })) @@ -48,7 +48,7 @@ func runEchoSvr(ln net.Listener) { }() } -func runTcpSvr(ln net.Listener, respContent string) { +func runTCPSvr(ln net.Listener, respContent string) { go func() { for { conn, err := ln.Accept() @@ -73,15 +73,15 @@ func TestMux(t *testing.T) { assert.NoError(err) mux := NewMux(ln) - httpLn := mux.ListenHttp(0) - httpsLn := mux.ListenHttps(0) + httpLn := mux.ListenHTTP(0) + httpsLn := mux.ListenHTTPS(0) defaultLn := mux.DefaultListener() go mux.Serve() time.Sleep(100 * time.Millisecond) - httpSvr := runHttpSvr(httpLn) + httpSvr := runHTTPSvr(httpLn) defer httpSvr.Close() - httpsSvr := runHttpsSvr(httpsLn) + httpsSvr := runHTTPSSvr(httpsLn) defer httpsSvr.Close() runEchoSvr(defaultLn) defer ln.Close() @@ -89,7 +89,7 @@ func TestMux(t *testing.T) { // test http service resp, err := http.Get(httpSvr.URL) assert.NoError(err) - data, err := ioutil.ReadAll(resp.Body) + data, err := io.ReadAll(resp.Body) assert.NoError(err) assert.Equal("http service", string(data)) @@ -97,7 +97,7 @@ func TestMux(t *testing.T) { client := httpsSvr.Client() resp, err = client.Get(httpsSvr.URL) assert.NoError(err) - data, err = ioutil.ReadAll(resp.Body) + data, err = io.ReadAll(resp.Body) assert.NoError(err) assert.Equal("https service", string(data)) @@ -120,21 +120,13 @@ func TestMuxPriority(t *testing.T) { mux := NewMux(ln) ln1 := mux.Listen(0, 2, func(data []byte) bool { - if data[0] == '1' { - return true - } else { - return false - } + return data[0] == '1' }) ln2 := mux.Listen(1, 2, func(data []byte) bool { - if data[0] == '1' { - return true - } else { - return false - } + return data[0] == '1' }) - runTcpSvr(ln1, "aaa") - runTcpSvr(ln2, "bbb") + runTCPSvr(ln1, "aaa") + runTCPSvr(ln2, "bbb") go mux.Serve() time.Sleep(100 * time.Millisecond) @@ -163,21 +155,13 @@ func TestMuxPriority(t *testing.T) { // priority 0, '1' -> 'bbb' // priority 1, '1' -> 'aaa' ln1 = mux.Listen(0, 2, func(data []byte) bool { - if data[0] == '1' { - return true - } else { - return false - } + return data[0] == '1' }) ln2 = mux.Listen(1, 2, func(data []byte) bool { - if data[0] == '2' { - return true - } else { - return false - } + return data[0] == '2' }) - runTcpSvr(ln2, "aaa") - runTcpSvr(ln1, "bbb") + runTCPSvr(ln2, "aaa") + runTCPSvr(ln1, "bbb") conn, err = net.Dial("tcp", ln.Addr().String()) assert.NoError(err) diff --git a/net/mux/rule.go b/net/mux/rule.go index f01b058..52f971d 100644 --- a/net/mux/rule.go +++ b/net/mux/rule.go @@ -3,38 +3,33 @@ package mux type MatchFunc func(data []byte) (match bool) var ( - HttpsNeedBytesNum uint32 = 1 - HttpNeedBytesNum uint32 = 3 + HTTPSNeedBytesNum uint32 = 1 + HTTPNeedBytesNum uint32 = 3 YamuxNeedBytesNum uint32 = 2 ) -var HttpsMatchFunc MatchFunc = func(data []byte) bool { - if len(data) < int(HttpsNeedBytesNum) { - return false - } - - if data[0] == 0x16 { - return true - } else { +var HTTPSMatchFunc MatchFunc = func(data []byte) bool { + if len(data) < int(HTTPSNeedBytesNum) { return false } + return data[0] == 0x16 } // From https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods var httpHeadBytes = map[string]struct{}{ - "GET": struct{}{}, - "HEA": struct{}{}, - "POS": struct{}{}, - "PUT": struct{}{}, - "DEL": struct{}{}, - "CON": struct{}{}, - "OPT": struct{}{}, - "TRA": struct{}{}, - "PAT": struct{}{}, + "GET": {}, + "HEA": {}, + "POS": {}, + "PUT": {}, + "DEL": {}, + "CON": {}, + "OPT": {}, + "TRA": {}, + "PAT": {}, } -var HttpMatchFunc MatchFunc = func(data []byte) bool { - if len(data) < int(HttpNeedBytesNum) { +var HTTPMatchFunc MatchFunc = func(data []byte) bool { + if len(data) < int(HTTPNeedBytesNum) { return false } @@ -42,13 +37,14 @@ var HttpMatchFunc MatchFunc = func(data []byte) bool { return ok } +// YamuxMatchFunc is a match function for yamux. // From https://github.com/hashicorp/yamux/blob/master/spec.md var YamuxMatchFunc MatchFunc = func(data []byte) bool { if len(data) < int(YamuxNeedBytesNum) { return false } - if data[0] == 0 && data[1] >= 0x0 && data[1] <= 0x3 { + if data[0] == 0 && data[1] <= 0x3 { return true } return false diff --git a/net/dial/util.go b/net/util.go similarity index 96% rename from net/dial/util.go rename to net/util.go index 3635956..9cb1b4b 100644 --- a/net/dial/util.go +++ b/net/util.go @@ -1,4 +1,4 @@ -package dial +package net import ( "net/url" diff --git a/net/dial/util_test.go b/net/util_test.go similarity index 99% rename from net/dial/util_test.go rename to net/util_test.go index 035df34..f6a22f0 100644 --- a/net/dial/util_test.go +++ b/net/util_test.go @@ -1,4 +1,4 @@ -package dial +package net import ( "testing" diff --git a/pool/buf.go b/pool/buf.go index 7fe2635..da5db78 100644 --- a/pool/buf.go +++ b/pool/buf.go @@ -28,17 +28,19 @@ var ( func GetBuf(size int) []byte { var x interface{} - if size >= 16*1024 { + switch { + case size >= 16*1024: x = bufPool16k.Get() - } else if size >= 5*1024 { + case size >= 5*1024: x = bufPool5k.Get() - } else if size >= 2*1024 { + case size >= 2*1024: x = bufPool2k.Get() - } else if size >= 1*1024 { + case size >= 1*1024: x = bufPool1k.Get() - } else { + default: x = bufPool.Get() } + if x == nil { return make([]byte, size) } @@ -51,15 +53,38 @@ func GetBuf(size int) []byte { func PutBuf(buf []byte) { size := cap(buf) - if size >= 16*1024 { + switch { + case size >= 16*1024: bufPool16k.Put(buf) - } else if size >= 5*1024 { + case size >= 5*1024: bufPool5k.Put(buf) - } else if size >= 2*1024 { + case size >= 2*1024: bufPool2k.Put(buf) - } else if size >= 1*1024 { + case size >= 1*1024: bufPool1k.Put(buf) - } else { + default: bufPool.Put(buf) } } + +type Buffer struct { + pool sync.Pool +} + +func NewBuffer(size int) *Buffer { + return &Buffer{ + pool: sync.Pool{ + New: func() interface{} { + return make([]byte, size) + }, + }, + } +} + +func (p *Buffer) Get() []byte { + return p.pool.Get().([]byte) +} + +func (p *Buffer) Put(buf []byte) { + p.pool.Put(buf) +} diff --git a/pool/buf_test.go b/pool/buf_test.go index c468340..4c01f45 100644 --- a/pool/buf_test.go +++ b/pool/buf_test.go @@ -15,9 +15,10 @@ package pool import ( + "bytes" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestPutBuf(t *testing.T) { @@ -35,17 +36,32 @@ func TestPutBuf(t *testing.T) { } func TestGetBuf(t *testing.T) { - assert := assert.New(t) + require := require.New(t) buf := GetBuf(200) - assert.Len(buf, 200) + require.Len(buf, 200) buf = GetBuf(1025) - assert.Len(buf, 1025) + require.Len(buf, 1025) buf = GetBuf(2 * 1024) - assert.Len(buf, 2*1024) + require.Len(buf, 2*1024) buf = GetBuf(5 * 2000) - assert.Len(buf, 5*2000) + require.Len(buf, 5*2000) +} + +func TestBuffer(t *testing.T) { + require := require.New(t) + + bufPool := NewBuffer(100) + + buf := bufPool.Get() + require.Len(buf, 100) + copy(buf, []byte("hello")) + + bufPool.Put(buf) + buf = bufPool.Get() + require.Len(buf, 100) + require.True(bytes.Contains(buf, []byte("hello"))) } diff --git a/pool/snappy.go b/pool/snappy.go index 7eb9226..a56f965 100644 --- a/pool/snappy.go +++ b/pool/snappy.go @@ -27,8 +27,7 @@ var ( ) func GetSnappyReader(r io.Reader) *snappy.Reader { - var x interface{} - x = snappyReaderPool.Get() + x := snappyReaderPool.Get() if x == nil { return snappy.NewReader(r) } @@ -42,8 +41,7 @@ func PutSnappyReader(sr *snappy.Reader) { } func GetSnappyWriter(w io.Writer) *snappy.Writer { - var x interface{} - x = snappyWriterPool.Get() + x := snappyWriterPool.Get() if x == nil { return snappy.NewWriter(w) }