├── .github ├── codecov.yml └── workflows │ └── actions.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── binding ├── binding.go ├── binding_nomsgpack.go ├── default_validator.go ├── form.go ├── form_mapping.go ├── form_mapping_benchmark_test.go ├── form_mapping_test.go ├── header.go ├── internal │ ├── bytesconv │ │ ├── bytesconv.go │ │ └── bytesconv_test.go │ └── json │ │ └── json.go ├── json.go ├── json_test.go ├── msgpack.go ├── msgpack_test.go ├── multipart_form_mapping.go ├── multipart_form_mapping_test.go ├── protobuf.go ├── query.go ├── uri.go ├── validate_test.go ├── xml.go ├── xml_test.go ├── yaml.go └── yaml_test.go ├── buffer ├── README.md ├── buffer.go ├── buffer_test.go ├── bytebuffer_ctx.go ├── bytebuffer_ctx_test.go ├── bytebuffer_pool.go ├── bytebuffer_pool_test.go ├── iobuffer.go ├── iobuffer_pool.go ├── iobuffer_pool_test.go ├── iobuffer_test.go ├── log.go └── types.go ├── build └── contrib │ └── builder │ └── binary │ └── Dockerfile ├── etc └── script │ └── report.sh ├── go.mod ├── go.sum ├── header ├── bytes.go └── common.go ├── internal └── context │ ├── context.go │ ├── context_test.go │ └── wrapper.go ├── log ├── buffer.go ├── buffer_test.go ├── contextlog.go ├── errorlog.go ├── errorlog_test.go ├── escape_test.go ├── logger.go ├── logger_test.go ├── roller.go ├── roller_test.go └── types.go ├── netpoll ├── epoll.go ├── epoll_test.go ├── handle.go ├── handle_stub.go ├── handle_unix.go ├── kqueue.go ├── netpoll.go ├── netpoll_epoll.go ├── netpoll_kqueue.go ├── netpoll_stub.go └── util.go ├── protocol └── http │ ├── header_test.go │ ├── types.go │ └── types_test.go ├── registry └── dubbo │ ├── base_registry.go │ ├── common │ ├── constant │ │ ├── cluster.go │ │ ├── default.go │ │ ├── env.go │ │ ├── key.go │ │ ├── time.go │ │ └── version.go │ ├── logger │ │ ├── log.yml │ │ ├── logger.go │ │ ├── logger_test.go │ │ └── logging.go │ ├── node.go │ ├── rpc_service.go │ ├── rpc_service_test.go │ └── url.go │ ├── config_center │ ├── configuration_listener.go │ ├── configurator.go │ ├── configurator │ │ ├── mock.go │ │ └── override.go │ ├── dynamic_configuration.go │ ├── dynamic_configuration_factory.go │ ├── mock_dynamic_config.go │ ├── parser │ │ ├── configuration_parser.go │ │ └── configuration_parser_test.go │ └── zookeeper │ │ ├── factory.go │ │ ├── impl.go │ │ └── listener.go │ ├── event.go │ ├── event_listener.go │ ├── mock_registry.go │ ├── readme.md │ ├── registry.go │ ├── remoting │ ├── listener.go │ └── zookeeper │ │ ├── client.go │ │ ├── curator_discovery │ │ ├── service_discovery.go │ │ └── service_instance.go │ │ ├── facade.go │ │ └── listener.go │ ├── service_discovery.go │ ├── service_instance.go │ └── zookeeper │ ├── listener.go │ ├── listener_test.go │ └── registry.go ├── utils ├── dup.go ├── dup_386.go ├── dup_amd64.go ├── dup_arm64.go ├── expire_map.go ├── expire_map_test.go ├── file.go ├── file_test.go ├── goroutine.go ├── goroutine_test.go ├── sync_list.go ├── sync_list_test.go ├── syscall.go ├── syscall_test.go ├── syscall_windows.go ├── ticker.go ├── time_cache.go ├── time_cache_test.go ├── timer.go ├── timer_test.go ├── trylock.go ├── trylock_test.go └── uuid.go └── variable ├── api.go ├── api_test.go ├── factory.go ├── factory_test.go ├── protocolres.go ├── protocolres_test.go ├── types.go └── var.go /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | # To validate: 2 | # cat codecov.yml | curl --data-binary @- https://codecov.io/validate 3 | 4 | codecov: 5 | notify: 6 | require_ci_to_pass: yes 7 | 8 | allow_coverage_offsets: true 9 | 10 | coverage: 11 | precision: 2 12 | round: down 13 | range: "50...75" 14 | 15 | status: 16 | project: 17 | default: 18 | threshold: 1 19 | # Disable patch since it is noisy and not correct 20 | patch: 21 | default: 22 | enabled: no 23 | if_not_found: success 24 | -------------------------------------------------------------------------------- /.github/workflows/actions.yml: -------------------------------------------------------------------------------- 1 | name: actions 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | jobs: 8 | golangci-lint: 9 | name: runner / golangci-lint 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out code 13 | uses: actions/checkout@v3 14 | - name: golangci-lint 15 | uses: reviewdog/action-golangci-lint@v2 16 | with: 17 | golangci_lint_flags: "--enable-all --timeout=10m --exclude-use-default=false --tests=false --disable=gochecknoinits,gochecknoglobals,exhaustive,nakedret,wrapcheck" 18 | 19 | test: 20 | name: test 21 | runs-on: ubuntu-latest 22 | # A matrix proves the supported range of Go versions work. This must always 23 | # include the floor Go version policy of Mosn and the current Go version. 24 | # Mosn's floor Go version for libraries is two behind current, e.g. if Go 25 | # supports 1.19 and 1.20, Mosn libraries must work on 1.18, 1.19 and 1.20. 26 | # 27 | # A floor version is required to ensure Mosn can receive security patches. 28 | # Without one, dependencies become locked to an old version of Go, which 29 | # itself receives no security patch updates. 30 | # 31 | # Mosn's binary is built with Go's floor version, e.g. if Go supports 1.19 32 | # and 1.20, Mosn will build any downloadable executables with 1.19. 33 | # 34 | # Even if mosn works with a Go version below its supported floor, users 35 | # must not depend on this. Mosn and its library dependencies are free to 36 | # use features in the supported floor Go version at any time. This remains 37 | # true even if mosn library dependencies are not eagerly updated. 38 | strategy: 39 | matrix: 40 | go-version: 41 | - "1.19" # Current Go version 42 | - "1.18" 43 | - "1.17" # Floor Go version of Mosn == current - 2 44 | 45 | steps: 46 | - name: Check out code 47 | uses: actions/checkout@v3 48 | 49 | - name: Set up Go 50 | uses: actions/setup-go@v3 51 | with: 52 | go-version: ${{ matrix.go-version }} 53 | cache: true 54 | 55 | - name: Run Unit tests. 56 | run: make coverage 57 | 58 | - name: Coverage 59 | run: bash <(curl -s https://codecov.io/bash) 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_IMAGE = godep-builder 2 | SCRIPT_DIR = $(shell pwd)/etc/script 3 | PROJECT_NAME = mosn.io/pkg 4 | 5 | coverage-local: 6 | sh ${SCRIPT_DIR}/report.sh 7 | 8 | coverage: 9 | docker build --rm -t ${BUILD_IMAGE} build/contrib/builder/binary 10 | docker run --rm -v $(shell go env GOPATH):/go -v $(shell pwd):/go/src/${PROJECT_NAME} -w /go/src/${PROJECT_NAME} ${BUILD_IMAGE} make coverage-local 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Common MOSN Packages 2 | 3 | Common utility packages leveraged by other repos. 4 | 5 | # Install 6 | 7 | ``` 8 | go get mosn.io/pkg 9 | ``` 10 | -------------------------------------------------------------------------------- /binding/binding.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !nomsgpack 6 | 7 | package binding 8 | 9 | import "net/http" 10 | 11 | // Content-Type MIME of the most common data formats. 12 | const ( 13 | MIMEJSON = "application/json" 14 | MIMEHTML = "text/html" 15 | MIMEXML = "application/xml" 16 | MIMEXML2 = "text/xml" 17 | MIMEPlain = "text/plain" 18 | MIMEPOSTForm = "application/x-www-form-urlencoded" 19 | MIMEMultipartPOSTForm = "multipart/form-data" 20 | MIMEPROTOBUF = "application/x-protobuf" 21 | MIMEMSGPACK = "application/x-msgpack" 22 | MIMEMSGPACK2 = "application/msgpack" 23 | MIMEYAML = "application/x-yaml" 24 | ) 25 | 26 | // Binding describes the interface which needs to be implemented for binding the 27 | // data present in the request such as JSON request body, query parameters or 28 | // the form POST. 29 | type Binding interface { 30 | Name() string 31 | Bind(*http.Request, interface{}) error 32 | } 33 | 34 | // BindingBody adds BindBody method to Binding. BindBody is similar with Bind, 35 | // but it reads the body from supplied bytes instead of req.Body. 36 | type BindingBody interface { 37 | Binding 38 | BindBody([]byte, interface{}) error 39 | } 40 | 41 | // BindingUri adds BindUri method to Binding. BindUri is similar with Bind, 42 | // but it read the Params. 43 | type BindingUri interface { 44 | Name() string 45 | BindUri(map[string][]string, interface{}) error 46 | } 47 | 48 | // StructValidator is the minimal interface which needs to be implemented in 49 | // order for it to be used as the validator engine for ensuring the correctness 50 | // of the request. Gin provides a default implementation for this using 51 | // https://github.com/go-playground/validator/tree/v8.18.2. 52 | type StructValidator interface { 53 | // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. 54 | // If the received type is not a struct, any validation should be skipped and nil must be returned. 55 | // If the received type is a struct or pointer to a struct, the validation should be performed. 56 | // If the struct is not valid or the validation itself fails, a descriptive error should be returned. 57 | // Otherwise nil must be returned. 58 | ValidateStruct(interface{}) error 59 | 60 | // Engine returns the underlying validator engine which powers the 61 | // StructValidator implementation. 62 | Engine() interface{} 63 | } 64 | 65 | // Validator is the default validator which implements the StructValidator 66 | // interface. It uses https://github.com/go-playground/validator/tree/v8.18.2 67 | // under the hood. 68 | var Validator StructValidator = &defaultValidator{} 69 | 70 | // These implement the Binding interface and can be used to bind the data 71 | // present in the request to struct instances. 72 | var ( 73 | JSON = jsonBinding{} 74 | XML = xmlBinding{} 75 | Form = formBinding{} 76 | Query = queryBinding{} 77 | FormPost = formPostBinding{} 78 | FormMultipart = formMultipartBinding{} 79 | ProtoBuf = protobufBinding{} 80 | MsgPack = msgpackBinding{} 81 | YAML = yamlBinding{} 82 | Uri = uriBinding{} 83 | Header = headerBinding{} 84 | ) 85 | 86 | // Default returns the appropriate Binding instance based on the HTTP method 87 | // and the content type. 88 | func Default(method, contentType string) Binding { 89 | if method == http.MethodGet { 90 | return Form 91 | } 92 | 93 | switch contentType { 94 | case MIMEJSON: 95 | return JSON 96 | case MIMEXML, MIMEXML2: 97 | return XML 98 | case MIMEPROTOBUF: 99 | return ProtoBuf 100 | case MIMEMSGPACK, MIMEMSGPACK2: 101 | return MsgPack 102 | case MIMEYAML: 103 | return YAML 104 | case MIMEMultipartPOSTForm: 105 | return FormMultipart 106 | default: // case MIMEPOSTForm: 107 | return Form 108 | } 109 | } 110 | 111 | func validate(obj interface{}) error { 112 | if Validator == nil { 113 | return nil 114 | } 115 | return Validator.ValidateStruct(obj) 116 | } 117 | -------------------------------------------------------------------------------- /binding/binding_nomsgpack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build nomsgpack 6 | 7 | package binding 8 | 9 | import "net/http" 10 | 11 | // Content-Type MIME of the most common data formats. 12 | const ( 13 | MIMEJSON = "application/json" 14 | MIMEHTML = "text/html" 15 | MIMEXML = "application/xml" 16 | MIMEXML2 = "text/xml" 17 | MIMEPlain = "text/plain" 18 | MIMEPOSTForm = "application/x-www-form-urlencoded" 19 | MIMEMultipartPOSTForm = "multipart/form-data" 20 | MIMEPROTOBUF = "application/x-protobuf" 21 | MIMEYAML = "application/x-yaml" 22 | ) 23 | 24 | // Binding describes the interface which needs to be implemented for binding the 25 | // data present in the request such as JSON request body, query parameters or 26 | // the form POST. 27 | type Binding interface { 28 | Name() string 29 | Bind(*http.Request, interface{}) error 30 | } 31 | 32 | // BindingBody adds BindBody method to Binding. BindBody is similar with Bind, 33 | // but it reads the body from supplied bytes instead of req.Body. 34 | type BindingBody interface { 35 | Binding 36 | BindBody([]byte, interface{}) error 37 | } 38 | 39 | // BindingUri adds BindUri method to Binding. BindUri is similar with Bind, 40 | // but it read the Params. 41 | type BindingUri interface { 42 | Name() string 43 | BindUri(map[string][]string, interface{}) error 44 | } 45 | 46 | // StructValidator is the minimal interface which needs to be implemented in 47 | // order for it to be used as the validator engine for ensuring the correctness 48 | // of the request. Gin provides a default implementation for this using 49 | // https://github.com/go-playground/validator/tree/v8.18.2. 50 | type StructValidator interface { 51 | // ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. 52 | // If the received type is not a struct, any validation should be skipped and nil must be returned. 53 | // If the received type is a struct or pointer to a struct, the validation should be performed. 54 | // If the struct is not valid or the validation itself fails, a descriptive error should be returned. 55 | // Otherwise nil must be returned. 56 | ValidateStruct(interface{}) error 57 | 58 | // Engine returns the underlying validator engine which powers the 59 | // StructValidator implementation. 60 | Engine() interface{} 61 | } 62 | 63 | // Validator is the default validator which implements the StructValidator 64 | // interface. It uses https://github.com/go-playground/validator/tree/v8.18.2 65 | // under the hood. 66 | var Validator StructValidator = &defaultValidator{} 67 | 68 | // These implement the Binding interface and can be used to bind the data 69 | // present in the request to struct instances. 70 | var ( 71 | JSON = jsonBinding{} 72 | XML = xmlBinding{} 73 | Form = formBinding{} 74 | Query = queryBinding{} 75 | FormPost = formPostBinding{} 76 | FormMultipart = formMultipartBinding{} 77 | ProtoBuf = protobufBinding{} 78 | YAML = yamlBinding{} 79 | Uri = uriBinding{} 80 | Header = headerBinding{} 81 | ) 82 | 83 | // Default returns the appropriate Binding instance based on the HTTP method 84 | // and the content type. 85 | func Default(method, contentType string) Binding { 86 | if method == "GET" { 87 | return Form 88 | } 89 | 90 | switch contentType { 91 | case MIMEJSON: 92 | return JSON 93 | case MIMEXML, MIMEXML2: 94 | return XML 95 | case MIMEPROTOBUF: 96 | return ProtoBuf 97 | case MIMEYAML: 98 | return YAML 99 | case MIMEMultipartPOSTForm: 100 | return FormMultipart 101 | default: // case MIMEPOSTForm: 102 | return Form 103 | } 104 | } 105 | 106 | func validate(obj interface{}) error { 107 | if Validator == nil { 108 | return nil 109 | } 110 | return Validator.ValidateStruct(obj) 111 | } 112 | -------------------------------------------------------------------------------- /binding/default_validator.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Manu Martinez-Almeida. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "reflect" 9 | "sync" 10 | 11 | "github.com/go-playground/validator/v10" 12 | ) 13 | 14 | type defaultValidator struct { 15 | once sync.Once 16 | validate *validator.Validate 17 | } 18 | 19 | var _ StructValidator = &defaultValidator{} 20 | 21 | // ValidateStruct receives any kind of type, but only performed struct or pointer to struct type. 22 | func (v *defaultValidator) ValidateStruct(obj interface{}) error { 23 | value := reflect.ValueOf(obj) 24 | valueType := value.Kind() 25 | if valueType == reflect.Ptr { 26 | valueType = value.Elem().Kind() 27 | } 28 | if valueType == reflect.Struct { 29 | v.lazyinit() 30 | if err := v.validate.Struct(obj); err != nil { 31 | return err 32 | } 33 | } 34 | return nil 35 | } 36 | 37 | // Engine returns the underlying validator engine which powers the default 38 | // Validator instance. This is useful if you want to register custom validations 39 | // or struct level validations. See validator GoDoc for more info - 40 | // https://godoc.org/gopkg.in/go-playground/validator.v8 41 | func (v *defaultValidator) Engine() interface{} { 42 | v.lazyinit() 43 | return v.validate 44 | } 45 | 46 | func (v *defaultValidator) lazyinit() { 47 | v.once.Do(func() { 48 | v.validate = validator.New() 49 | v.validate.SetTagName("binding") 50 | }) 51 | } 52 | -------------------------------------------------------------------------------- /binding/form.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "net/http" 9 | ) 10 | 11 | const defaultMemory = 32 << 20 12 | 13 | type formBinding struct{} 14 | type formPostBinding struct{} 15 | type formMultipartBinding struct{} 16 | 17 | func (formBinding) Name() string { 18 | return "form" 19 | } 20 | 21 | func (formBinding) Bind(req *http.Request, obj interface{}) error { 22 | if err := req.ParseForm(); err != nil { 23 | return err 24 | } 25 | if err := req.ParseMultipartForm(defaultMemory); err != nil { 26 | if err != http.ErrNotMultipart { 27 | return err 28 | } 29 | } 30 | if err := mapForm(obj, req.Form); err != nil { 31 | return err 32 | } 33 | return validate(obj) 34 | } 35 | 36 | func (formPostBinding) Name() string { 37 | return "form-urlencoded" 38 | } 39 | 40 | func (formPostBinding) Bind(req *http.Request, obj interface{}) error { 41 | if err := req.ParseForm(); err != nil { 42 | return err 43 | } 44 | if err := mapForm(obj, req.PostForm); err != nil { 45 | return err 46 | } 47 | return validate(obj) 48 | } 49 | 50 | func (formMultipartBinding) Name() string { 51 | return "multipart/form-data" 52 | } 53 | 54 | func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error { 55 | if err := req.ParseMultipartForm(defaultMemory); err != nil { 56 | return err 57 | } 58 | if err := mappingByPtr(obj, (*multipartRequest)(req), "form"); err != nil { 59 | return err 60 | } 61 | 62 | return validate(obj) 63 | } 64 | -------------------------------------------------------------------------------- /binding/form_mapping_benchmark_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | var form = map[string][]string{ 15 | "name": {"mike"}, 16 | "friends": {"anna", "nicole"}, 17 | "id_number": {"12345678"}, 18 | "id_date": {"2018-01-20"}, 19 | } 20 | 21 | type structFull struct { 22 | Name string `form:"name"` 23 | Age int `form:"age,default=25"` 24 | Friends []string `form:"friends"` 25 | ID *struct { 26 | Number string `form:"id_number"` 27 | DateOfIssue time.Time `form:"id_date" time_format:"2006-01-02" time_utc:"true"` 28 | } 29 | Nationality *string `form:"nationality"` 30 | } 31 | 32 | func BenchmarkMapFormFull(b *testing.B) { 33 | var s structFull 34 | for i := 0; i < b.N; i++ { 35 | err := mapForm(&s, form) 36 | if err != nil { 37 | b.Fatalf("Error on a form mapping") 38 | } 39 | } 40 | b.StopTimer() 41 | 42 | t := b 43 | assert.Equal(t, "mike", s.Name) 44 | assert.Equal(t, 25, s.Age) 45 | assert.Equal(t, []string{"anna", "nicole"}, s.Friends) 46 | assert.Equal(t, "12345678", s.ID.Number) 47 | assert.Equal(t, time.Date(2018, 1, 20, 0, 0, 0, 0, time.UTC), s.ID.DateOfIssue) 48 | assert.Nil(t, s.Nationality) 49 | } 50 | 51 | type structName struct { 52 | Name string `form:"name"` 53 | } 54 | 55 | func BenchmarkMapFormName(b *testing.B) { 56 | var s structName 57 | for i := 0; i < b.N; i++ { 58 | err := mapForm(&s, form) 59 | if err != nil { 60 | b.Fatalf("Error on a form mapping") 61 | } 62 | } 63 | b.StopTimer() 64 | 65 | t := b 66 | assert.Equal(t, "mike", s.Name) 67 | } 68 | -------------------------------------------------------------------------------- /binding/header.go: -------------------------------------------------------------------------------- 1 | package binding 2 | 3 | import ( 4 | "net/http" 5 | "net/textproto" 6 | "reflect" 7 | ) 8 | 9 | type headerBinding struct{} 10 | 11 | func (headerBinding) Name() string { 12 | return "header" 13 | } 14 | 15 | func (headerBinding) Bind(req *http.Request, obj interface{}) error { 16 | 17 | if err := mapHeader(obj, req.Header); err != nil { 18 | return err 19 | } 20 | 21 | return validate(obj) 22 | } 23 | 24 | func mapHeader(ptr interface{}, h map[string][]string) error { 25 | return mappingByPtr(ptr, headerSource(h), "header") 26 | } 27 | 28 | type headerSource map[string][]string 29 | 30 | var _ setter = headerSource(nil) 31 | 32 | func (hs headerSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) { 33 | return setByForm(value, field, hs, textproto.CanonicalMIMEHeaderKey(tagValue), opt) 34 | } 35 | -------------------------------------------------------------------------------- /binding/internal/bytesconv/bytesconv.go: -------------------------------------------------------------------------------- 1 | package bytesconv 2 | 3 | import ( 4 | "reflect" 5 | "unsafe" 6 | ) 7 | 8 | // StringToBytes converts string to byte slice without a memory allocation. 9 | func StringToBytes(s string) (b []byte) { 10 | sh := *(*reflect.StringHeader)(unsafe.Pointer(&s)) 11 | bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 12 | bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len 13 | return b 14 | } 15 | 16 | // BytesToString converts byte slice to string without a memory allocation. 17 | func BytesToString(b []byte) string { 18 | return *(*string)(unsafe.Pointer(&b)) 19 | } 20 | -------------------------------------------------------------------------------- /binding/internal/bytesconv/bytesconv_test.go: -------------------------------------------------------------------------------- 1 | package bytesconv 2 | 3 | import ( 4 | "bytes" 5 | "math/rand" 6 | "strings" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | var testString = "Albert Einstein: Logic will get you from A to B. Imagination will take you everywhere." 12 | var testBytes = []byte(testString) 13 | 14 | func rawBytesToStr(b []byte) string { 15 | return string(b) 16 | } 17 | 18 | func rawStrToBytes(s string) []byte { 19 | return []byte(s) 20 | } 21 | 22 | // go test -v 23 | 24 | func TestBytesToString(t *testing.T) { 25 | data := make([]byte, 1024) 26 | for i := 0; i < 100; i++ { 27 | rand.Read(data) 28 | if rawBytesToStr(data) != BytesToString(data) { 29 | t.Fatal("don't match") 30 | } 31 | } 32 | } 33 | 34 | const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 35 | const ( 36 | letterIdxBits = 6 // 6 bits to represent a letter index 37 | letterIdxMask = 1<= 0; { 48 | if remain == 0 { 49 | cache, remain = src.Int63(), letterIdxMax 50 | } 51 | if idx := int(cache & letterIdxMask); idx < len(letterBytes) { 52 | sb.WriteByte(letterBytes[idx]) 53 | i-- 54 | } 55 | cache >>= letterIdxBits 56 | remain-- 57 | } 58 | 59 | return sb.String() 60 | } 61 | 62 | func TestStringToBytes(t *testing.T) { 63 | for i := 0; i < 100; i++ { 64 | s := RandStringBytesMaskImprSrcSB(64) 65 | if !bytes.Equal(rawStrToBytes(s), StringToBytes(s)) { 66 | t.Fatal("don't match") 67 | } 68 | } 69 | } 70 | 71 | // go test -v -run=none -bench=^BenchmarkBytesConv -benchmem=true 72 | 73 | func BenchmarkBytesConvBytesToStrRaw(b *testing.B) { 74 | for i := 0; i < b.N; i++ { 75 | rawBytesToStr(testBytes) 76 | } 77 | } 78 | 79 | func BenchmarkBytesConvBytesToStr(b *testing.B) { 80 | for i := 0; i < b.N; i++ { 81 | BytesToString(testBytes) 82 | } 83 | } 84 | 85 | func BenchmarkBytesConvStrToBytesRaw(b *testing.B) { 86 | for i := 0; i < b.N; i++ { 87 | rawStrToBytes(testString) 88 | } 89 | } 90 | 91 | func BenchmarkBytesConvStrToBytes(b *testing.B) { 92 | for i := 0; i < b.N; i++ { 93 | StringToBytes(testString) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /binding/internal/json/json.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Bo-Yi Wu. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package json 6 | 7 | import "encoding/json" 8 | 9 | var ( 10 | // Marshal is exported by gin/json package. 11 | Marshal = json.Marshal 12 | // Unmarshal is exported by gin/json package. 13 | Unmarshal = json.Unmarshal 14 | // MarshalIndent is exported by gin/json package. 15 | MarshalIndent = json.MarshalIndent 16 | // NewDecoder is exported by gin/json package. 17 | NewDecoder = json.NewDecoder 18 | // NewEncoder is exported by gin/json package. 19 | NewEncoder = json.NewEncoder 20 | ) 21 | -------------------------------------------------------------------------------- /binding/json.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "io" 11 | "net/http" 12 | 13 | "mosn.io/pkg/binding/internal/json" 14 | ) 15 | 16 | // EnableDecoderUseNumber is used to call the UseNumber method on the JSON 17 | // Decoder instance. UseNumber causes the Decoder to unmarshal a number into an 18 | // interface{} as a Number instead of as a float64. 19 | var EnableDecoderUseNumber = false 20 | 21 | // EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method 22 | // on the JSON Decoder instance. DisallowUnknownFields causes the Decoder to 23 | // return an error when the destination is a struct and the input contains object 24 | // keys which do not match any non-ignored, exported fields in the destination. 25 | var EnableDecoderDisallowUnknownFields = false 26 | 27 | type jsonBinding struct{} 28 | 29 | func (jsonBinding) Name() string { 30 | return "json" 31 | } 32 | 33 | func (jsonBinding) Bind(req *http.Request, obj interface{}) error { 34 | if req == nil || req.Body == nil { 35 | return fmt.Errorf("invalid request") 36 | } 37 | return decodeJSON(req.Body, obj) 38 | } 39 | 40 | func (jsonBinding) BindBody(body []byte, obj interface{}) error { 41 | return decodeJSON(bytes.NewReader(body), obj) 42 | } 43 | 44 | func decodeJSON(r io.Reader, obj interface{}) error { 45 | decoder := json.NewDecoder(r) 46 | if EnableDecoderUseNumber { 47 | decoder.UseNumber() 48 | } 49 | if EnableDecoderDisallowUnknownFields { 50 | decoder.DisallowUnknownFields() 51 | } 52 | if err := decoder.Decode(obj); err != nil { 53 | return err 54 | } 55 | return validate(obj) 56 | } 57 | -------------------------------------------------------------------------------- /binding/json_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestJSONBindingBindBody(t *testing.T) { 15 | var s struct { 16 | Foo string `json:"foo"` 17 | } 18 | err := jsonBinding{}.BindBody([]byte(`{"foo": "FOO"}`), &s) 19 | require.NoError(t, err) 20 | assert.Equal(t, "FOO", s.Foo) 21 | } 22 | -------------------------------------------------------------------------------- /binding/msgpack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Manu Martinez-Almeida. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !nomsgpack 6 | 7 | package binding 8 | 9 | import ( 10 | "bytes" 11 | "io" 12 | "net/http" 13 | 14 | "github.com/ugorji/go/codec" 15 | ) 16 | 17 | type msgpackBinding struct{} 18 | 19 | func (msgpackBinding) Name() string { 20 | return "msgpack" 21 | } 22 | 23 | func (msgpackBinding) Bind(req *http.Request, obj interface{}) error { 24 | return decodeMsgPack(req.Body, obj) 25 | } 26 | 27 | func (msgpackBinding) BindBody(body []byte, obj interface{}) error { 28 | return decodeMsgPack(bytes.NewReader(body), obj) 29 | } 30 | 31 | func decodeMsgPack(r io.Reader, obj interface{}) error { 32 | cdc := new(codec.MsgpackHandle) 33 | if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil { 34 | return err 35 | } 36 | return validate(obj) 37 | } 38 | -------------------------------------------------------------------------------- /binding/msgpack_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !nomsgpack 6 | 7 | package binding 8 | 9 | import ( 10 | "bytes" 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | "github.com/stretchr/testify/require" 15 | "github.com/ugorji/go/codec" 16 | ) 17 | 18 | func TestMsgpackBindingBindBody(t *testing.T) { 19 | type teststruct struct { 20 | Foo string `msgpack:"foo"` 21 | } 22 | var s teststruct 23 | err := msgpackBinding{}.BindBody(msgpackBody(t, teststruct{"FOO"}), &s) 24 | require.NoError(t, err) 25 | assert.Equal(t, "FOO", s.Foo) 26 | } 27 | 28 | func msgpackBody(t *testing.T, obj interface{}) []byte { 29 | var bs bytes.Buffer 30 | h := &codec.MsgpackHandle{} 31 | err := codec.NewEncoder(&bs, h).Encode(obj) 32 | require.NoError(t, err) 33 | return bs.Bytes() 34 | } 35 | -------------------------------------------------------------------------------- /binding/multipart_form_mapping.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "errors" 9 | "mime/multipart" 10 | "net/http" 11 | "reflect" 12 | ) 13 | 14 | type multipartRequest http.Request 15 | 16 | var _ setter = (*multipartRequest)(nil) 17 | 18 | // TrySet tries to set a value by the multipart request with the binding a form file 19 | func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) { 20 | if files := r.MultipartForm.File[key]; len(files) != 0 { 21 | return setByMultipartFormFile(value, field, files) 22 | } 23 | 24 | return setByForm(value, field, r.MultipartForm.Value, key, opt) 25 | } 26 | 27 | func setByMultipartFormFile(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) { 28 | switch value.Kind() { 29 | case reflect.Ptr: 30 | switch value.Interface().(type) { 31 | case *multipart.FileHeader: 32 | value.Set(reflect.ValueOf(files[0])) 33 | return true, nil 34 | } 35 | case reflect.Struct: 36 | switch value.Interface().(type) { 37 | case multipart.FileHeader: 38 | value.Set(reflect.ValueOf(*files[0])) 39 | return true, nil 40 | } 41 | case reflect.Slice: 42 | slice := reflect.MakeSlice(value.Type(), len(files), len(files)) 43 | isSetted, err = setArrayOfMultipartFormFiles(slice, field, files) 44 | if err != nil || !isSetted { 45 | return isSetted, err 46 | } 47 | value.Set(slice) 48 | return true, nil 49 | case reflect.Array: 50 | return setArrayOfMultipartFormFiles(value, field, files) 51 | } 52 | return false, errors.New("unsupported field type for multipart.FileHeader") 53 | } 54 | 55 | func setArrayOfMultipartFormFiles(value reflect.Value, field reflect.StructField, files []*multipart.FileHeader) (isSetted bool, err error) { 56 | if value.Len() != len(files) { 57 | return false, errors.New("unsupported len of array for []*multipart.FileHeader") 58 | } 59 | for i := range files { 60 | setted, err := setByMultipartFormFile(value.Index(i), field, files[i:i+1]) 61 | if err != nil || !setted { 62 | return setted, err 63 | } 64 | } 65 | return true, nil 66 | } 67 | -------------------------------------------------------------------------------- /binding/multipart_form_mapping_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "bytes" 9 | "io/ioutil" 10 | "mime/multipart" 11 | "net/http" 12 | "testing" 13 | 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestFormMultipartBindingBindOneFile(t *testing.T) { 18 | var s struct { 19 | FileValue multipart.FileHeader `form:"file"` 20 | FilePtr *multipart.FileHeader `form:"file"` 21 | SliceValues []multipart.FileHeader `form:"file"` 22 | SlicePtrs []*multipart.FileHeader `form:"file"` 23 | ArrayValues [1]multipart.FileHeader `form:"file"` 24 | ArrayPtrs [1]*multipart.FileHeader `form:"file"` 25 | } 26 | file := testFile{"file", "file1", []byte("hello")} 27 | 28 | req := createRequestMultipartFiles(t, file) 29 | err := FormMultipart.Bind(req, &s) 30 | assert.NoError(t, err) 31 | 32 | assertMultipartFileHeader(t, &s.FileValue, file) 33 | assertMultipartFileHeader(t, s.FilePtr, file) 34 | assert.Len(t, s.SliceValues, 1) 35 | assertMultipartFileHeader(t, &s.SliceValues[0], file) 36 | assert.Len(t, s.SlicePtrs, 1) 37 | assertMultipartFileHeader(t, s.SlicePtrs[0], file) 38 | assertMultipartFileHeader(t, &s.ArrayValues[0], file) 39 | assertMultipartFileHeader(t, s.ArrayPtrs[0], file) 40 | } 41 | 42 | func TestFormMultipartBindingBindTwoFiles(t *testing.T) { 43 | var s struct { 44 | SliceValues []multipart.FileHeader `form:"file"` 45 | SlicePtrs []*multipart.FileHeader `form:"file"` 46 | ArrayValues [2]multipart.FileHeader `form:"file"` 47 | ArrayPtrs [2]*multipart.FileHeader `form:"file"` 48 | } 49 | files := []testFile{ 50 | {"file", "file1", []byte("hello")}, 51 | {"file", "file2", []byte("world")}, 52 | } 53 | 54 | req := createRequestMultipartFiles(t, files...) 55 | err := FormMultipart.Bind(req, &s) 56 | assert.NoError(t, err) 57 | 58 | assert.Len(t, s.SliceValues, len(files)) 59 | assert.Len(t, s.SlicePtrs, len(files)) 60 | assert.Len(t, s.ArrayValues, len(files)) 61 | assert.Len(t, s.ArrayPtrs, len(files)) 62 | 63 | for i, file := range files { 64 | assertMultipartFileHeader(t, &s.SliceValues[i], file) 65 | assertMultipartFileHeader(t, s.SlicePtrs[i], file) 66 | assertMultipartFileHeader(t, &s.ArrayValues[i], file) 67 | assertMultipartFileHeader(t, s.ArrayPtrs[i], file) 68 | } 69 | } 70 | 71 | func TestFormMultipartBindingBindError(t *testing.T) { 72 | files := []testFile{ 73 | {"file", "file1", []byte("hello")}, 74 | {"file", "file2", []byte("world")}, 75 | } 76 | 77 | for _, tt := range []struct { 78 | name string 79 | s interface{} 80 | }{ 81 | {"wrong type", &struct { 82 | Files int `form:"file"` 83 | }{}}, 84 | {"wrong array size", &struct { 85 | Files [1]*multipart.FileHeader `form:"file"` 86 | }{}}, 87 | {"wrong slice type", &struct { 88 | Files []int `form:"file"` 89 | }{}}, 90 | } { 91 | req := createRequestMultipartFiles(t, files...) 92 | err := FormMultipart.Bind(req, tt.s) 93 | assert.Error(t, err) 94 | } 95 | } 96 | 97 | type testFile struct { 98 | Fieldname string 99 | Filename string 100 | Content []byte 101 | } 102 | 103 | func createRequestMultipartFiles(t *testing.T, files ...testFile) *http.Request { 104 | var body bytes.Buffer 105 | 106 | mw := multipart.NewWriter(&body) 107 | for _, file := range files { 108 | fw, err := mw.CreateFormFile(file.Fieldname, file.Filename) 109 | assert.NoError(t, err) 110 | 111 | n, err := fw.Write(file.Content) 112 | assert.NoError(t, err) 113 | assert.Equal(t, len(file.Content), n) 114 | } 115 | err := mw.Close() 116 | assert.NoError(t, err) 117 | 118 | req, err := http.NewRequest("POST", "/", &body) 119 | assert.NoError(t, err) 120 | 121 | req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+mw.Boundary()) 122 | return req 123 | } 124 | 125 | func assertMultipartFileHeader(t *testing.T, fh *multipart.FileHeader, file testFile) { 126 | assert.Equal(t, file.Filename, fh.Filename) 127 | // assert.Equal(t, int64(len(file.Content)), fh.Size) // fh.Size does not exist on go1.8 128 | 129 | fl, err := fh.Open() 130 | assert.NoError(t, err) 131 | 132 | body, err := ioutil.ReadAll(fl) 133 | assert.NoError(t, err) 134 | assert.Equal(t, string(file.Content), string(body)) 135 | 136 | err = fl.Close() 137 | assert.NoError(t, err) 138 | } 139 | -------------------------------------------------------------------------------- /binding/protobuf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "io/ioutil" 9 | "net/http" 10 | 11 | "github.com/golang/protobuf/proto" 12 | ) 13 | 14 | type protobufBinding struct{} 15 | 16 | func (protobufBinding) Name() string { 17 | return "protobuf" 18 | } 19 | 20 | func (b protobufBinding) Bind(req *http.Request, obj interface{}) error { 21 | buf, err := ioutil.ReadAll(req.Body) 22 | if err != nil { 23 | return err 24 | } 25 | return b.BindBody(buf, obj) 26 | } 27 | 28 | func (protobufBinding) BindBody(body []byte, obj interface{}) error { 29 | if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil { 30 | return err 31 | } 32 | // Here it's same to return validate(obj), but util now we can't add 33 | // `binding:""` to the struct which automatically generate by gen-proto 34 | return nil 35 | // return validate(obj) 36 | } 37 | -------------------------------------------------------------------------------- /binding/query.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Manu Martinez-Almeida. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import "net/http" 8 | 9 | type queryBinding struct{} 10 | 11 | func (queryBinding) Name() string { 12 | return "query" 13 | } 14 | 15 | func (queryBinding) Bind(req *http.Request, obj interface{}) error { 16 | values := req.URL.Query() 17 | if err := mapForm(obj, values); err != nil { 18 | return err 19 | } 20 | return validate(obj) 21 | } 22 | -------------------------------------------------------------------------------- /binding/uri.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | type uriBinding struct{} 8 | 9 | func (uriBinding) Name() string { 10 | return "uri" 11 | } 12 | 13 | func (uriBinding) BindUri(m map[string][]string, obj interface{}) error { 14 | if err := mapUri(obj, m); err != nil { 15 | return err 16 | } 17 | return validate(obj) 18 | } 19 | -------------------------------------------------------------------------------- /binding/xml.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "bytes" 9 | "encoding/xml" 10 | "io" 11 | "net/http" 12 | ) 13 | 14 | type xmlBinding struct{} 15 | 16 | func (xmlBinding) Name() string { 17 | return "xml" 18 | } 19 | 20 | func (xmlBinding) Bind(req *http.Request, obj interface{}) error { 21 | return decodeXML(req.Body, obj) 22 | } 23 | 24 | func (xmlBinding) BindBody(body []byte, obj interface{}) error { 25 | return decodeXML(bytes.NewReader(body), obj) 26 | } 27 | func decodeXML(r io.Reader, obj interface{}) error { 28 | decoder := xml.NewDecoder(r) 29 | if err := decoder.Decode(obj); err != nil { 30 | return err 31 | } 32 | return validate(obj) 33 | } 34 | -------------------------------------------------------------------------------- /binding/xml_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestXMLBindingBindBody(t *testing.T) { 15 | var s struct { 16 | Foo string `xml:"foo"` 17 | } 18 | xmlBody := ` 19 | 20 | FOO 21 | ` 22 | err := xmlBinding{}.BindBody([]byte(xmlBody), &s) 23 | require.NoError(t, err) 24 | assert.Equal(t, "FOO", s.Foo) 25 | } 26 | -------------------------------------------------------------------------------- /binding/yaml.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "bytes" 9 | "io" 10 | "net/http" 11 | 12 | "gopkg.in/yaml.v2" 13 | ) 14 | 15 | type yamlBinding struct{} 16 | 17 | func (yamlBinding) Name() string { 18 | return "yaml" 19 | } 20 | 21 | func (yamlBinding) Bind(req *http.Request, obj interface{}) error { 22 | return decodeYAML(req.Body, obj) 23 | } 24 | 25 | func (yamlBinding) BindBody(body []byte, obj interface{}) error { 26 | return decodeYAML(bytes.NewReader(body), obj) 27 | } 28 | 29 | func decodeYAML(r io.Reader, obj interface{}) error { 30 | decoder := yaml.NewDecoder(r) 31 | if err := decoder.Decode(obj); err != nil { 32 | return err 33 | } 34 | return validate(obj) 35 | } 36 | -------------------------------------------------------------------------------- /binding/yaml_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Gin Core Team. All rights reserved. 2 | // Use of this source code is governed by a MIT style 3 | // license that can be found in the LICENSE file. 4 | 5 | package binding 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestYAMLBindingBindBody(t *testing.T) { 15 | var s struct { 16 | Foo string `yaml:"foo"` 17 | } 18 | err := yamlBinding{}.BindBody([]byte("foo: FOO"), &s) 19 | require.NoError(t, err) 20 | assert.Equal(t, "FOO", s.Foo) 21 | } 22 | -------------------------------------------------------------------------------- /buffer/README.md: -------------------------------------------------------------------------------- 1 | ## IoBuffer复用 2 | ``` 3 | // GetIoBuffer returns IoBuffer from pool 4 | func GetIoBuffer(size int) types.IoBuffer { 5 | return ibPool.take(size) 6 | } 7 | 8 | // PutIoBuffer returns IoBuffer to pool 9 | func PutIoBuffer(buf types.IoBuffer) { 10 | if buf.Count(-1) != 0 { 11 | return 12 | } 13 | ibPool.give(buf) 14 | } 15 | ``` 16 | 17 | 18 | ## Byte复用 19 | ``` 20 | // GetBytes returns *[]byte from byteBufferPool 21 | func GetBytes(size int) *[]byte { 22 | p := getByteBufferPool() 23 | return p.take(size) 24 | } 25 | 26 | // PutBytes Put *[]byte to byteBufferPool 27 | func PutBytes(buf *[]byte) { 28 | p := getByteBufferPool() 29 | p.give(buf) 30 | } 31 | ``` 32 | 33 | ## 自定义结构体复用 34 | ##### 请求维度的内存申请复用 35 | * 模板 36 | ``` 37 | package example 38 | 39 | import ( 40 | "context" 41 | 42 | "mosn.io/mosn/pkg/buffer" 43 | "net/http" 44 | ) 45 | 46 | var ins exampleBufferCtx 47 | 48 | // 注册buffer类型到内存复用框架 49 | func init() { 50 | buffer.RegisterBuffer(&ins) 51 | } 52 | 53 | // 需要包含 buffer.TempBufferCtx 到自定义的Ctx, 且要放到第一位 54 | type exampleBufferCtx struct{ 55 | buffer.TempBufferCtx 56 | } 57 | 58 | // 实现New()函数, 用于生成自定义buffer 59 | func (ctx exampleBufferCtx) New() interface{} { 60 | buffer := new(exampleBuffers) 61 | return buffer 62 | } 63 | 64 | // 实现Reset()函数, 用于回收buffer之前,重置buffer内复用的结构体 65 | func (ctx exampleBufferCtx) Reset(i interface{}) { 66 | buf := i.(*exampleBufferCtx) 67 | *buf = exampleBufferCtx{} 68 | } 69 | 70 | // 自定义buffer结构体,包含需要复用的结构体 71 | type exampleBuffers struct { 72 | req http.Request 73 | rsp http.Response 74 | } 75 | 76 | // 通过ctx获取复用buffer 77 | func exampleBuffersByContext(ctx context.Context) *exampleBuffers { 78 | poolCtx := buffer.PoolContext(ctx) 79 | return poolCtx.Find(&ins, nil).(*exampleBuffers) 80 | } 81 | ``` 82 | * 使用方式 83 | ``` 84 | func run(ctx context.Context) { 85 | // 通过ctx获取内存块 86 | buffer := exampleBuffersByContext(ctx) 87 | // 通过指针使用 88 | req := &buffer.req 89 | rsp := &buffer.rsp 90 | } 91 | ``` 92 | 93 | -------------------------------------------------------------------------------- /buffer/buffer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package buffer 19 | 20 | import ( 21 | "context" 22 | "runtime/debug" 23 | "testing" 24 | ) 25 | 26 | //test bufferpool 27 | var mock mock_bufferctx 28 | 29 | type mock_bufferctx struct { 30 | TempBufferCtx 31 | } 32 | 33 | func (ctx *mock_bufferctx) New() interface{} { 34 | return new(mock_buffers) 35 | } 36 | 37 | func (ctx *mock_bufferctx) Reset(x interface{}) { 38 | buf := x.(*mock_buffers) 39 | *buf = mock_buffers{} 40 | } 41 | 42 | type mock_buffers struct { 43 | m [10]int 44 | } 45 | 46 | func mock_BuffersByContext(ctx context.Context) *mock_buffers { 47 | poolCtx := PoolContext(ctx) 48 | return poolCtx.Find(&mock, nil).(*mock_buffers) 49 | } 50 | 51 | func Test_BufferPool_Register(t *testing.T) { 52 | defer func() { 53 | if p := recover(); p != nil { 54 | t.Log("expected panic") 55 | } 56 | }() 57 | ctx1 := NewBufferPoolContext(context.Background()) 58 | mock_BuffersByContext(ctx1) 59 | t.Errorf("should panic") 60 | 61 | } 62 | 63 | func Test_BufferPool(t *testing.T) { 64 | // close GC 65 | debug.SetGCPercent(100000) 66 | var null [10]int 67 | 68 | RegisterBuffer(&mock) 69 | 70 | // first 71 | ctx1 := NewBufferPoolContext(context.Background()) 72 | buf1 := mock_BuffersByContext(ctx1) 73 | for i := 0; i < 10; i++ { 74 | buf1.m[i] = i 75 | } 76 | t.Log(buf1.m) 77 | PoolContext(ctx1).Give() 78 | if buf1.m != null { 79 | t.Errorf("test bufferPool Error: Reset() failed") 80 | } 81 | t.Log(buf1.m) 82 | t.Logf("%p", buf1) 83 | 84 | // second 85 | ctx2 := NewBufferPoolContext(context.Background()) 86 | buf2 := mock_BuffersByContext(ctx2) 87 | t.Logf("%p", buf2) 88 | if buf1 != buf2 { 89 | t.Errorf("test bufferPool Error: Reuse failed") 90 | } 91 | 92 | debug.SetGCPercent(100) 93 | } 94 | 95 | func Test_TransmitBufferPoolContext(t *testing.T) { 96 | RegisterBuffer(&mock) 97 | var null [10]int 98 | 99 | // first 100 | ctx1 := NewBufferPoolContext(context.Background()) 101 | buf1 := mock_BuffersByContext(ctx1) 102 | for i := 0; i < 10; i++ { 103 | buf1.m[i] = i 104 | } 105 | 106 | // second 107 | ctx2 := NewBufferPoolContext(context.Background()) 108 | buf2 := mock_BuffersByContext(ctx2) 109 | for i := 0; i < 10; i++ { 110 | buf2.m[i] = i 111 | } 112 | 113 | TransmitBufferPoolContext(ctx2, ctx1) 114 | 115 | bv := PoolContext(ctx2) 116 | bv.Give() 117 | 118 | if buf1.m != null { 119 | t.Errorf("test bufferPool Error: Transmit failed") 120 | } 121 | 122 | if buf2.m != null { 123 | t.Errorf("test bufferPool Error: Transmit failed") 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /buffer/bytebuffer_ctx.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | //nolint 19 | package buffer 20 | 21 | import ( 22 | "context" 23 | ) 24 | 25 | var ins = ByteBufferCtx{} 26 | 27 | func init() { 28 | RegisterBuffer(&ins) 29 | } 30 | 31 | type ByteBufferCtx struct { 32 | TempBufferCtx 33 | } 34 | 35 | func (ctx ByteBufferCtx) New() interface{} { 36 | return NewByteBufferPoolContainer() 37 | } 38 | 39 | func (ctx ByteBufferCtx) Reset(i interface{}) { 40 | p := i.(*ByteBufferPoolContainer) 41 | p.Reset() 42 | } 43 | 44 | // GetBytesByContext returns []byte from byteBufferPool by context 45 | func GetBytesByContext(context context.Context, size int) *[]byte { 46 | p := PoolContext(context).Find(&ins, nil).(*ByteBufferPoolContainer) 47 | return p.Take(size) 48 | } 49 | -------------------------------------------------------------------------------- /buffer/bytebuffer_ctx_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package buffer 18 | 19 | import ( 20 | "context" 21 | "testing" 22 | ) 23 | 24 | func Test_ByteBuffer(t *testing.T) { 25 | ctx := NewBufferPoolContext(context.Background()) 26 | b := GetBytesByContext(ctx, 1000) 27 | if len(*b) != 1000 { 28 | t.Errorf("bytes len should %d", 1000) 29 | } 30 | if cap(*b) != 1024 { 31 | t.Errorf("bytes cap should %d", 1024) 32 | } 33 | bv := PoolContext(ctx) 34 | bv.Give() 35 | } 36 | -------------------------------------------------------------------------------- /buffer/bytebuffer_pool.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package buffer 19 | 20 | import ( 21 | "sync" 22 | ) 23 | 24 | const minShift = 6 25 | const maxShift = 27 26 | const errSlot = -1 27 | 28 | var bbPool *byteBufferPool 29 | 30 | func init() { 31 | bbPool = newByteBufferPool() 32 | } 33 | 34 | // byteBufferPool is []byte pools 35 | type byteBufferPool struct { 36 | minShift int 37 | minSize int 38 | maxSize int 39 | 40 | pool []*bufferSlot 41 | } 42 | 43 | type bufferSlot struct { 44 | defaultSize int 45 | pool sync.Pool 46 | } 47 | 48 | // newByteBufferPool returns byteBufferPool 49 | func newByteBufferPool() *byteBufferPool { 50 | p := &byteBufferPool{ 51 | minShift: minShift, 52 | minSize: 1 << minShift, 53 | maxSize: 1 << maxShift, 54 | } 55 | for i := 0; i <= maxShift-minShift; i++ { 56 | slab := &bufferSlot{ 57 | defaultSize: 1 << (uint)(i+minShift), 58 | } 59 | p.pool = append(p.pool, slab) 60 | } 61 | 62 | return p 63 | } 64 | 65 | func (p *byteBufferPool) slot(size int) int { 66 | if size > p.maxSize { 67 | return errSlot 68 | } 69 | slot := 0 70 | shift := 0 71 | if size > p.minSize { 72 | size-- 73 | for size > 0 { 74 | size = size >> 1 75 | shift++ 76 | } 77 | slot = shift - p.minShift 78 | } 79 | 80 | return slot 81 | } 82 | 83 | func newBytes(size int) []byte { 84 | return make([]byte, size) 85 | } 86 | 87 | // take returns *[]byte from byteBufferPool 88 | func (p *byteBufferPool) take(size int) *[]byte { 89 | slot := p.slot(size) 90 | if slot == errSlot { 91 | b := newBytes(size) 92 | return &b 93 | } 94 | v := p.pool[slot].pool.Get() 95 | if v == nil { 96 | b := newBytes(p.pool[slot].defaultSize) 97 | b = b[0:size] 98 | return &b 99 | } 100 | b := v.(*[]byte) 101 | *b = (*b)[0:size] 102 | return b 103 | } 104 | 105 | // give returns *[]byte to byteBufferPool 106 | func (p *byteBufferPool) give(buf *[]byte) { 107 | if buf == nil { 108 | return 109 | } 110 | size := cap(*buf) 111 | slot := p.slot(size) 112 | if slot == errSlot { 113 | return 114 | } 115 | if size != int(p.pool[slot].defaultSize) { 116 | return 117 | } 118 | p.pool[slot].pool.Put(buf) 119 | } 120 | 121 | type ByteBufferPoolContainer struct { 122 | bytes []*[]byte 123 | *byteBufferPool 124 | } 125 | 126 | func NewByteBufferPoolContainer() *ByteBufferPoolContainer { 127 | return &ByteBufferPoolContainer{ 128 | byteBufferPool: bbPool, 129 | } 130 | } 131 | 132 | func (c *ByteBufferPoolContainer) Reset() { 133 | for _, buf := range c.bytes { 134 | c.give(buf) 135 | } 136 | c.bytes = c.bytes[:0] 137 | } 138 | 139 | func (c *ByteBufferPoolContainer) Take(size int) *[]byte { 140 | buf := c.take(size) 141 | c.bytes = append(c.bytes, buf) 142 | return buf 143 | } 144 | 145 | // GetBytes returns *[]byte from byteBufferPool 146 | func GetBytes(size int) *[]byte { 147 | return bbPool.take(size) 148 | } 149 | 150 | // PutBytes Put *[]byte to byteBufferPool 151 | func PutBytes(buf *[]byte) { 152 | bbPool.give(buf) 153 | } 154 | -------------------------------------------------------------------------------- /buffer/bytebuffer_pool_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package buffer 19 | 20 | import ( 21 | "math/rand" 22 | "testing" 23 | "time" 24 | ) 25 | 26 | func init() { 27 | rand.Seed(time.Now().UnixNano()) 28 | } 29 | 30 | func intRange(min, max int) int { 31 | return rand.Intn(max-min) + min 32 | } 33 | 34 | func intN(n int) int { 35 | return rand.Intn(n) + 1 36 | } 37 | 38 | func TestByteBufferPoolSmallBytes(t *testing.T) { 39 | pool := newByteBufferPool() 40 | 41 | for i := 0; i < 1024; i++ { 42 | size := intN(1 << minShift) 43 | bp := pool.take(size) 44 | 45 | if cap(*bp) != 1< 0 { 60 | return nil 61 | } else if count < 0 { 62 | return errors.New("PutIoBuffer duplicate") 63 | } 64 | 65 | if pb, _ := buf.(*pipe); pb != nil { 66 | buf = pb.IoBuffer 67 | } 68 | p.give(buf) 69 | return nil 70 | } 71 | 72 | // GetIoBuffer is a wrapper for ibPool 73 | func GetIoBuffer(size int) IoBuffer { 74 | return ibPool.GetIoBuffer(size) 75 | } 76 | 77 | // NewIoBuffer is an alias for GetIoBuffer 78 | func NewIoBuffer(size int) IoBuffer { 79 | return ibPool.GetIoBuffer(size) 80 | } 81 | 82 | // PutIoBuffer is a a wrapper for ibPool 83 | func PutIoBuffer(buf IoBuffer) error { 84 | err := ibPool.PutIoBuffer(buf) 85 | if err != nil { 86 | logFunc(err.Error()) 87 | } 88 | return err 89 | } 90 | -------------------------------------------------------------------------------- /buffer/iobuffer_pool_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package buffer 19 | 20 | import ( 21 | "testing" 22 | ) 23 | 24 | func TestIoBufferPoolWithCount(t *testing.T) { 25 | buf := GetIoBuffer(0) 26 | bytes := []byte{0x00, 0x01, 0x02, 0x03, 0x04} 27 | buf.Write(bytes) 28 | if buf.Len() != len(bytes) { 29 | t.Error("iobuffer len not match write bytes' size") 30 | } 31 | // Add a count, need put twice to free buffer 32 | buf.Count(1) 33 | PutIoBuffer(buf) 34 | if buf.Len() != len(bytes) { 35 | t.Error("iobuffer expected put ignore") 36 | } 37 | PutIoBuffer(buf) 38 | if buf.Len() != 0 { 39 | t.Error("iobuffer expected put success") 40 | } 41 | } 42 | 43 | func TestIoBufferPooPutduplicate(t *testing.T) { 44 | buf := GetIoBuffer(0) 45 | err := PutIoBuffer(buf) 46 | if err != nil { 47 | t.Errorf("iobuffer put error:%v", err) 48 | } 49 | err = PutIoBuffer(buf) 50 | if err == nil { 51 | t.Errorf("iobuffer should be error: Put IoBuffer duplicate") 52 | } 53 | } 54 | 55 | func Test_IoBufferPool_Slice_Increase(t *testing.T) { 56 | str := "IoBufferPool Test" 57 | // []byte slice increase 58 | buffer := GetIoBuffer(1) 59 | buffer.Write([]byte(str)) 60 | 61 | b := make([]byte, 32) 62 | _, err := buffer.Read(b) 63 | 64 | if err != nil { 65 | t.Fatal(err) 66 | } 67 | 68 | PutIoBuffer(buffer) 69 | 70 | if string(b[:len(str)]) != str { 71 | t.Fatal("IoBufferPool Test Slice Increase Failed") 72 | } 73 | t.Log("IoBufferPool Test Slice Increase Sucess") 74 | } 75 | func Test_IoBufferPool_Alloc_Free(t *testing.T) { 76 | str := "IoBufferPool Test" 77 | buffer := GetIoBuffer(100) 78 | buffer.Free() 79 | buffer.Alloc(1) 80 | buffer.Write([]byte(str)) 81 | 82 | b := make([]byte, 32) 83 | _, err := buffer.Read(b) 84 | 85 | if err != nil { 86 | t.Fatal(err) 87 | } 88 | 89 | PutIoBuffer(buffer) 90 | 91 | if string(b[:len(str)]) != str { 92 | t.Fatal("IoBufferPool Test Alloc Free Failed") 93 | } 94 | t.Log("IoBufferPool Test Alloc Free Sucess") 95 | } 96 | 97 | func Test_IoBufferPool(t *testing.T) { 98 | str := "IoBufferPool Test" 99 | buffer := GetIoBuffer(len(str)) 100 | buffer.Write([]byte(str)) 101 | 102 | b := make([]byte, 32) 103 | _, err := buffer.Read(b) 104 | 105 | if err != nil { 106 | t.Fatal(err) 107 | } 108 | 109 | PutIoBuffer(buffer) 110 | 111 | if string(b[:len(str)]) != str { 112 | t.Fatal("IoBufferPool Test Failed") 113 | } 114 | t.Log("IoBufferPool Test Sucess") 115 | } 116 | 117 | // Test IoBufferPool 118 | const Size = 2048 119 | 120 | var Buffer [Size]byte 121 | 122 | func testiobufferpool() IoBuffer { 123 | b := GetIoBuffer(Size) 124 | b.Write(Buffer[:]) 125 | return b 126 | } 127 | 128 | func testiobuffer() IoBuffer { 129 | b := newIoBuffer(Size) 130 | b.Write(Buffer[:]) 131 | return b 132 | } 133 | 134 | func BenchmarkIoBufferPool(b *testing.B) { 135 | for i := 0; i < b.N; i++ { 136 | buf := testiobufferpool() 137 | PutIoBuffer(buf) 138 | } 139 | } 140 | 141 | func BenchmarkIoBuffer(b *testing.B) { 142 | for i := 0; i < b.N; i++ { 143 | testiobuffer() 144 | } 145 | } 146 | 147 | func BenchmarkNewIoBuffer(b *testing.B) { 148 | for i := 0; i < b.N; i++ { 149 | buf := testiobuffer() 150 | PutIoBuffer(buf) 151 | } 152 | } 153 | 154 | -------------------------------------------------------------------------------- /buffer/log.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package buffer 19 | 20 | import ( 21 | "fmt" 22 | "os" 23 | ) 24 | 25 | // logFunc record buffer's error log, default to std error. 26 | // User can be overwrite it with any log implementation function 27 | // For example, use mosn.io/pkg/log logger.Errorf overwrite it. 28 | var logFunc = func(msg string) { 29 | fmt.Fprintf(os.Stderr, "%s\n", msg) 30 | } 31 | 32 | // SetLogFunc use f overwrite logFunc. 33 | func SetLogFunc(f func(msg string)) { 34 | logFunc = f 35 | } 36 | -------------------------------------------------------------------------------- /buffer/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package buffer 19 | 20 | import ( 21 | "mosn.io/api" 22 | ) 23 | 24 | // keep this alias for compatbile. 25 | // if you write new code, use api.IoBuffer instead. 26 | type IoBuffer = api.IoBuffer 27 | -------------------------------------------------------------------------------- /build/contrib/builder/binary/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.18 2 | -------------------------------------------------------------------------------- /etc/script/report.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | echo "" > coverage.txt 5 | 6 | for d in $(go list ./...); do 7 | echo "--------Run test package: $d" 8 | go test -v -coverprofile=profile.out -covermode=atomic $d 9 | echo "--------Finish test package: $d" 10 | if [ -f profile.out ]; then 11 | cat profile.out >> coverage.txt 12 | rm profile.out 13 | fi 14 | done 15 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module mosn.io/pkg 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/dubbogo/getty v1.3.4 7 | github.com/dubbogo/go-zookeeper v1.0.3 8 | github.com/dubbogo/gost v1.11.16 9 | github.com/go-playground/validator/v10 v10.2.0 10 | github.com/golang/protobuf v1.5.0 11 | github.com/hashicorp/go-syslog v1.0.0 12 | github.com/jinzhu/copier v0.3.2 13 | github.com/magiconair/properties v1.8.1 14 | github.com/pkg/errors v0.9.1 15 | github.com/satori/go.uuid v1.2.0 16 | github.com/stretchr/testify v1.7.0 17 | github.com/ugorji/go/codec v1.1.7 18 | github.com/valyala/fasthttp v1.40.0 19 | go.uber.org/atomic v1.7.0 20 | go.uber.org/zap v1.16.0 21 | golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 22 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 23 | gopkg.in/yaml.v2 v2.4.0 24 | mosn.io/api v1.6.0 25 | ) 26 | 27 | require ( 28 | github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect 29 | github.com/andybalholm/brotli v1.0.4 // indirect 30 | github.com/davecgh/go-spew v1.1.1 // indirect 31 | github.com/go-ole/go-ole v1.2.4 // indirect 32 | github.com/go-playground/locales v0.13.0 // indirect 33 | github.com/go-playground/universal-translator v0.17.0 // indirect 34 | github.com/golang/snappy v0.0.1 // indirect 35 | github.com/gorilla/websocket v1.4.2 // indirect 36 | github.com/juju/errors v0.0.0-20200330140219-3fe23663418f // indirect 37 | github.com/k0kubun/pp v3.0.1+incompatible // indirect 38 | github.com/klauspost/compress v1.15.11 // indirect 39 | github.com/kr/pretty v0.3.0 // indirect 40 | github.com/leodido/go-urn v1.2.0 // indirect 41 | github.com/mattn/go-colorable v0.1.7 // indirect 42 | github.com/mattn/go-isatty v0.0.12 // indirect 43 | github.com/pmezard/go-difflib v1.0.0 // indirect 44 | github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect 45 | github.com/rogpeppe/go-internal v1.8.0 // indirect 46 | github.com/shirou/gopsutil v3.20.11+incompatible // indirect 47 | github.com/valyala/bytebufferpool v1.0.0 // indirect 48 | go.uber.org/multierr v1.5.0 // indirect 49 | google.golang.org/protobuf v1.26.0-rc.1 // indirect 50 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 51 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 52 | ) 53 | -------------------------------------------------------------------------------- /header/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package header 19 | 20 | import "mosn.io/api" 21 | 22 | // CommonHeader wrapper for map[string]string, is an implementation of api.HeaderMap 23 | type CommonHeader map[string]string 24 | 25 | // Get value of key 26 | func (h CommonHeader) Get(key string) (value string, ok bool) { 27 | value, ok = h[key] 28 | return 29 | } 30 | 31 | // Set key-value pair in header map, the previous pair will be replaced if exists 32 | func (h CommonHeader) Set(key string, value string) { 33 | h[key] = value 34 | } 35 | 36 | // Add value for given key. 37 | // Multiple headers with the same key may be added with this function. 38 | // Use Set for setting a single header for the given key. 39 | func (h CommonHeader) Add(key string, value string) { 40 | panic("not supported") 41 | } 42 | 43 | // Del delete pair of specified key 44 | func (h CommonHeader) Del(key string) { 45 | delete(h, key) 46 | } 47 | 48 | // Range calls f sequentially for each key and value present in the map. 49 | // If f returns false, range stops the iteration. 50 | func (h CommonHeader) Range(f func(key, value string) bool) { 51 | for k, v := range h { 52 | // stop if f return false 53 | if !f(k, v) { 54 | break 55 | } 56 | } 57 | } 58 | 59 | // Clone used to deep copy header's map 60 | func (h CommonHeader) Clone() api.HeaderMap { 61 | copy := make(map[string]string) 62 | 63 | for k, v := range h { 64 | copy[k] = v 65 | } 66 | 67 | return CommonHeader(copy) 68 | } 69 | 70 | func (h CommonHeader) ByteSize() uint64 { 71 | var size uint64 72 | 73 | for k, v := range h { 74 | size += uint64(len(k) + len(v)) 75 | } 76 | return size 77 | } 78 | -------------------------------------------------------------------------------- /internal/context/context.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package context 19 | 20 | import "context" 21 | 22 | // ContextKey type 23 | type Key int 24 | 25 | // Context key types(built-in) 26 | const ( 27 | KeyBufferPoolCtx Key = iota 28 | KeyVariables 29 | KeyEnd 30 | ) 31 | 32 | type valueCtx struct { 33 | context.Context 34 | 35 | builtin [KeyEnd]interface{} 36 | } 37 | 38 | func (c *valueCtx) Value(key interface{}) interface{} { 39 | if contextKey, ok := key.(Key); ok { 40 | return c.builtin[contextKey] 41 | } 42 | 43 | return c.Context.Value(key) 44 | } 45 | -------------------------------------------------------------------------------- /internal/context/context_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package context 19 | 20 | import ( 21 | "context" 22 | "math/rand" 23 | "os" 24 | "testing" 25 | 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/require" 28 | ) 29 | 30 | const testNodeNum = 10 31 | 32 | var randomTable [testNodeNum]Key 33 | 34 | func TestMain(m *testing.M) { 35 | // init random table per-run for all benchmark scenario, so the performance will not be affected by random functions. 36 | for i := 0; i < testNodeNum; i++ { 37 | randomTable[i] = Key(rand.Intn(int(KeyEnd))) 38 | } 39 | os.Exit(m.Run()) 40 | } 41 | 42 | func TestContext(t *testing.T) { 43 | ctx := context.Background() 44 | // Test Set 45 | expected := "test value" 46 | ctx = WithValue(ctx, KeyBufferPoolCtx, expected) 47 | // Test Get 48 | vi := ctx.Value(KeyBufferPoolCtx) 49 | value, ok := vi.(string) 50 | require.True(t, ok) 51 | require.Equal(t, expected, value) 52 | 53 | // parent is valueCtx, withValue test 54 | e2 := []string{"1", "2"} 55 | ctx2 := WithValue(ctx, KeyVariables, e2) 56 | vi2 := ctx2.Value(KeyVariables) 57 | value2, ok := vi2.([]string) 58 | require.True(t, ok) 59 | require.Len(t, value2, 2) 60 | 61 | // mosn context is different from the std context 62 | // if you add a k v in the child context 63 | // the parent context will also change 64 | pvi2 := ctx.Value(KeyVariables) 65 | pvalue2, ok := pvi2.([]string) 66 | require.True(t, ok) 67 | require.Len(t, pvalue2, 2) 68 | 69 | // not context type key, should go to the other branch of ctx.Value() 70 | invalid_value := ctx.Value("test") 71 | assert.Nil(t, invalid_value) 72 | 73 | // another way to get 74 | vi3 := Get(ctx, KeyBufferPoolCtx) 75 | value3, ok := vi3.(string) 76 | require.True(t, ok) 77 | require.Equal(t, expected, value3) 78 | 79 | // std context 80 | stdv := Get(context.TODO(), KeyVariables) 81 | assert.Nil(t, stdv) 82 | 83 | // Test Clone 84 | ctxNew := Clone(ctx) 85 | 86 | nvi := ctxNew.Value(KeyBufferPoolCtx) 87 | require.NotNil(t, nvi) 88 | 89 | // clone std context 90 | ctxBaseNew := context.TODO() 91 | ctxNew = Clone(ctxBaseNew) 92 | assert.Equal(t, ctxNew, ctxBaseNew) 93 | } 94 | 95 | func BenchmarkCompatibleGet(b *testing.B) { 96 | ctx := context.Background() 97 | for i := 0; i < testNodeNum; i++ { 98 | ctx = WithValue(ctx, randomTable[i], struct{}{}) 99 | } 100 | 101 | b.ResetTimer() 102 | 103 | for i := 0; i < b.N; i++ { 104 | // get all index 105 | for i := 0; i < testNodeNum; i++ { 106 | ctx.Value(randomTable[i]) 107 | } 108 | } 109 | 110 | } 111 | 112 | func BenchmarkGet(b *testing.B) { 113 | ctx := context.Background() 114 | for i := 0; i < testNodeNum; i++ { 115 | ctx = WithValue(ctx, randomTable[i], struct{}{}) 116 | } 117 | 118 | b.ResetTimer() 119 | 120 | for i := 0; i < b.N; i++ { 121 | // get all index 122 | for i := 0; i < testNodeNum; i++ { 123 | Get(ctx, randomTable[i]) 124 | } 125 | } 126 | 127 | } 128 | 129 | func BenchmarkSet(b *testing.B) { 130 | // based on 10 k-v 131 | 132 | for i := 0; i < b.N; i++ { 133 | ctx := context.Background() 134 | for i := 0; i < testNodeNum; i++ { 135 | ctx = WithValue(ctx, randomTable[i], struct{}{}) 136 | } 137 | } 138 | } 139 | 140 | func BenchmarkRawGet(b *testing.B) { 141 | ctx := context.Background() 142 | for i := 0; i < testNodeNum; i++ { 143 | ctx = context.WithValue(ctx, randomTable[i], struct{}{}) 144 | } 145 | 146 | b.ResetTimer() 147 | 148 | for i := 0; i < b.N; i++ { 149 | // get all index 150 | for i := 0; i < testNodeNum; i++ { 151 | ctx.Value(randomTable[i]) 152 | } 153 | } 154 | } 155 | 156 | func BenchmarkRawSet(b *testing.B) { 157 | // based on 10 k-v 158 | for i := 0; i < b.N; i++ { 159 | ctx := context.Background() 160 | for i := 0; i < testNodeNum; i++ { 161 | ctx = context.WithValue(ctx, randomTable[i], struct{}{}) 162 | } 163 | 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /internal/context/wrapper.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | //nolint 19 | package context 20 | 21 | import "context" 22 | 23 | // Get is a wrapper for context.Value 24 | func Get(ctx context.Context, key Key) interface{} { 25 | if mosnCtx, ok := ctx.(*valueCtx); ok { 26 | return mosnCtx.builtin[key] 27 | } 28 | 29 | return ctx.Value(key) 30 | } 31 | 32 | // This Function should not be used along with the official context.WithValue !! 33 | // The following context topology will leads to existed pair {'foo':'bar'} NOT FOUND, because recursive lookup for 34 | // key-type=types.ContextKey is not supported by mosn.valueCtx. 35 | // topology: context.Background -> mosn.valueCtx{'foo':'bar'} -> context.valueCtx -> mosn.valueCtx{'hmm':'haa'} 36 | 37 | // WithValue add the given key-value pair into the existed value context, 38 | // or create a new value context which contains the pair. 39 | func WithValue(parent context.Context, key Key, value interface{}) context.Context { 40 | if mosnCtx, ok := parent.(*valueCtx); ok { 41 | mosnCtx.builtin[key] = value 42 | return mosnCtx 43 | } 44 | 45 | // create new valueCtx 46 | mosnCtx := &valueCtx{Context: parent} 47 | mosnCtx.builtin[key] = value 48 | return mosnCtx 49 | } 50 | 51 | // Clone copy the origin mosn value context(if it is), and return new one 52 | func Clone(parent context.Context) context.Context { 53 | if mosnCtx, ok := parent.(*valueCtx); ok { 54 | clone := &valueCtx{Context: mosnCtx} 55 | // array copy assign 56 | clone.builtin = mosnCtx.builtin 57 | return clone 58 | } 59 | return parent 60 | } 61 | -------------------------------------------------------------------------------- /log/buffer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package log 19 | 20 | import ( 21 | "mosn.io/api" 22 | "mosn.io/pkg/buffer" 23 | ) 24 | 25 | // logPool stores buffers for log. 26 | // we use a separate pool to avoid log data impacting others 27 | var logPool buffer.IoBufferPool 28 | 29 | // GetLogBuffer returns a LogBuffer from logPool 30 | func GetLogBuffer(size int) LogBuffer { 31 | return LogBuffer{ 32 | logbuffer: logPool.GetIoBuffer(size), 33 | } 34 | } 35 | 36 | // PutLogBuffer puts a LogBuffer back to logPool 37 | func PutLogBuffer(buf LogBuffer) error { 38 | return logPool.PutIoBuffer(buf.buffer()) 39 | } 40 | 41 | // logbuffer is renamed by api.IoBuffer, makes LogBuffer contains an unexported anonymous member 42 | type logbuffer api.IoBuffer 43 | 44 | // LogBuffer is an implementation of api.IoBuffer that used in log package, to distinguish it from api.IoBuffer 45 | // nolint 46 | type LogBuffer struct { 47 | logbuffer 48 | } 49 | 50 | // nolint 51 | var _ api.IoBuffer = LogBuffer{} 52 | 53 | func (lb LogBuffer) buffer() api.IoBuffer { 54 | return lb.logbuffer 55 | } 56 | -------------------------------------------------------------------------------- /log/buffer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package log 19 | 20 | import ( 21 | "fmt" 22 | "testing" 23 | 24 | "github.com/stretchr/testify/require" 25 | "mosn.io/api" 26 | ) 27 | 28 | func TestLogBufferPool(t *testing.T) { 29 | buf := GetLogBuffer(0) 30 | bufaddr := fmt.Sprintf("%p", buf.buffer()) 31 | PutLogBuffer(buf) 32 | buf2 := GetLogBuffer(0) 33 | buf2addr := fmt.Sprintf("%p", buf2.buffer()) 34 | require.Equal(t, bufaddr, buf2addr) 35 | } 36 | 37 | // use an interface to benchmark 38 | // use struct directly is better than use an interface or a pointer 39 | type iLogBuf interface { 40 | buffer() api.IoBuffer 41 | } 42 | 43 | func getILogBuf() iLogBuf { 44 | return GetLogBuffer(0) 45 | } 46 | 47 | func getILogBufByPointer() iLogBuf { 48 | return getLogBufferPointer() 49 | } 50 | 51 | func putILogBuf(buf iLogBuf) { 52 | logPool.PutIoBuffer(buf.buffer()) 53 | } 54 | 55 | func getLogBufferPointer() *LogBuffer { 56 | return &LogBuffer{ 57 | logbuffer: logPool.GetIoBuffer(0), 58 | } 59 | } 60 | 61 | func putLogBufferPointer(bp *LogBuffer) { 62 | logPool.PutIoBuffer(bp.buffer()) 63 | } 64 | 65 | func BenchmarkLogBuffer(b *testing.B) { 66 | // use channel write & read to mock log print 67 | b.Run("raw iobuffer", func(b *testing.B) { 68 | ch := make(chan api.IoBuffer, 1) 69 | for i := 0; i < b.N; i++ { 70 | func(bf api.IoBuffer) { 71 | ch <- bf 72 | buf := <-ch 73 | logPool.PutIoBuffer(buf) 74 | }(logPool.GetIoBuffer(0)) 75 | } 76 | }) 77 | 78 | b.Run("struct", func(b *testing.B) { 79 | ch := make(chan LogBuffer, 1) 80 | for i := 0; i < b.N; i++ { 81 | func(bf LogBuffer) { 82 | ch <- bf 83 | buf := <-ch 84 | PutLogBuffer(buf) 85 | }(GetLogBuffer(0)) 86 | } 87 | }) 88 | 89 | b.Run("pointer", func(b *testing.B) { 90 | ch := make(chan *LogBuffer, 1) 91 | for i := 0; i < b.N; i++ { 92 | func(bf *LogBuffer) { 93 | ch <- bf 94 | bp := <-ch 95 | putLogBufferPointer(bp) 96 | }(getLogBufferPointer()) 97 | } 98 | }) 99 | 100 | b.Run("struct interface", func(b *testing.B) { 101 | ch := make(chan iLogBuf, 1) 102 | for i := 0; i < b.N; i++ { 103 | func(bf iLogBuf) { 104 | ch <- bf 105 | buf := <-ch 106 | putILogBuf(buf) 107 | }(getILogBuf()) 108 | } 109 | }) 110 | 111 | b.Run("pointer interface", func(b *testing.B) { 112 | ch := make(chan iLogBuf, 1) 113 | for i := 0; i < b.N; i++ { 114 | func(bf iLogBuf) { 115 | ch <- bf 116 | buf := <-ch 117 | putILogBuf(buf) 118 | }(getILogBufByPointer()) 119 | } 120 | }) 121 | } 122 | -------------------------------------------------------------------------------- /log/contextlog.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package log 19 | 20 | import "context" 21 | 22 | var DefaultContextLogger ContextLogger 23 | 24 | func init() { 25 | logger, err := GetOrCreateLogger("", nil) 26 | if err != nil { 27 | panic("init default logger error: " + err.Error()) 28 | } 29 | DefaultContextLogger = &SimpleContextLog{ 30 | SimpleErrorLog: &SimpleErrorLog{ 31 | Logger: logger, 32 | Level: INFO, 33 | }, 34 | } 35 | } 36 | 37 | // SimpleComtextLog is a wrapper of SimpleErrorLog 38 | type SimpleContextLog struct { 39 | *SimpleErrorLog 40 | } 41 | 42 | func (l *SimpleContextLog) Infof(ctx context.Context, format string, args ...interface{}) { 43 | l.SimpleErrorLog.Infof(format, args...) 44 | } 45 | 46 | func (l *SimpleContextLog) Debugf(ctx context.Context, format string, args ...interface{}) { 47 | l.SimpleErrorLog.Debugf(format, args...) 48 | } 49 | 50 | func (l *SimpleContextLog) Tracef(ctx context.Context, format string, args ...interface{}) { 51 | l.SimpleErrorLog.Tracef(format, args...) 52 | } 53 | 54 | func (l *SimpleContextLog) Warnf(ctx context.Context, format string, args ...interface{}) { 55 | l.SimpleErrorLog.Infof(format, args...) 56 | } 57 | 58 | func (l *SimpleContextLog) Errorf(ctx context.Context, format string, args ...interface{}) { 59 | l.SimpleErrorLog.Infof(format, args...) 60 | } 61 | 62 | func (l *SimpleContextLog) Alertf(ctx context.Context, alert string, format string, args ...interface{}) { 63 | l.SimpleErrorLog.Infof(format, args...) 64 | } 65 | 66 | func (l *SimpleContextLog) Fatalf(ctx context.Context, format string, args ...interface{}) { 67 | l.SimpleErrorLog.Infof(format, args...) 68 | } 69 | -------------------------------------------------------------------------------- /log/errorlog.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package log 19 | 20 | import "mosn.io/pkg/utils" 21 | 22 | var DefaultLogger ErrorLogger 23 | 24 | func init() { 25 | logger, err := GetOrCreateLogger("", nil) 26 | if err != nil { 27 | panic("init default logger error: " + err.Error()) 28 | } 29 | DefaultLogger = &SimpleErrorLog{ 30 | Logger: logger, 31 | Level: INFO, 32 | } 33 | } 34 | 35 | type SimpleErrorLog struct { 36 | *Logger 37 | Formatter func(lv string, alert string, format string) string 38 | Level Level 39 | } 40 | 41 | func DefaultFormatter(lv string, alert string, format string) string { 42 | if alert == "" { 43 | return utils.CacheTime() + " " + lv + " " + format 44 | } 45 | return utils.CacheTime() + " " + lv + " [" + alert + "] " + format 46 | } 47 | 48 | func (l *SimpleErrorLog) Alertf(alert string, format string, args ...interface{}) { 49 | if l.disable { 50 | return 51 | } 52 | if l.Level >= ERROR { 53 | var fs string 54 | if l.Formatter != nil { 55 | fs = l.Formatter(ErrorPre, alert, format) 56 | } else { 57 | fs = DefaultFormatter(ErrorPre, alert, format) 58 | } 59 | l.Printf(fs, args...) 60 | } 61 | } 62 | func (l *SimpleErrorLog) levelf(lv string, format string, args ...interface{}) { 63 | if l.disable { 64 | return 65 | } 66 | fs := "" 67 | if l.Formatter != nil { 68 | fs = l.Formatter(lv, "", format) 69 | } else { 70 | fs = DefaultFormatter(lv, "", format) 71 | } 72 | l.Printf(fs, args...) 73 | } 74 | 75 | func (l *SimpleErrorLog) Infof(format string, args ...interface{}) { 76 | if l.Level >= INFO { 77 | l.levelf(InfoPre, format, args...) 78 | } 79 | } 80 | 81 | func (l *SimpleErrorLog) Debugf(format string, args ...interface{}) { 82 | if l.Level >= DEBUG { 83 | l.levelf(DebugPre, format, args...) 84 | } 85 | } 86 | 87 | func (l *SimpleErrorLog) Warnf(format string, args ...interface{}) { 88 | if l.Level >= WARN { 89 | l.levelf(WarnPre, format, args...) 90 | } 91 | } 92 | 93 | func (l *SimpleErrorLog) Errorf(format string, args ...interface{}) { 94 | if l.Level >= ERROR { 95 | l.levelf(ErrorPre, format, args...) 96 | } 97 | } 98 | 99 | func (l *SimpleErrorLog) Tracef(format string, args ...interface{}) { 100 | if l.Level >= TRACE { 101 | l.levelf(TracePre, format, args...) 102 | } 103 | } 104 | 105 | func (l *SimpleErrorLog) Fatalf(format string, args ...interface{}) { 106 | var s string 107 | if l.Formatter != nil { 108 | s = l.Formatter(FatalPre, "", format) 109 | } else { 110 | s = DefaultFormatter(FatalPre, "", format) 111 | } 112 | l.Logger.Fatalf(s, args...) 113 | } 114 | 115 | func (l *SimpleErrorLog) SetLogLevel(level Level) { 116 | l.Level = level 117 | } 118 | 119 | func (l *SimpleErrorLog) GetLogLevel() Level { 120 | return l.Level 121 | } 122 | -------------------------------------------------------------------------------- /log/escape_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package log 19 | 20 | import ( 21 | "testing" 22 | ) 23 | 24 | func BenchmarkWrapper(b *testing.B) { 25 | lg := &SimpleErrorLog{ 26 | Logger: &Logger{ 27 | output: "stdout", 28 | roller: DefaultRoller(), 29 | }, 30 | Level: ERROR, 31 | } 32 | for n := 0; n < b.N; n++ { 33 | lg.Debugf("say something:%s%s", "hello", expr("world", "!")) 34 | } 35 | 36 | } 37 | 38 | func BenchmarkDirect(b *testing.B) { 39 | lg := &SimpleErrorLog{ 40 | Logger: &Logger{ 41 | output: "stdout", 42 | roller: DefaultRoller(), 43 | }, 44 | Level: ERROR, 45 | } 46 | for n := 0; n < b.N; n++ { 47 | if lg.Level >= DEBUG { 48 | lg.Debugf("say something:%s%s", "hello", expr("world", "!")) 49 | } 50 | } 51 | } 52 | 53 | func expr(left, right string) string { 54 | return left + right 55 | } 56 | -------------------------------------------------------------------------------- /log/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package log 19 | 20 | import ( 21 | "context" 22 | ) 23 | 24 | type Level uint8 25 | 26 | const ( 27 | FATAL Level = iota 28 | ERROR 29 | WARN 30 | INFO 31 | DEBUG 32 | TRACE 33 | RAW 34 | ) 35 | 36 | const ( 37 | FatalPre string = "[FATAL]" 38 | ErrorPre string = "[ERROR]" 39 | WarnPre string = "[WARN]" 40 | InfoPre string = "[INFO]" 41 | DebugPre string = "[DEBUG]" 42 | TracePre string = "[TRACE]" 43 | ) 44 | 45 | // ErrorLogger generates lines of output to an io.Writer 46 | // ErrorLogger generates lines of output to an io.Writer 47 | type ErrorLogger interface { 48 | Alertf(alert string, format string, args ...interface{}) 49 | 50 | Infof(format string, args ...interface{}) 51 | 52 | Debugf(format string, args ...interface{}) 53 | 54 | Warnf(format string, args ...interface{}) 55 | 56 | Errorf(format string, args ...interface{}) 57 | 58 | Tracef(format string, args ...interface{}) 59 | 60 | Fatalf(format string, args ...interface{}) 61 | 62 | // SetLogLevel updates the log level 63 | SetLogLevel(Level) 64 | // GetLogLevel returns the logger's level 65 | GetLogLevel() Level 66 | 67 | // Toggle disable/enable the logger 68 | Toggle(disable bool) 69 | 70 | Disable() bool 71 | } 72 | 73 | type ContextLogger interface { 74 | Alertf(ctx context.Context, alert string, format string, args ...interface{}) 75 | 76 | Infof(ctx context.Context, format string, args ...interface{}) 77 | 78 | Debugf(ctx context.Context, format string, args ...interface{}) 79 | 80 | Warnf(ctx context.Context, format string, args ...interface{}) 81 | 82 | Errorf(ctx context.Context, format string, args ...interface{}) 83 | 84 | Tracef(ctx context.Context, format string, args ...interface{}) 85 | 86 | Fatalf(ctx context.Context, format string, args ...interface{}) 87 | 88 | // SetLogLevel updates the log level 89 | SetLogLevel(Level) 90 | // GetLogLevel returns the logger's level 91 | GetLogLevel() Level 92 | 93 | // Toggle disable/enable the logger 94 | Toggle(disable bool) 95 | } 96 | -------------------------------------------------------------------------------- /netpoll/handle.go: -------------------------------------------------------------------------------- 1 | package netpoll 2 | 3 | import ( 4 | "net" 5 | "os" 6 | ) 7 | 8 | // filer describes an object that has ability to return os.File. 9 | type filer interface { 10 | // File returns a copy of object's file descriptor. 11 | File() (*os.File, error) 12 | } 13 | 14 | // Desc is a network connection within netpoll descriptor. 15 | // It's methods are not goroutine safe. 16 | type Desc struct { 17 | file *os.File 18 | event Event 19 | pfd uintptr 20 | } 21 | 22 | // NewDesc creates descriptor from custom fd. 23 | func NewDesc(fd uintptr, ev Event) *Desc { 24 | return &Desc{ 25 | event: ev, 26 | pfd: fd, 27 | } 28 | } 29 | 30 | // Close closes underlying file. 31 | func (h *Desc) Close() error { 32 | if h.file != nil { 33 | return h.file.Close() 34 | } 35 | return nil 36 | } 37 | 38 | func (h *Desc) Fd() int { 39 | return int(h.pfd) 40 | } 41 | 42 | // Must is a helper that wraps a call to a function returning (*Desc, error). 43 | // It panics if the error is non-nil and returns desc if not. 44 | // It is intended for use in short Desc initializations. 45 | func Must(desc *Desc, err error) *Desc { 46 | if err != nil { 47 | panic(err) 48 | } 49 | return desc 50 | } 51 | 52 | // HandleRead creates read descriptor for further use in Poller methods. 53 | // It is the same as Handle(conn, EventRead|EventEdgeTriggered). 54 | func HandleRead(conn net.Conn) (*Desc, error) { 55 | return Handle(conn, EventRead|EventEdgeTriggered) 56 | } 57 | 58 | // HandleReadOnce creates read descriptor for further use in Poller methods. 59 | // It is the same as Handle(conn, EventRead|EventOneShot). 60 | func HandleReadOnce(conn net.Conn) (*Desc, error) { 61 | return Handle(conn, EventRead|EventOneShot) 62 | } 63 | 64 | // HandleWrite creates write descriptor for further use in Poller methods. 65 | // It is the same as Handle(conn, EventWrite|EventEdgeTriggered). 66 | func HandleWrite(conn net.Conn) (*Desc, error) { 67 | return Handle(conn, EventWrite|EventEdgeTriggered) 68 | } 69 | 70 | // HandleWriteOnce creates write descriptor for further use in Poller methods. 71 | // It is the same as Handle(conn, EventWrite|EventOneShot). 72 | func HandleWriteOnce(conn net.Conn) (*Desc, error) { 73 | return Handle(conn, EventWrite|EventOneShot) 74 | } 75 | 76 | // HandleReadWrite creates read and write descriptor for further use in Poller 77 | // methods. 78 | // It is the same as Handle(conn, EventRead|EventWrite|EventEdgeTriggered). 79 | func HandleReadWrite(conn net.Conn) (*Desc, error) { 80 | return Handle(conn, EventRead|EventWrite|EventEdgeTriggered) 81 | } 82 | 83 | // Handle creates new Desc with given conn and event. 84 | // Returned descriptor could be used as argument to Start(), Resume() and 85 | // Stop() methods of some Poller implementation. 86 | func Handle(conn net.Conn, event Event) (*Desc, error) { 87 | desc, err := handle(conn, event) 88 | if err != nil { 89 | return nil, err 90 | } 91 | 92 | // Set the file back to non blocking mode since conn.File() sets underlying 93 | // os.File to blocking mode. This is useful to get conn.Set{Read}Deadline 94 | // methods still working on source Conn. 95 | // 96 | // See https://golang.org/pkg/net/#TCPConn.File 97 | // See /usr/local/go/src/net/net.go: conn.File() 98 | if err = setNonblock(desc.Fd(), true); err != nil { 99 | return nil, os.NewSyscallError("setnonblock", err) 100 | } 101 | 102 | return desc, nil 103 | } 104 | 105 | // Handle creates new Desc with given file and event. 106 | // Returned descriptor could be used as argument to Start(), Resume() and 107 | // Stop() methods of some Poller implementation. 108 | func HandleFile(file *os.File, event Event) (*Desc, error) { 109 | desc := NewDesc(file.Fd(), event) 110 | 111 | // Set the file back to non blocking mode since conn.File() sets underlying 112 | // os.File to blocking mode. This is useful to get conn.Set{Read}Deadline 113 | // methods still working on source Conn. 114 | // 115 | // See https://golang.org/pkg/net/#TCPConn.File 116 | // See /usr/local/go/src/net/net.go: conn.File() 117 | if err := setNonblock(desc.Fd(), true); err != nil { 118 | return nil, os.NewSyscallError("setnonblock", err) 119 | } 120 | 121 | return desc, nil 122 | } 123 | 124 | // HandleListener returns descriptor for a net.Listener. 125 | func HandleListener(ln net.Listener, event Event) (*Desc, error) { 126 | return handle(ln, event) 127 | } 128 | 129 | func handle(x interface{}, event Event) (*Desc, error) { 130 | f, ok := x.(filer) 131 | if !ok { 132 | return nil, ErrNotFiler 133 | } 134 | 135 | // Get a copy of fd. 136 | file, err := f.File() 137 | if err != nil { 138 | return nil, err 139 | } 140 | 141 | return &Desc{ 142 | file: file, 143 | event: event, 144 | }, nil 145 | } 146 | -------------------------------------------------------------------------------- /netpoll/handle_stub.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd 2 | 3 | package netpoll 4 | 5 | import "fmt" 6 | 7 | func setNonblock(fd int, nonblocking bool) (err error) { 8 | return fmt.Errorf("setNonblock is not supported on this operating system") 9 | } 10 | -------------------------------------------------------------------------------- /netpoll/handle_unix.go: -------------------------------------------------------------------------------- 1 | // +build linux darwin dragonfly freebsd netbsd openbsd 2 | 3 | package netpoll 4 | 5 | import "syscall" 6 | 7 | func setNonblock(fd int, nonblocking bool) (err error) { 8 | return syscall.SetNonblock(fd, nonblocking) 9 | } 10 | -------------------------------------------------------------------------------- /netpoll/netpoll_epoll.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package netpoll 4 | 5 | // New creates new epoll-based Poller instance with given config. 6 | func New(c *Config) (Poller, error) { 7 | cfg := c.withDefaults() 8 | 9 | epoll, err := EpollCreate(&EpollConfig{ 10 | OnWaitError: cfg.OnWaitError, 11 | }) 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | return poller{epoll}, nil 17 | } 18 | 19 | // poller implements Poller interface. 20 | type poller struct { 21 | *Epoll 22 | } 23 | 24 | // Start implements Poller.Start() method. 25 | func (ep poller) Start(desc *Desc, cb CallbackFn) error { 26 | return ep.Add(desc.Fd(), toEpollEvent(desc.event), 27 | func(ep EpollEvent) { 28 | var event Event 29 | 30 | if ep&EPOLLHUP != 0 { 31 | event |= EventHup 32 | } 33 | if ep&EPOLLRDHUP != 0 { 34 | event |= EventReadHup 35 | } 36 | if ep&EPOLLIN != 0 { 37 | event |= EventRead 38 | } 39 | if ep&EPOLLOUT != 0 { 40 | event |= EventWrite 41 | } 42 | if ep&EPOLLERR != 0 { 43 | event |= EventErr 44 | } 45 | if ep&_EPOLLCLOSED != 0 { 46 | event |= EventPollerClosed 47 | } 48 | 49 | cb(event) 50 | }, 51 | ) 52 | } 53 | 54 | // Stop implements Poller.Stop() method. 55 | func (ep poller) Stop(desc *Desc) error { 56 | return ep.Del(desc.Fd()) 57 | } 58 | 59 | // Resume implements Poller.Resume() method. 60 | func (ep poller) Resume(desc *Desc) error { 61 | return ep.Mod(desc.Fd(), toEpollEvent(desc.event)) 62 | } 63 | 64 | func toEpollEvent(event Event) (ep EpollEvent) { 65 | if event&EventRead != 0 { 66 | ep |= EPOLLIN | EPOLLRDHUP 67 | } 68 | if event&EventWrite != 0 { 69 | ep |= EPOLLOUT 70 | } 71 | if event&EventOneShot != 0 { 72 | ep |= EPOLLONESHOT 73 | } 74 | if event&EventEdgeTriggered != 0 { 75 | ep |= EPOLLET 76 | } 77 | return ep 78 | } 79 | -------------------------------------------------------------------------------- /netpoll/netpoll_kqueue.go: -------------------------------------------------------------------------------- 1 | // +build darwin dragonfly freebsd netbsd openbsd 2 | 3 | package netpoll 4 | 5 | // New creates new kqueue-based Poller instance with given config. 6 | func New(c *Config) (Poller, error) { 7 | cfg := c.withDefaults() 8 | 9 | kq, err := KqueueCreate(&KqueueConfig{ 10 | OnWaitError: cfg.OnWaitError, 11 | }) 12 | if err != nil { 13 | return nil, err 14 | } 15 | 16 | return poller{kq}, nil 17 | } 18 | 19 | type poller struct { 20 | *Kqueue 21 | } 22 | 23 | func (p poller) Start(desc *Desc, cb CallbackFn) error { 24 | n, events := toKevents(desc.event, true) 25 | return p.Add(desc.Fd(), events, n, func(kev Kevent) { 26 | var ( 27 | event Event 28 | 29 | flags = kev.Flags 30 | filter = kev.Filter 31 | ) 32 | 33 | // Set EventHup for any EOF flag. Below will be more precise detection 34 | // of what exatcly HUP occured. 35 | if flags&EV_EOF != 0 { 36 | event |= EventHup 37 | } 38 | 39 | if filter == EVFILT_READ { 40 | event |= EventRead 41 | if flags&EV_EOF != 0 { 42 | event |= EventReadHup 43 | } 44 | } 45 | if filter == EVFILT_WRITE { 46 | event |= EventWrite 47 | if flags&EV_EOF != 0 { 48 | event |= EventWriteHup 49 | } 50 | } 51 | if flags&EV_ERROR != 0 { 52 | event |= EventErr 53 | } 54 | if filter == _EVFILT_CLOSED { 55 | event |= EventPollerClosed 56 | } 57 | 58 | cb(event) 59 | }) 60 | } 61 | 62 | func (p poller) Stop(desc *Desc) error { 63 | n, events := toKevents(desc.event, false) 64 | if err := p.Del(desc.Fd()); err != nil { 65 | return err 66 | } 67 | if err := p.Mod(desc.Fd(), events, n); err != nil && err != ErrNotRegistered { 68 | return err 69 | } 70 | return nil 71 | } 72 | 73 | func (p poller) Resume(desc *Desc) error { 74 | n, events := toKevents(desc.event, true) 75 | return p.Mod(desc.Fd(), events, n) 76 | } 77 | 78 | func toKevents(event Event, add bool) (n int, ks Kevents) { 79 | var flags KeventFlag 80 | if add { 81 | flags = EV_ADD 82 | if event&EventOneShot != 0 { 83 | flags |= EV_ONESHOT 84 | } 85 | if event&EventEdgeTriggered != 0 { 86 | flags |= EV_CLEAR 87 | } 88 | } else { 89 | flags = EV_DELETE 90 | } 91 | if event&EventRead != 0 { 92 | ks[n].Flags = flags 93 | ks[n].Filter = EVFILT_READ 94 | n++ 95 | } 96 | if event&EventWrite != 0 { 97 | ks[n].Flags = flags 98 | ks[n].Filter = EVFILT_WRITE 99 | n++ 100 | } 101 | return 102 | } 103 | -------------------------------------------------------------------------------- /netpoll/netpoll_stub.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd 2 | 3 | package netpoll 4 | 5 | import "fmt" 6 | 7 | // New always returns an error to indicate that Poller is not implemented for 8 | // current operating system. 9 | func New(*Config) (Poller, error) { 10 | return nil, fmt.Errorf("poller is not supported on this operating system") 11 | } 12 | -------------------------------------------------------------------------------- /netpoll/util.go: -------------------------------------------------------------------------------- 1 | package netpoll 2 | 3 | import "syscall" 4 | 5 | func temporaryErr(err error) bool { 6 | errno, ok := err.(syscall.Errno) 7 | if !ok { 8 | return false 9 | } 10 | return errno.Temporary() 11 | } 12 | -------------------------------------------------------------------------------- /protocol/http/header_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package http 19 | 20 | import ( 21 | "strings" 22 | "testing" 23 | 24 | "github.com/valyala/fasthttp" 25 | ) 26 | 27 | func TestRequestHeader_Add(t *testing.T) { 28 | header := RequestHeader{&fasthttp.RequestHeader{}} 29 | header.Add("test-multiple", "value-one") 30 | header.Add("test-multiple", "value-two") 31 | 32 | // assert Peek results 33 | val := header.Peek("test-multiple") 34 | if string(val) != "value-one" { 35 | t.Errorf("RequestHeader.Get return not expected") 36 | } 37 | 38 | // assert output results 39 | output := header.String() 40 | if !strings.Contains(output, "value-one") || !strings.Contains(output, "value-two") { 41 | t.Errorf("RequestHeader.String not contains all header values") 42 | } 43 | } 44 | 45 | func TestResponseHeader_Add(t *testing.T) { 46 | header := ResponseHeader{&fasthttp.ResponseHeader{}} 47 | header.Add("test-multiple", "value-one") 48 | header.Add("test-multiple", "value-two") 49 | 50 | // assert Peek results 51 | val := header.Peek("test-multiple") 52 | if string(val) != "value-one" { 53 | t.Errorf("ResponseHeader.Get return not expected") 54 | } 55 | 56 | // assert output results 57 | output := header.String() 58 | if !strings.Contains(output, "value-one") || !strings.Contains(output, "value-two") { 59 | t.Errorf("ResponseHeader.String not contains all header values") 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /protocol/http/types_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package http 19 | 20 | import ( 21 | "testing" 22 | 23 | "github.com/valyala/fasthttp" 24 | ) 25 | 26 | const testHeaderHostKey = "Mosn-Header-Host" 27 | const testHeaderContentTypeKey = "Content-Type" 28 | const testHeaderEmptyKey = "Mosn-Empty" 29 | 30 | func TestRequestHeader(t *testing.T) { 31 | defer func() { 32 | if r := recover(); r != nil { 33 | t.Errorf("TestCommonHeader error: %v", r) 34 | } 35 | }() 36 | 37 | header := RequestHeader{&fasthttp.RequestHeader{}} 38 | 39 | header.Set(testHeaderHostKey, "test") 40 | if v, ok := header.Get(testHeaderHostKey); !ok || v != "test" { 41 | t.Error("Get header failed.") 42 | } 43 | 44 | header.Del(testHeaderHostKey) 45 | if _, ok := header.Get(testHeaderHostKey); ok { 46 | t.Error("Del header failed.") 47 | } 48 | 49 | // test clone header 50 | header.Set(testHeaderHostKey, "test") 51 | h2 := header.Clone() 52 | if h2 == nil { 53 | t.Error("Clone header failed.") 54 | } 55 | if v, ok := header.Get(testHeaderHostKey); !ok || v != "test" { 56 | t.Error("Clone header failed.") 57 | } 58 | 59 | // test ByteSize 60 | if l := h2.ByteSize(); l != uint64(len(testHeaderHostKey)+len("test")) { 61 | t.Errorf("get ByteSize failed got: %d want:%d", l, len(testHeaderHostKey)+len("test")) 62 | } 63 | 64 | // test range header 65 | h2.Range(func(key, value string) bool { 66 | if key != testHeaderHostKey || value != "test" { 67 | t.Errorf("Range header failed: %v, %v", key, value) 68 | return false 69 | } 70 | return true 71 | }) 72 | 73 | } 74 | 75 | func TestEmptyValueForRequestHeader(t *testing.T) { 76 | defer func() { 77 | if r := recover(); r != nil { 78 | t.Errorf("TestCommonHeader error: %v", r) 79 | } 80 | }() 81 | header := RequestHeader{&fasthttp.RequestHeader{}} 82 | 83 | header.Set(testHeaderEmptyKey, "") 84 | if v, ok := header.Get(testHeaderEmptyKey); !ok || v != "" { 85 | t.Errorf("Set empty header failed: %v %v", v, ok) 86 | } 87 | } 88 | 89 | func TestResponseHeader(t *testing.T) { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | t.Errorf("TestCommonHeader error: %v", r) 93 | } 94 | }() 95 | 96 | header := ResponseHeader{&fasthttp.ResponseHeader{}} 97 | 98 | header.Set(testHeaderContentTypeKey, "test") 99 | if v, ok := header.Get(testHeaderContentTypeKey); !ok || v != "test" { 100 | t.Error("Get header failed.") 101 | } 102 | 103 | // test clone header 104 | header.Set(testHeaderContentTypeKey, "test") 105 | h2 := header.Clone() 106 | if h2 == nil { 107 | t.Error("Clone header failed.") 108 | } 109 | if v, ok := header.Get(testHeaderContentTypeKey); !ok || v != "test" { 110 | t.Error("Clone header failed.") 111 | } 112 | 113 | // test ByteSize 114 | if l := h2.ByteSize(); l != uint64(len(testHeaderContentTypeKey)+len("test")) { 115 | t.Errorf("get ByteSize failed got: %d want:%d", l, len(testHeaderContentTypeKey)+len("test")) 116 | } 117 | 118 | // test range header 119 | h2.Range(func(key, value string) bool { 120 | if key != testHeaderContentTypeKey || value != "test" { 121 | t.Error("Range header failed.") 122 | return false 123 | } 124 | return true 125 | }) 126 | 127 | // test set empty header 128 | h2.Set(testHeaderHostKey, "") 129 | if _, ok := header.Get(testHeaderHostKey); ok { 130 | t.Error("Set empty header failed.") 131 | } 132 | } 133 | 134 | func TestEmptyValueForResponseHeader(t *testing.T) { 135 | defer func() { 136 | if r := recover(); r != nil { 137 | t.Errorf("TestCommonHeader error: %v", r) 138 | } 139 | }() 140 | header := ResponseHeader{&fasthttp.ResponseHeader{}} 141 | 142 | header.Set(testHeaderEmptyKey, "") 143 | if v, ok := header.Get(testHeaderEmptyKey); !ok || v != "" { 144 | t.Errorf("Set empty header failed: %v %v", v, ok) 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /registry/dubbo/common/constant/cluster.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package constant 19 | 20 | // nolint 21 | const ( 22 | FAILOVER_CLUSTER_NAME = "failover" 23 | ZONEAWARE_CLUSTER_NAME = "zoneAware" 24 | ) 25 | -------------------------------------------------------------------------------- /registry/dubbo/common/constant/default.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package constant 19 | 20 | const ( 21 | DUBBO = "dubbo" 22 | PROVIDER_PROTOCOL = "provider" 23 | //compatible with 2.6.x 24 | OVERRIDE_PROTOCOL = "override" 25 | EMPTY_PROTOCOL = "empty" 26 | ROUTER_PROTOCOL = "router" 27 | ) 28 | 29 | const ( 30 | DEFAULT_WEIGHT = 100 // 31 | DEFAULT_WARMUP = 10 * 60 // in java here is 10*60*1000 because of System.currentTimeMillis() is measured in milliseconds & in go time.Unix() is second 32 | ) 33 | 34 | const ( 35 | DEFAULT_LOADBALANCE = "random" 36 | DEFAULT_RETRIES = "2" 37 | DEFAULT_RETRIES_INT = 2 38 | DEFAULT_PROTOCOL = "dubbo" 39 | DEFAULT_REG_TIMEOUT = "10s" 40 | DEFAULT_REG_TTL = "15m" 41 | DEFAULT_CLUSTER = "failover" 42 | DEFAULT_FAILBACK_TIMES = "3" 43 | DEFAULT_FAILBACK_TIMES_INT = 3 44 | DEFAULT_FAILBACK_TASKS = 100 45 | DEFAULT_REST_CLIENT = "resty" 46 | DEFAULT_REST_SERVER = "go-restful" 47 | DEFAULT_PORT = 20000 48 | ) 49 | 50 | const ( 51 | DEFAULT_KEY = "default" 52 | PREFIX_DEFAULT_KEY = "default." 53 | DEFAULT_SERVICE_FILTERS = "echo,token,accesslog,tps,generic_service,execute,pshutdown" 54 | DEFAULT_REFERENCE_FILTERS = "cshutdown" 55 | GENERIC_REFERENCE_FILTERS = "generic" 56 | GENERIC = "$invoke" 57 | ECHO = "$echo" 58 | ) 59 | 60 | const ( 61 | ANY_VALUE = "*" 62 | ANYHOST_VALUE = "0.0.0.0" 63 | LOCAL_HOST_VALUE = "192.168.1.1" 64 | REMOVE_VALUE_PREFIX = "-" 65 | ) 66 | 67 | const ( 68 | CONFIGURATORS_CATEGORY = "configurators" 69 | ROUTER_CATEGORY = "category" 70 | DEFAULT_CATEGORY = PROVIDER_CATEGORY 71 | DYNAMIC_CONFIGURATORS_CATEGORY = "dynamicconfigurators" 72 | APP_DYNAMIC_CONFIGURATORS_CATEGORY = "appdynamicconfigurators" 73 | PROVIDER_CATEGORY = "providers" 74 | CONSUMER_CATEGORY = "consumers" 75 | ) 76 | 77 | const ( 78 | COMMA_SPLIT_PATTERN = "\\s*[,]+\\s*" 79 | ) 80 | 81 | const ( 82 | SIMPLE_METADATA_SERVICE_NAME = "MetadataService" 83 | DEFAULT_REVIESION = "N/A" 84 | ) 85 | 86 | const ( 87 | SERVICE_DISCOVERY_DEFAULT_GROUP = "DEFAULT_GROUP" 88 | ) 89 | -------------------------------------------------------------------------------- /registry/dubbo/common/constant/env.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package constant 19 | 20 | // nolint 21 | const ( 22 | // CONF_CONSUMER_FILE_PATH ... 23 | CONF_CONSUMER_FILE_PATH = "CONF_CONSUMER_FILE_PATH" 24 | // CONF_PROVIDER_FILE_PATH ... 25 | CONF_PROVIDER_FILE_PATH = "CONF_PROVIDER_FILE_PATH" 26 | // APP_LOG_CONF_FILE ... 27 | APP_LOG_CONF_FILE = "APP_LOG_CONF_FILE" 28 | // CONF_ROUTER_FILE_PATH Specify Path variable of router config file 29 | CONF_ROUTER_FILE_PATH = "CONF_ROUTER_FILE_PATH" 30 | ) 31 | -------------------------------------------------------------------------------- /registry/dubbo/common/constant/time.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package constant 19 | 20 | import ( 21 | "time" 22 | ) 23 | 24 | var ( 25 | // The value will be 10^6 26 | // 1ms = 10^6ns 27 | MsToNanoRate = int64(time.Millisecond / time.Nanosecond) 28 | ) 29 | -------------------------------------------------------------------------------- /registry/dubbo/common/constant/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package constant 19 | 20 | const ( 21 | // Version apache/dubbo-go version 22 | Version = "1.3.0" 23 | // Name module name 24 | Name = "dubbogo" 25 | // Date release date 26 | DATE = "2020/01/12" 27 | ) 28 | -------------------------------------------------------------------------------- /registry/dubbo/common/logger/log.yml: -------------------------------------------------------------------------------- 1 | level: "debug" 2 | development: false 3 | disableCaller: false 4 | disableStacktrace: false 5 | sampling: 6 | encoding: "console" 7 | 8 | # encoder 9 | encoderConfig: 10 | messageKey: "message" 11 | levelKey: "level" 12 | timeKey: "time" 13 | nameKey: "logger" 14 | callerKey: "caller" 15 | stacktraceKey: "stacktrace" 16 | lineEnding: "" 17 | levelEncoder: "capitalColor" 18 | timeEncoder: "iso8601" 19 | durationEncoder: "seconds" 20 | callerEncoder: "short" 21 | nameEncoder: "" 22 | 23 | outputPaths: 24 | - "stderr" 25 | errorOutputPaths: 26 | - "stderr" 27 | initialFields: 28 | -------------------------------------------------------------------------------- /registry/dubbo/common/logger/logger.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package logger 19 | 20 | import ( 21 | "io/ioutil" 22 | "path" 23 | 24 | "github.com/dubbogo/getty" 25 | perrors "github.com/pkg/errors" 26 | "go.uber.org/zap" 27 | "go.uber.org/zap/zapcore" 28 | "gopkg.in/yaml.v2" 29 | ) 30 | 31 | var ( 32 | logger Logger 33 | ) 34 | 35 | // nolint 36 | type DubboLogger struct { 37 | Logger 38 | dynamicLevel zap.AtomicLevel 39 | } 40 | 41 | // Logger is the interface for Logger types 42 | type Logger interface { 43 | Info(args ...interface{}) 44 | Warn(args ...interface{}) 45 | Error(args ...interface{}) 46 | Debug(args ...interface{}) 47 | 48 | Infof(fmt string, args ...interface{}) 49 | Warnf(fmt string, args ...interface{}) 50 | Errorf(fmt string, args ...interface{}) 51 | Debugf(fmt string, args ...interface{}) 52 | } 53 | 54 | // InitLog ... 55 | 56 | // InitLog use for init logger by call InitLogger 57 | func InitLog(logConfFile string) error { 58 | if logConfFile == "" { 59 | InitLogger(nil) 60 | return perrors.New("log configure file name is nil") 61 | } 62 | if path.Ext(logConfFile) != ".yml" { 63 | InitLogger(nil) 64 | return perrors.Errorf("log configure file name{%s} suffix must be .yml", logConfFile) 65 | } 66 | 67 | confFileStream, err := ioutil.ReadFile(logConfFile) 68 | if err != nil { 69 | InitLogger(nil) 70 | return perrors.Errorf("ioutil.ReadFile(file:%s) = error:%v", logConfFile, err) 71 | } 72 | 73 | conf := &zap.Config{} 74 | err = yaml.Unmarshal(confFileStream, conf) 75 | if err != nil { 76 | InitLogger(nil) 77 | return perrors.Errorf("[Unmarshal]init logger error: %v", err) 78 | } 79 | 80 | InitLogger(conf) 81 | 82 | return nil 83 | } 84 | 85 | // InitLogger use for init logger by @conf 86 | func InitLogger(conf *zap.Config) { 87 | var zapLoggerConfig zap.Config 88 | if conf == nil { 89 | zapLoggerEncoderConfig := zapcore.EncoderConfig{ 90 | TimeKey: "time", 91 | LevelKey: "level", 92 | NameKey: "logger", 93 | CallerKey: "caller", 94 | MessageKey: "message", 95 | StacktraceKey: "stacktrace", 96 | EncodeLevel: zapcore.CapitalColorLevelEncoder, 97 | EncodeTime: zapcore.ISO8601TimeEncoder, 98 | EncodeDuration: zapcore.SecondsDurationEncoder, 99 | EncodeCaller: zapcore.ShortCallerEncoder, 100 | } 101 | zapLoggerConfig = zap.Config{ 102 | Level: zap.NewAtomicLevelAt(zap.DebugLevel), 103 | Development: false, 104 | Encoding: "console", 105 | EncoderConfig: zapLoggerEncoderConfig, 106 | OutputPaths: []string{"stderr"}, 107 | ErrorOutputPaths: []string{"stderr"}, 108 | } 109 | } else { 110 | zapLoggerConfig = *conf 111 | } 112 | zapLogger, _ := zapLoggerConfig.Build(zap.AddCallerSkip(1)) 113 | logger = &DubboLogger{Logger: zapLogger.Sugar(), dynamicLevel: zapLoggerConfig.Level} 114 | 115 | // set getty log 116 | getty.SetLogger(logger) 117 | } 118 | 119 | // SetLogger sets logger for dubbo and getty 120 | func SetLogger(log Logger) { 121 | logger = log 122 | getty.SetLogger(logger) 123 | } 124 | 125 | // GetLogger gets the logger 126 | func GetLogger() Logger { 127 | return logger 128 | } 129 | 130 | // SetLoggerLevel use for set logger level 131 | func SetLoggerLevel(level string) bool { 132 | if l, ok := logger.(OpsLogger); ok { 133 | l.SetLoggerLevel(level) 134 | return true 135 | } 136 | return false 137 | } 138 | 139 | // OpsLogger use for the SetLoggerLevel 140 | type OpsLogger interface { 141 | Logger 142 | SetLoggerLevel(level string) 143 | } 144 | 145 | // SetLoggerLevel use for set logger level 146 | func (dl *DubboLogger) SetLoggerLevel(level string) { 147 | l := new(zapcore.Level) 148 | l.Set(level) 149 | dl.dynamicLevel.SetLevel(*l) 150 | } 151 | -------------------------------------------------------------------------------- /registry/dubbo/common/logger/logger_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package logger 19 | 20 | import ( 21 | "fmt" 22 | "path/filepath" 23 | "runtime" 24 | "testing" 25 | ) 26 | 27 | import ( 28 | "github.com/stretchr/testify/assert" 29 | ) 30 | 31 | func TestInitLog(t *testing.T) { 32 | var ( 33 | err error 34 | path string 35 | ) 36 | 37 | err = InitLog("") 38 | assert.EqualError(t, err, "log configure file name is nil") 39 | 40 | path, err = filepath.Abs("./log.xml") 41 | assert.NoError(t, err) 42 | err = InitLog(path) 43 | assert.EqualError(t, err, "log configure file name{"+path+"} suffix must be .yml") 44 | 45 | path, err = filepath.Abs("./logger.yml") 46 | assert.NoError(t, err) 47 | err = InitLog(path) 48 | var errMsg string 49 | if runtime.GOOS == "windows" { 50 | errMsg = fmt.Sprintf("open %s: The system cannot find the file specified.", path) 51 | } else { 52 | errMsg = fmt.Sprintf("open %s: no such file or directory", path) 53 | } 54 | assert.EqualError(t, err, fmt.Sprintf("ioutil.ReadFile(file:%s) = error:%s", path, errMsg)) 55 | 56 | err = InitLog("./log.yml") 57 | assert.NoError(t, err) 58 | 59 | Debug("debug") 60 | Info("info") 61 | Warn("warn") 62 | Error("error") 63 | Debugf("%s", "debug") 64 | Infof("%s", "info") 65 | Warnf("%s", "warn") 66 | Errorf("%s", "error") 67 | } 68 | 69 | func TestSetLevel(t *testing.T) { 70 | err := InitLog("./log.yml") 71 | assert.NoError(t, err) 72 | Debug("debug") 73 | Info("info") 74 | 75 | assert.True(t, SetLoggerLevel("info")) 76 | Debug("debug") 77 | Info("info") 78 | 79 | SetLogger(GetLogger().(*DubboLogger).Logger) 80 | assert.False(t, SetLoggerLevel("debug")) 81 | Debug("debug") 82 | Info("info") 83 | } 84 | -------------------------------------------------------------------------------- /registry/dubbo/common/logger/logging.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package logger 19 | 20 | // Info is info level 21 | func Info(args ...interface{}) { 22 | logger.Info(args...) 23 | } 24 | 25 | // Warn is warning level 26 | func Warn(args ...interface{}) { 27 | logger.Warn(args...) 28 | } 29 | 30 | // Error is error level 31 | func Error(args ...interface{}) { 32 | logger.Error(args...) 33 | } 34 | 35 | // Debug is debug level 36 | func Debug(args ...interface{}) { 37 | logger.Debug(args...) 38 | } 39 | 40 | // Infof is format info level 41 | func Infof(fmt string, args ...interface{}) { 42 | logger.Infof(fmt, args...) 43 | } 44 | 45 | // Warnf is format warning level 46 | func Warnf(fmt string, args ...interface{}) { 47 | logger.Warnf(fmt, args...) 48 | } 49 | 50 | // Errorf is format error level 51 | func Errorf(fmt string, args ...interface{}) { 52 | logger.Errorf(fmt, args...) 53 | } 54 | 55 | // Debugf is format debug level 56 | func Debugf(fmt string, args ...interface{}) { 57 | logger.Debugf(fmt, args...) 58 | } 59 | -------------------------------------------------------------------------------- /registry/dubbo/common/node.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package common 19 | 20 | // Node ... 21 | type Node interface { 22 | GetUrl() URL 23 | IsAvailable() bool 24 | Destroy() 25 | } 26 | -------------------------------------------------------------------------------- /registry/dubbo/common/rpc_service_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package common 19 | 20 | import ( 21 | "context" 22 | "reflect" 23 | "testing" 24 | 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestMethodType_SuiteContext(t *testing.T) { 29 | mt := &MethodType{ctxType: reflect.TypeOf(context.TODO())} 30 | ctx := context.WithValue(context.Background(), "key", "value") 31 | assert.Equal(t, reflect.ValueOf(ctx), mt.SuiteContext(ctx)) 32 | 33 | assert.Equal(t, reflect.Zero(mt.ctxType), mt.SuiteContext(nil)) 34 | } 35 | -------------------------------------------------------------------------------- /registry/dubbo/config_center/configuration_listener.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package config_center 19 | 20 | import ( 21 | "fmt" 22 | 23 | "mosn.io/pkg/registry/dubbo/remoting" 24 | ) 25 | 26 | // ConfigurationListener ... 27 | type ConfigurationListener interface { 28 | Process(*ConfigChangeEvent) 29 | } 30 | 31 | // ConfigChangeEvent ... 32 | type ConfigChangeEvent struct { 33 | Key string 34 | Value interface{} 35 | ConfigType remoting.EventType 36 | } 37 | 38 | func (c ConfigChangeEvent) String() string { 39 | return fmt.Sprintf("ConfigChangeEvent{key = %v , value = %v , changeType = %v}", c.Key, c.Value, c.ConfigType) 40 | } 41 | -------------------------------------------------------------------------------- /registry/dubbo/config_center/configurator.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package config_center 19 | 20 | import ( 21 | "mosn.io/pkg/registry/dubbo/common" 22 | ) 23 | 24 | // Configurator ... 25 | type Configurator interface { 26 | GetUrl() *common.URL 27 | Configure(url *common.URL) 28 | } 29 | -------------------------------------------------------------------------------- /registry/dubbo/config_center/configurator/mock.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package configurator 19 | 20 | import ( 21 | "mosn.io/pkg/registry/dubbo/common" 22 | "mosn.io/pkg/registry/dubbo/common/constant" 23 | "mosn.io/pkg/registry/dubbo/config_center" 24 | ) 25 | 26 | // NewMockConfigurator ... 27 | func NewMockConfigurator(url *common.URL) config_center.Configurator { 28 | return &mockConfigurator{configuratorUrl: url} 29 | } 30 | 31 | type mockConfigurator struct { 32 | configuratorUrl *common.URL 33 | } 34 | 35 | // GetUrl ... 36 | func (c *mockConfigurator) GetUrl() *common.URL { 37 | return c.configuratorUrl 38 | } 39 | 40 | // Configure ... 41 | func (c *mockConfigurator) Configure(url *common.URL) { 42 | if cluster := c.GetUrl().GetParam(constant.CLUSTER_KEY, ""); cluster != "" { 43 | url.SetParam(constant.CLUSTER_KEY, cluster) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /registry/dubbo/config_center/dynamic_configuration.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package config_center 19 | 20 | import ( 21 | "time" 22 | 23 | gxset "github.com/dubbogo/gost/container/set" 24 | "mosn.io/pkg/registry/dubbo/common" 25 | "mosn.io/pkg/registry/dubbo/config_center/parser" 26 | ) 27 | 28 | // //////////////////////////////////////// 29 | // DynamicConfiguration 30 | // //////////////////////////////////////// 31 | const ( 32 | // DEFAULT_GROUP: default group 33 | DEFAULT_GROUP = "dubbo" 34 | // DEFAULT_CONFIG_TIMEOUT: default config timeout 35 | DEFAULT_CONFIG_TIMEOUT = "10s" 36 | ) 37 | 38 | // DynamicConfiguration ... 39 | type DynamicConfiguration interface { 40 | Parser() parser.ConfigurationParser 41 | SetParser(parser.ConfigurationParser) 42 | AddListener(string, ConfigurationListener, ...Option) 43 | RemoveListener(string, ConfigurationListener, ...Option) 44 | // GetProperties get properties file 45 | GetProperties(string, ...Option) (string, error) 46 | 47 | // GetRule get Router rule properties file 48 | GetRule(string, ...Option) (string, error) 49 | 50 | // GetInternalProperty get value by key in Default properties file(dubbo.properties) 51 | GetInternalProperty(string, ...Option) (string, error) 52 | 53 | // PublishConfig will publish the config with the (key, group, value) pair 54 | PublishConfig(string, string, string) error 55 | 56 | // GetConfigKeysByGroup will return all keys with the group 57 | GetConfigKeysByGroup(group string) (*gxset.HashSet, error) 58 | } 59 | 60 | // Options ... 61 | type Options struct { 62 | Group string 63 | Timeout time.Duration 64 | } 65 | 66 | // Option ... 67 | type Option func(*Options) 68 | 69 | // WithGroup ... 70 | func WithGroup(group string) Option { 71 | return func(opt *Options) { 72 | opt.Group = group 73 | } 74 | } 75 | 76 | // WithTimeout ... 77 | func WithTimeout(time time.Duration) Option { 78 | return func(opt *Options) { 79 | opt.Timeout = time 80 | } 81 | } 82 | 83 | // GetRuleKey The format is '{interfaceName}:[version]:[group]' 84 | func GetRuleKey(url common.URL) string { 85 | return url.ColonSeparatedKey() 86 | } 87 | -------------------------------------------------------------------------------- /registry/dubbo/config_center/dynamic_configuration_factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package config_center 19 | 20 | import ( 21 | "mosn.io/pkg/registry/dubbo/common" 22 | ) 23 | 24 | // DynamicConfigurationFactory ... 25 | type DynamicConfigurationFactory interface { 26 | GetDynamicConfiguration(*common.URL) (DynamicConfiguration, error) 27 | } 28 | -------------------------------------------------------------------------------- /registry/dubbo/config_center/parser/configuration_parser_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package parser 19 | 20 | import ( 21 | "testing" 22 | ) 23 | 24 | import ( 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestDefaultConfigurationParser_Parser(t *testing.T) { 29 | parser := &DefaultConfigurationParser{} 30 | m, err := parser.Parse("dubbo.registry.address=172.0.0.1\ndubbo.registry.name=test") 31 | assert.NoError(t, err) 32 | assert.Equal(t, 2, len(m)) 33 | assert.Equal(t, "172.0.0.1", m["dubbo.registry.address"]) 34 | } 35 | -------------------------------------------------------------------------------- /registry/dubbo/config_center/zookeeper/factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package zookeeper 19 | 20 | import ( 21 | "mosn.io/pkg/registry/dubbo/common" 22 | "mosn.io/pkg/registry/dubbo/config_center" 23 | "mosn.io/pkg/registry/dubbo/config_center/parser" 24 | ) 25 | 26 | type zookeeperDynamicConfigurationFactory struct { 27 | } 28 | 29 | func (f *zookeeperDynamicConfigurationFactory) GetDynamicConfiguration(url *common.URL) (config_center.DynamicConfiguration, error) { 30 | dynamicConfiguration, err := newZookeeperDynamicConfiguration(url) 31 | if err != nil { 32 | return nil, err 33 | } 34 | dynamicConfiguration.SetParser(&parser.DefaultConfigurationParser{}) 35 | return dynamicConfiguration, err 36 | 37 | } 38 | -------------------------------------------------------------------------------- /registry/dubbo/config_center/zookeeper/listener.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package zookeeper 19 | 20 | import ( 21 | "strings" 22 | "sync" 23 | 24 | "mosn.io/pkg/registry/dubbo/config_center" 25 | "mosn.io/pkg/registry/dubbo/remoting" 26 | ) 27 | 28 | // CacheListener ... 29 | type CacheListener struct { 30 | keyListeners sync.Map 31 | rootPath string 32 | } 33 | 34 | // NewCacheListener ... 35 | func NewCacheListener(rootPath string) *CacheListener { 36 | return &CacheListener{rootPath: rootPath} 37 | } 38 | 39 | // AddListener ... 40 | func (l *CacheListener) AddListener(key string, listener config_center.ConfigurationListener) { 41 | 42 | // reference from https://stackoverflow.com/questions/34018908/golang-why-dont-we-have-a-set-datastructure 43 | // make a map[your type]struct{} like set in java 44 | listeners, loaded := l.keyListeners.LoadOrStore(key, map[config_center.ConfigurationListener]struct{}{listener: {}}) 45 | if loaded { 46 | listeners.(map[config_center.ConfigurationListener]struct{})[listener] = struct{}{} 47 | l.keyListeners.Store(key, listeners) 48 | } 49 | } 50 | 51 | // RemoveListener ... 52 | func (l *CacheListener) RemoveListener(key string, listener config_center.ConfigurationListener) { 53 | listeners, loaded := l.keyListeners.Load(key) 54 | if loaded { 55 | delete(listeners.(map[config_center.ConfigurationListener]struct{}), listener) 56 | } 57 | } 58 | 59 | // DataChange ... 60 | func (l *CacheListener) DataChange(event remoting.Event) bool { 61 | if event.Content == "" { 62 | //meanings new node 63 | return true 64 | } 65 | key := l.pathToKey(event.Path) 66 | if key != "" { 67 | if listeners, ok := l.keyListeners.Load(key); ok { 68 | for listener := range listeners.(map[config_center.ConfigurationListener]struct{}) { 69 | listener.Process(&config_center.ConfigChangeEvent{Key: key, Value: event.Content, ConfigType: event.Action}) 70 | } 71 | return true 72 | } 73 | } 74 | return false 75 | } 76 | 77 | func (l *CacheListener) pathToKey(path string) string { 78 | return strings.Replace(strings.Replace(path, l.rootPath+"/", "", -1), "/", ".", -1) 79 | } 80 | -------------------------------------------------------------------------------- /registry/dubbo/event.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dubbo 19 | 20 | import ( 21 | "fmt" 22 | "math/rand" 23 | "time" 24 | 25 | "mosn.io/pkg/registry/dubbo/common" 26 | "mosn.io/pkg/registry/dubbo/remoting" 27 | ) 28 | 29 | func init() { 30 | rand.Seed(time.Now().UnixNano()) 31 | } 32 | 33 | // //////////////////////////////////////// 34 | // service event 35 | // //////////////////////////////////////// 36 | 37 | // ServiceEvent ... 38 | type ServiceEvent struct { 39 | Action remoting.EventType 40 | Service common.URL 41 | } 42 | 43 | // String return the description of event 44 | func (e ServiceEvent) String() string { 45 | return fmt.Sprintf("ServiceEvent{Action{%s}, Path{%s}}", e.Action, e.Service) 46 | } 47 | 48 | // Event is align with Event interface in Java. 49 | // it's the top abstraction 50 | // Align with 2.7.5 51 | type Event interface { 52 | fmt.Stringer 53 | GetSource() interface{} 54 | GetTimestamp() time.Time 55 | } 56 | 57 | // baseEvent is the base implementation of Event 58 | // You should never use it directly 59 | type baseEvent struct { 60 | source interface{} 61 | timestamp time.Time 62 | } 63 | 64 | // GetSource return the source 65 | func (b *baseEvent) GetSource() interface{} { 66 | return b.source 67 | } 68 | 69 | // GetTimestamp return the timestamp when the event is created 70 | func (b *baseEvent) GetTimestamp() time.Time { 71 | return b.timestamp 72 | } 73 | 74 | // String return a human readable string representing this event 75 | func (b *baseEvent) String() string { 76 | return fmt.Sprintf("baseEvent[source = %#v]", b.source) 77 | } 78 | 79 | func newBaseEvent(source interface{}) *baseEvent { 80 | return &baseEvent{ 81 | source: source, 82 | timestamp: time.Now(), 83 | } 84 | } 85 | 86 | // ServiceInstancesChangedEvent represents service instances make some changing 87 | type ServiceInstancesChangedEvent struct { 88 | baseEvent 89 | ServiceName string 90 | Instances []ServiceInstance 91 | } 92 | 93 | // String return the description of the event 94 | func (s *ServiceInstancesChangedEvent) String() string { 95 | return fmt.Sprintf("ServiceInstancesChangedEvent[source=%s]", s.ServiceName) 96 | } 97 | 98 | // NewServiceInstancesChangedEvent will create the ServiceInstanceChangedEvent instance 99 | func NewServiceInstancesChangedEvent(serviceName string, instances []ServiceInstance) *ServiceInstancesChangedEvent { 100 | return &ServiceInstancesChangedEvent{ 101 | baseEvent: baseEvent{ 102 | source: serviceName, 103 | timestamp: time.Now(), 104 | }, 105 | ServiceName: serviceName, 106 | Instances: instances, 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /registry/dubbo/event_listener.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dubbo 19 | 20 | import ( 21 | gxsort "github.com/dubbogo/gost/sort" 22 | ) 23 | 24 | // EventListener is an new interface used to align with dubbo 2.7.5 25 | // It contains the Prioritized means that the listener has its priority 26 | type EventListener interface { 27 | gxsort.Prioritizer 28 | // OnEvent handle this event 29 | OnEvent(e Event) error 30 | } 31 | 32 | // ConditionalEventListener only handle the event which it can handle 33 | type ConditionalEventListener interface { 34 | EventListener 35 | // Accept will make the decision whether it should handle this event 36 | Accept(e Event) bool 37 | } 38 | 39 | // TODO (implement ConditionalEventListener) 40 | type ServiceInstancesChangedListener struct { 41 | ServiceName string 42 | } 43 | -------------------------------------------------------------------------------- /registry/dubbo/mock_registry.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dubbo 19 | 20 | import ( 21 | "time" 22 | 23 | "mosn.io/pkg/registry/dubbo/common" 24 | "mosn.io/pkg/registry/dubbo/common/logger" 25 | "go.uber.org/atomic" 26 | ) 27 | 28 | // MockRegistry ... 29 | type MockRegistry struct { 30 | listener *listener 31 | destroyed *atomic.Bool 32 | } 33 | 34 | // NewMockRegistry ... 35 | func NewMockRegistry(url *common.URL) (Registry, error) { 36 | registry := &MockRegistry{ 37 | destroyed: atomic.NewBool(false), 38 | } 39 | listener := &listener{count: 0, registry: registry, listenChan: make(chan *ServiceEvent)} 40 | registry.listener = listener 41 | return registry, nil 42 | } 43 | 44 | // Register ... 45 | func (*MockRegistry) Register(url *common.URL) error { 46 | return nil 47 | } 48 | 49 | // UnRegister 50 | func (r *MockRegistry) UnRegister(conf *common.URL) error { 51 | return nil 52 | } 53 | 54 | // Destroy ... 55 | func (r *MockRegistry) Destroy() { 56 | if r.destroyed.CAS(false, true) { 57 | } 58 | } 59 | 60 | // IsAvailable ... 61 | func (r *MockRegistry) IsAvailable() bool { 62 | return !r.destroyed.Load() 63 | } 64 | 65 | // GetUrl ... 66 | func (r *MockRegistry) GetUrl() common.URL { 67 | return common.URL{} 68 | } 69 | 70 | func (r *MockRegistry) subscribe(*common.URL) (Listener, error) { 71 | return r.listener, nil 72 | } 73 | 74 | // Subscribe ... 75 | func (r *MockRegistry) Subscribe(url *common.URL, notifyListener NotifyListener) error { 76 | go func() { 77 | for { 78 | if !r.IsAvailable() { 79 | logger.Warnf("event listener game over.") 80 | time.Sleep(time.Duration(3) * time.Second) 81 | return 82 | } 83 | 84 | listener, err := r.subscribe(url) 85 | if err != nil { 86 | if !r.IsAvailable() { 87 | logger.Warnf("event listener game over.") 88 | return 89 | } 90 | time.Sleep(time.Duration(3) * time.Second) 91 | continue 92 | } 93 | 94 | for { 95 | serviceEvent, err := listener.Next() 96 | if err != nil { 97 | listener.Close() 98 | time.Sleep(time.Duration(3) * time.Second) 99 | return 100 | } 101 | 102 | logger.Infof("update begin, service event: %v", serviceEvent.String()) 103 | notifyListener.Notify(serviceEvent) 104 | } 105 | } 106 | }() 107 | return nil 108 | } 109 | 110 | // UnSubscribe : 111 | func (r *MockRegistry) UnSubscribe(url *common.URL, notifyListener NotifyListener) error { 112 | return nil 113 | } 114 | 115 | type listener struct { 116 | count int64 117 | registry *MockRegistry 118 | listenChan chan *ServiceEvent 119 | } 120 | 121 | func (l *listener) Next() (*ServiceEvent, error) { 122 | select { 123 | case e := <-l.listenChan: 124 | return e, nil 125 | } 126 | } 127 | 128 | func (*listener) Close() { 129 | 130 | } 131 | 132 | // MockEvent ... 133 | func (r *MockRegistry) MockEvent(event *ServiceEvent) { 134 | r.listener.listenChan <- event 135 | } 136 | -------------------------------------------------------------------------------- /registry/dubbo/readme.md: -------------------------------------------------------------------------------- 1 | # Notice 2 | 3 | This package is extracted from github.com/apache/dubbo-go 4 | 5 | 1. Import paths were edited to reduce the dependencies. 6 | 7 | 2. The most init funcitons were removed 8 | 9 | 3. ETCD, consul, nacos, kubernetes were removed 10 | 11 | -------------------------------------------------------------------------------- /registry/dubbo/registry.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dubbo 19 | 20 | import ( 21 | "mosn.io/pkg/registry/dubbo/common" 22 | ) 23 | 24 | /* 25 | * -----------------------------------NOTICE--------------------------------------------- 26 | * If there is no special case, you'd better inherit BaseRegistry and implement the 27 | * FacadeBasedRegistry interface instead of directly implementing the Registry interface. 28 | * -------------------------------------------------------------------------------------- 29 | */ 30 | // Registry Extension - Registry 31 | type Registry interface { 32 | common.Node 33 | //used for service provider calling , register services to registry 34 | //And it is also used for service consumer calling , register services cared about ,for dubbo's admin monitoring. 35 | Register(url *common.URL) error 36 | 37 | // UnRegister is required to support the contract: 38 | // 1. If it is the persistent stored data of dynamic=false, the registration data can not be found, then the IllegalStateException is thrown, otherwise it is ignored. 39 | // 2. Unregister according to the full url match. 40 | // url Registration information , is not allowed to be empty, e.g: dubbo://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin 41 | UnRegister(url *common.URL) error 42 | 43 | //When creating new registry extension,pls select one of the following modes. 44 | //Will remove in dubbogo version v1.1.0 45 | //mode1 : return Listener with Next function which can return subscribe service event from registry 46 | //Deprecated! 47 | //subscribe(common.URL) (Listener, error) 48 | 49 | //Will relace mode1 in dubbogo version v1.1.0 50 | //mode2 : callback mode, subscribe with notify(notify listener). 51 | Subscribe(*common.URL, NotifyListener) error 52 | 53 | // UnSubscribe is required to support the contract: 54 | // 1. If don't subscribe, ignore it directly. 55 | // 2. Unsubscribe by full URL match. 56 | // url Subscription condition, not allowed to be empty, e.g. consumer://10.20.153.10/org.apache.dubbo.foo.BarService?version=1.0.0&application=kylin 57 | // listener A listener of the change event, not allowed to be empty 58 | UnSubscribe(*common.URL, NotifyListener) error 59 | } 60 | 61 | // NotifyListener ... 62 | type NotifyListener interface { 63 | Notify(*ServiceEvent) 64 | } 65 | 66 | // Listener Deprecated! 67 | type Listener interface { 68 | Next() (*ServiceEvent, error) 69 | Close() 70 | } 71 | -------------------------------------------------------------------------------- /registry/dubbo/remoting/listener.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package remoting 19 | 20 | import ( 21 | "fmt" 22 | ) 23 | 24 | // DataListener ... 25 | type DataListener interface { 26 | DataChange(eventType Event) bool //bool is return for interface implement is interesting 27 | } 28 | 29 | ////////////////////////////////////////// 30 | // event type 31 | ////////////////////////////////////////// 32 | 33 | // EventType ... 34 | type EventType int 35 | 36 | const ( 37 | // EventTypeAdd ... 38 | EventTypeAdd = iota 39 | // EventTypeDel ... 40 | EventTypeDel 41 | // EventTypeUpdate ... 42 | EventTypeUpdate 43 | ) 44 | 45 | var serviceEventTypeStrings = [...]string{ 46 | "add", 47 | "delete", 48 | "update", 49 | } 50 | 51 | func (t EventType) String() string { 52 | return serviceEventTypeStrings[t] 53 | } 54 | 55 | ////////////////////////////////////////// 56 | // service event 57 | ////////////////////////////////////////// 58 | 59 | // Event ... 60 | type Event struct { 61 | Path string 62 | Action EventType 63 | Content string 64 | } 65 | 66 | func (e Event) String() string { 67 | return fmt.Sprintf("Event{Action{%s}, Content{%s}}", e.Action, e.Content) 68 | } 69 | -------------------------------------------------------------------------------- /registry/dubbo/remoting/zookeeper/curator_discovery/service_instance.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package curator_discovery 19 | 20 | // ServiceInstance which define in curator-x-discovery, please refer to 21 | // https://github.com/apache/curator/blob/master/curator-x-discovery/src/main/java/org/apache/curator/x/discovery/ServiceInstance.java 22 | type ServiceInstance struct { 23 | Name string 24 | Id string 25 | Address string 26 | Port int 27 | Payload interface{} 28 | RegistrationTimeUTC int64 29 | } 30 | -------------------------------------------------------------------------------- /registry/dubbo/remoting/zookeeper/facade.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package zookeeper 19 | 20 | import ( 21 | "sync" 22 | 23 | "github.com/dubbogo/getty" 24 | "mosn.io/pkg/registry/dubbo/common" 25 | "mosn.io/pkg/registry/dubbo/common/logger" 26 | perrors "github.com/pkg/errors" 27 | ) 28 | 29 | type ZkClientFacade interface { 30 | ZkClient() *ZookeeperClient 31 | SetZkClient(*ZookeeperClient) 32 | ZkClientLock() *sync.Mutex 33 | WaitGroup() *sync.WaitGroup // for wait group control, zk client listener & zk client container 34 | Done() chan struct{} // for zk client control 35 | RestartCallBack() bool 36 | GetUrl() common.URL 37 | } 38 | 39 | // HandleClientRestart keeps the connection between client and server 40 | func HandleClientRestart(r ZkClientFacade) { 41 | var ( 42 | err error 43 | 44 | failTimes int 45 | ) 46 | 47 | LOOP: 48 | for { 49 | select { 50 | case <-r.Done(): 51 | r.WaitGroup().Done() // dec the wg when registry is closed 52 | logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...") 53 | break LOOP 54 | // re-register all services 55 | case <-r.ZkClient().Done(): 56 | r.ZkClientLock().Lock() 57 | r.ZkClient().Close() 58 | zkName := r.ZkClient().name 59 | zkAddress := r.ZkClient().ZkAddrs 60 | r.SetZkClient(nil) 61 | r.ZkClientLock().Unlock() 62 | r.WaitGroup().Done() // dec the wg when zk client is closed 63 | 64 | // Connect zk until success. 65 | failTimes = 0 66 | for { 67 | select { 68 | case <-r.Done(): 69 | r.WaitGroup().Done() // dec the wg when registry is closed 70 | logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...") 71 | break LOOP 72 | case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // Prevent crazy reconnection zk. 73 | } 74 | err = ValidateZookeeperClient(r, WithZkName(zkName)) 75 | logger.Infof("ZkProviderRegistry.validateZookeeperClient(zkAddr{%s}) = error{%#v}", 76 | zkAddress, perrors.WithStack(err)) 77 | if err == nil && r.RestartCallBack() { 78 | break 79 | } 80 | failTimes++ 81 | if MaxFailTimes <= failTimes { 82 | failTimes = MaxFailTimes 83 | } 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /registry/dubbo/service_discovery.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dubbo 19 | 20 | import ( 21 | "fmt" 22 | 23 | gxset "github.com/dubbogo/gost/container/set" 24 | gxpage "github.com/dubbogo/gost/hash/page" 25 | ) 26 | 27 | const DefaultPageSize = 100 28 | 29 | type ServiceDiscovery interface { 30 | fmt.Stringer 31 | 32 | // ----------------- lifecycle ------------------- 33 | 34 | // Destroy will destroy the service discovery. 35 | // If the discovery cannot be destroy, it will return an error. 36 | Destroy() error 37 | 38 | // ----------------- registration ---------------- 39 | 40 | // Register will register an instance of ServiceInstance to registry 41 | Register(instance ServiceInstance) error 42 | 43 | // Update will update the data of the instance in registry 44 | Update(instance ServiceInstance) error 45 | 46 | // Unregister will unregister this instance from registry 47 | Unregister(instance ServiceInstance) error 48 | 49 | // ----------------- discovery ------------------- 50 | // GetDefaultPageSize will return the default page size 51 | GetDefaultPageSize() int 52 | 53 | // GetServices will return the all service names. 54 | GetServices() *gxset.HashSet 55 | 56 | // GetInstances will return all service instances with serviceName 57 | GetInstances(serviceName string) []ServiceInstance 58 | 59 | // GetInstancesByPage will return a page containing instances of ServiceInstance with the serviceName 60 | // the page will start at offset 61 | GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager 62 | 63 | // GetHealthyInstancesByPage will return a page containing instances of ServiceInstance. 64 | // The param healthy indices that the instance should be healthy or not. 65 | // The page will start at offset 66 | GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager 67 | 68 | // Batch get all instances by the specified service names 69 | GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager 70 | 71 | // ----------------- event ---------------------- 72 | // AddListener adds a new ServiceInstancesChangedListener 73 | // see addServiceInstancesChangedListener in Java 74 | AddListener(listener *ServiceInstancesChangedListener) error 75 | 76 | // DispatchEventByServiceName dispatches the ServiceInstancesChangedEvent to service instance whose name is serviceName 77 | DispatchEventByServiceName(serviceName string) error 78 | 79 | // DispatchEventForInstances dispatches the ServiceInstancesChangedEvent to target instances 80 | DispatchEventForInstances(serviceName string, instances []ServiceInstance) error 81 | 82 | // DispatchEvent dispatches the event 83 | DispatchEvent(event *ServiceInstancesChangedEvent) error 84 | } 85 | -------------------------------------------------------------------------------- /registry/dubbo/service_instance.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package dubbo 19 | 20 | type ServiceInstance interface { 21 | 22 | // GetId will return this instance's id. It should be unique. 23 | GetId() string 24 | 25 | // GetServiceName will return the serviceName 26 | GetServiceName() string 27 | 28 | // GetHost will return the hostname 29 | GetHost() string 30 | 31 | // GetPort will return the port. 32 | GetPort() int 33 | 34 | // IsEnable will return the enable status of this instance 35 | IsEnable() bool 36 | 37 | // IsHealthy will return the value represent the instance whether healthy or not 38 | IsHealthy() bool 39 | 40 | // GetMetadata will return the metadata 41 | GetMetadata() map[string]string 42 | } 43 | 44 | // DefaultServiceInstance the default implementation of ServiceInstance 45 | // or change the ServiceInstance to be struct??? 46 | type DefaultServiceInstance struct { 47 | Id string 48 | ServiceName string 49 | Host string 50 | Port int 51 | Enable bool 52 | Healthy bool 53 | Metadata map[string]string 54 | } 55 | 56 | // GetId will return this instance's id. It should be unique. 57 | func (d *DefaultServiceInstance) GetId() string { 58 | return d.Id 59 | } 60 | 61 | // GetServiceName will return the serviceName 62 | func (d *DefaultServiceInstance) GetServiceName() string { 63 | return d.ServiceName 64 | } 65 | 66 | // GetHost will return the hostname 67 | func (d *DefaultServiceInstance) GetHost() string { 68 | return d.Host 69 | } 70 | 71 | // GetPort will return the port. 72 | func (d *DefaultServiceInstance) GetPort() int { 73 | return d.Port 74 | } 75 | 76 | // IsEnable will return the enable status of this instance 77 | func (d *DefaultServiceInstance) IsEnable() bool { 78 | return d.Enable 79 | } 80 | 81 | // IsHealthy will return the value represent the instance whether healthy or not 82 | func (d *DefaultServiceInstance) IsHealthy() bool { 83 | return d.Healthy 84 | } 85 | 86 | // GetMetadata will return the metadata 87 | func (d *DefaultServiceInstance) GetMetadata() map[string]string { 88 | return d.Metadata 89 | } 90 | -------------------------------------------------------------------------------- /registry/dubbo/zookeeper/listener_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package zookeeper 19 | 20 | import ( 21 | "testing" 22 | 23 | "mosn.io/pkg/registry/dubbo/common" 24 | "mosn.io/pkg/registry/dubbo/config_center" 25 | "mosn.io/pkg/registry/dubbo/remoting" 26 | "github.com/stretchr/testify/assert" 27 | ) 28 | 29 | func Test_DataChange(t *testing.T) { 30 | listener := NewRegistryDataListener() 31 | url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100") 32 | listener.SubscribeURL(&url, &MockConfigurationListener{}) 33 | int := listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"}) 34 | assert.Equal(t, true, int) 35 | } 36 | 37 | type MockConfigurationListener struct { 38 | } 39 | 40 | func (*MockConfigurationListener) Process(configType *config_center.ConfigChangeEvent) { 41 | } 42 | -------------------------------------------------------------------------------- /utils/dup.go: -------------------------------------------------------------------------------- 1 | // +build linux,!arm64,!amd64,!386 darwin,!amd64,!386 windows 2 | 3 | package utils 4 | 5 | import ( 6 | "fmt" 7 | "runtime" 8 | ) 9 | 10 | func Dup(from, to int) error { 11 | fmt.Printf("GOOS %s, GOARCH %s is not support dup\n", runtime.GOOS, runtime.GOARCH) 12 | return nil 13 | } 14 | -------------------------------------------------------------------------------- /utils/dup_386.go: -------------------------------------------------------------------------------- 1 | // +build linux darwin 2 | 3 | package utils 4 | 5 | import "syscall" 6 | 7 | func Dup(from, to int) error { 8 | return syscall.Dup2(from, to) 9 | } 10 | -------------------------------------------------------------------------------- /utils/dup_amd64.go: -------------------------------------------------------------------------------- 1 | // +build linux darwin 2 | 3 | package utils 4 | 5 | import "syscall" 6 | 7 | func Dup(from, to int) error { 8 | return syscall.Dup2(from, to) 9 | } 10 | -------------------------------------------------------------------------------- /utils/dup_arm64.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package utils 4 | 5 | import "syscall" 6 | 7 | // if oldd ≠ newd and flags == 0, the behavior is identical to dup2(oldd, newd). 8 | // arm support dup3 only 9 | func Dup(from, to int) error { 10 | return syscall.Dup3(from, to, 0) 11 | } 12 | -------------------------------------------------------------------------------- /utils/file.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "encoding/json" 22 | "errors" 23 | "fmt" 24 | "io/ioutil" 25 | "os" 26 | "path" 27 | ) 28 | 29 | // WriteFileSafety trys to over write a file safety. 30 | func WriteFileSafety(filename string, data []byte, perm os.FileMode) (err error) { 31 | tempFile := filename + ".tmp" 32 | Try: 33 | for i := 0; i < 5; i++ { 34 | err = ioutil.WriteFile(tempFile, data, perm) 35 | if err == nil { 36 | break Try 37 | } 38 | } 39 | if err != nil { 40 | return err 41 | } 42 | err = os.Rename(tempFile, filename) 43 | return 44 | } 45 | 46 | const JsonExt = ".json" 47 | 48 | var ErrIgnore = errors.New("error ignore") 49 | 50 | // ReadJsonFile reads a json into interface 51 | // If a file is not .json ignore it 52 | // If a file is empty, ignore it 53 | func ReadJsonFile(file string, v interface{}) error { 54 | if path.Ext(file) != JsonExt { 55 | return ErrIgnore 56 | } 57 | b, err := ioutil.ReadFile(file) 58 | if err != nil { 59 | return fmt.Errorf("read file %s got error %v", file, err) 60 | } 61 | if len(b) == 0 { 62 | return ErrIgnore 63 | } 64 | if err := json.Unmarshal(b, v); err != nil { 65 | return fmt.Errorf("unmarshal json file %s got error %v", file, err) 66 | } 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /utils/file_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "bytes" 22 | "errors" 23 | "io/ioutil" 24 | "os" 25 | "testing" 26 | ) 27 | 28 | func TestWriteFileSafety(t *testing.T) { 29 | target := "/tmp/test_write_file_safety" 30 | data := []byte("test_data") 31 | if err := WriteFileSafety(target, data, 0644); err != nil { 32 | t.Fatal("write file error: ", err) 33 | } 34 | // verify 35 | b, err := ioutil.ReadFile(target) 36 | if err != nil { 37 | t.Fatal("read target file failed: ", err) 38 | } 39 | if !bytes.Equal(data, b) { 40 | t.Error("write data is not expected") 41 | } 42 | 43 | f, err := os.Stat(target) 44 | if err != nil { 45 | t.Fatal("read target file stat failed: ", err) 46 | } 47 | if !(f.Mode() == 0644) { 48 | t.Fatal("target file stat verify failed: ", f.Mode()) 49 | } 50 | } 51 | 52 | func TestReadJsonFile(t *testing.T) { 53 | AnyError := errors.New("any error") 54 | tcs := []struct { 55 | path string 56 | data []byte 57 | expected error 58 | }{ 59 | { 60 | path: "/tmp/test_empty.json", 61 | data: []byte(`{"test":"data"}`), 62 | expected: nil, 63 | }, 64 | { 65 | path: "/tmp/not.json.tmp", 66 | data: []byte("12345"), 67 | expected: ErrIgnore, 68 | }, 69 | { 70 | path: "/tmp/empty.json", 71 | data: nil, 72 | expected: ErrIgnore, 73 | }, 74 | { 75 | path: "/tmp/error.json", 76 | data: []byte("12345"), 77 | expected: AnyError, 78 | }, 79 | } 80 | for _, tc := range tcs { 81 | os.Remove(tc.path) 82 | if err := WriteFileSafety(tc.path, tc.data, 0644); err != nil { 83 | t.Fatal(err) 84 | } 85 | v := map[string]interface{}{} 86 | err := ReadJsonFile(tc.path, &v) 87 | switch tc.expected { 88 | case ErrIgnore, nil: 89 | if err != tc.expected { 90 | t.Fatalf("expected %v, but got: %v", tc.expected, err) 91 | } 92 | case AnyError: 93 | if err == nil { 94 | t.Fatal("expected got an error, but not") 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /utils/goroutine.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "fmt" 22 | "io" 23 | "os" 24 | "runtime/debug" 25 | ) 26 | 27 | var recoverLogger func(w io.Writer, r interface{}) = defaultRecoverLogger 28 | 29 | // RegisterRecoverLogger replace the log handler when go with recover catch a panic 30 | // notice the replaced handler should be simple. 31 | // if the handler panic, the recover handler will be failed. 32 | func RegisterRecoverLogger(f func(w io.Writer, r interface{})) { 33 | recoverLogger = f 34 | } 35 | 36 | func defaultRecoverLogger(w io.Writer, r interface{}) { 37 | fmt.Fprintf(w, "%s goroutine panic: %v\n%s\n", CacheTime(), r, string(debug.Stack())) 38 | } 39 | 40 | // GoWithRecover wraps a `go func()` with recover() 41 | func GoWithRecover(handler func(), recoverHandler func(r interface{})) { 42 | go func() { 43 | defer func() { 44 | if r := recover(); r != nil { 45 | recoverLogger(os.Stderr, r) 46 | if recoverHandler != nil { 47 | go func() { 48 | defer func() { 49 | if p := recover(); p != nil { 50 | recoverLogger(os.Stderr, p) 51 | } 52 | }() 53 | recoverHandler(r) 54 | }() 55 | } 56 | } 57 | }() 58 | handler() 59 | }() 60 | } 61 | -------------------------------------------------------------------------------- /utils/goroutine_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "fmt" 22 | "io" 23 | "os" 24 | "testing" 25 | "time" 26 | ) 27 | 28 | func debugIgnoreLogger(w io.Writer, r interface{}) { 29 | } 30 | 31 | func TestMain(m *testing.M) { 32 | RegisterRecoverLogger(debugIgnoreLogger) 33 | os.Exit(m.Run()) 34 | } 35 | 36 | func TestGoWithRecover(t *testing.T) { 37 | panicStr := "test panic" 38 | panicHandler := func() { 39 | panic(panicStr) 40 | } 41 | output := "" 42 | recoverHandler := func(r interface{}) { 43 | output = fmt.Sprintf("%v", r) 44 | } 45 | GoWithRecover(panicHandler, recoverHandler) 46 | time.Sleep(time.Second) // wait panic goroutine 47 | if output != panicStr { 48 | t.Errorf("expected catch panic output, but got: %s", output) 49 | } 50 | } 51 | 52 | // recover handler panic, should not panic 53 | func TestRecoverPanic(t *testing.T) { 54 | handler := func() { 55 | panic("1") 56 | } 57 | recoverHandler := func(r interface{}) { 58 | panic("2") 59 | } 60 | GoWithRecover(handler, recoverHandler) 61 | } 62 | 63 | // Example for how to recover with recover 64 | type _run struct { 65 | count int 66 | noPanic bool 67 | } 68 | 69 | func (r *_run) work() { 70 | GoWithRecover(r.exec, func(p interface{}) { 71 | r.work() 72 | }) 73 | } 74 | 75 | func (r *_run) exec() { 76 | r.count++ 77 | if r.count <= 2 { 78 | panic("panic") 79 | } 80 | r.noPanic = true 81 | } 82 | 83 | func TestGoWithRecoverAgain(t *testing.T) { 84 | r := &_run{} 85 | r.work() 86 | time.Sleep(time.Second) 87 | if !(r.noPanic && r.count == 3) { 88 | t.Errorf("panic handler is not restart expectedly, noPanic: %v, count: %d", r.noPanic, r.count) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /utils/sync_list.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "container/list" 22 | "sync" 23 | ) 24 | 25 | // SyncList similar with the builtin List container while it is concurrency safe. 26 | type SyncList struct { 27 | list *list.List 28 | curr *list.Element 29 | mux sync.Mutex 30 | visitMux sync.Mutex 31 | } 32 | 33 | // NewSyncList returns an initialized SyncList. 34 | func NewSyncList() *SyncList { 35 | return &SyncList{ 36 | list: list.New(), 37 | curr: nil, 38 | mux: sync.Mutex{}, 39 | visitMux: sync.Mutex{}, 40 | } 41 | } 42 | 43 | // PushBack inserts a new element e with value v at the back of list l and returns e. 44 | func (l *SyncList) PushBack(v interface{}) *list.Element { 45 | l.mux.Lock() 46 | defer l.mux.Unlock() 47 | return l.list.PushBack(v) 48 | } 49 | 50 | // Remove removes e from l if e is an element of list l. 51 | // It returns the element value e.Value. 52 | // The element must not be nil. 53 | func (l *SyncList) Remove(e *list.Element) interface{} { 54 | l.mux.Lock() 55 | defer l.mux.Unlock() 56 | if e == l.curr { 57 | l.curr = l.curr.Prev() 58 | } 59 | 60 | return l.list.Remove(e) 61 | } 62 | 63 | // VisitSafe means the visit function f can visit each element safely even f may block some time. 64 | // Also, it won't block other operations(e.g. Remove) when the visit function f is blocked. 65 | // But, it can not run parallel since there is an instance level curr point. 66 | func (l *SyncList) VisitSafe(f func(v interface{})) { 67 | l.visitMux.Lock() 68 | defer l.visitMux.Unlock() 69 | 70 | // just in case there is some dirty data left from the previous call. 71 | l.mux.Lock() 72 | l.curr = nil 73 | l.mux.Unlock() 74 | 75 | for { 76 | l.mux.Lock() 77 | if l.curr == nil { 78 | l.curr = l.list.Front() 79 | } else { 80 | l.curr = l.curr.Next() 81 | } 82 | curr := l.curr 83 | l.mux.Unlock() 84 | 85 | if curr == nil { 86 | break 87 | } 88 | 89 | f(curr.Value) 90 | } 91 | } 92 | 93 | // Len returns the number of elements of list l. 94 | func (l *SyncList) Len() int { 95 | l.mux.Lock() 96 | defer l.mux.Unlock() 97 | 98 | return l.list.Len() 99 | } 100 | -------------------------------------------------------------------------------- /utils/sync_list_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "sync" 22 | "testing" 23 | ) 24 | 25 | func TestSyncListPushBack(t *testing.T) { 26 | l := NewSyncList() 27 | 28 | wg := sync.WaitGroup{} 29 | wg.Add(100) 30 | for i := 0; i < 100; i++ { 31 | go func() { 32 | defer wg.Done() 33 | l.PushBack(1) 34 | }() 35 | } 36 | wg.Wait() 37 | len := l.Len() 38 | if len != 100 { 39 | t.Errorf("sync list length expect 100 while got: %v", len) 40 | } 41 | } 42 | 43 | func BenchmarkSyncListPushBack(b *testing.B) { 44 | l := NewSyncList() 45 | for i := 0; i < b.N; i++ { 46 | l.PushBack(1) 47 | } 48 | } 49 | 50 | func TestSyncListRemove(t *testing.T) { 51 | l := NewSyncList() 52 | wg := sync.WaitGroup{} 53 | wg.Add(200) 54 | for i := 0; i < 100; i++ { 55 | go func() { 56 | defer wg.Done() 57 | l.PushBack(1) 58 | }() 59 | go func() { 60 | defer wg.Done() 61 | e := l.PushBack(2) 62 | l.Remove(e) 63 | }() 64 | } 65 | wg.Wait() 66 | len := l.Len() 67 | if len != 100 { 68 | t.Errorf("sync list length expect 100 while got: %v", len) 69 | } 70 | } 71 | 72 | func BenchmarkSyncListRemove(b *testing.B) { 73 | l := NewSyncList() 74 | for i := 0; i < b.N; i++ { 75 | e := l.PushBack(1) 76 | l.Remove(e) 77 | } 78 | } 79 | 80 | func TestSyncListVisitSafe(t *testing.T) { 81 | l := NewSyncList() 82 | for i := 0; i < 100; i++ { 83 | l.PushBack(i) 84 | } 85 | count := 0 86 | l.VisitSafe(func(_ interface{}) { 87 | count++ 88 | }) 89 | if count != 100 { 90 | t.Errorf("count expected 100 while got: %v", count) 91 | } 92 | len := l.Len() 93 | if len != 100 { 94 | t.Errorf("sync list length expect 100 while got: %v", len) 95 | } 96 | } 97 | 98 | func TestSyncListVisitSafeWithRemove(t *testing.T) { 99 | l := NewSyncList() 100 | for i := 0; i < 100; i++ { 101 | l.PushBack(i) 102 | } 103 | count := 0 104 | l.VisitSafe(func(v interface{}) { 105 | n := v.(int) 106 | first := l.list.Front().Value.(int) 107 | 108 | if n != first { 109 | t.Errorf("visit value not match the first value, %v vs %v", n, first) 110 | } 111 | l.Remove(l.list.Front().Next()) 112 | l.Remove(l.list.Front()) 113 | 114 | count++ 115 | }) 116 | if count != 50 { 117 | t.Errorf("count expected 50 while got: %v", count) 118 | } 119 | len := l.Len() 120 | if len != 0 { 121 | t.Errorf("sync list length expect 0 while got: %v", len) 122 | } 123 | } 124 | 125 | func BenchmarkSyncListVisitSafe(b *testing.B) { 126 | l := NewSyncList() 127 | for i := 0; i < 100; i++ { 128 | l.PushBack(i) 129 | } 130 | for i := 0; i < b.N; i++ { 131 | l.VisitSafe(func(v interface{}) { 132 | n := v.(int) 133 | n++ 134 | }) 135 | } 136 | } 137 | 138 | func TestSyncListVisitSafeWithPushBack(t *testing.T) { 139 | l := NewSyncList() 140 | for i := 0; i < 100; i++ { 141 | l.PushBack(i) 142 | } 143 | count := 0 144 | l.VisitSafe(func(v interface{}) { 145 | n := v.(int) 146 | if n%2 == 0 && n > 10 { 147 | l.PushBack(n / 2) 148 | } 149 | 150 | count++ 151 | }) 152 | if count != 171 { 153 | t.Errorf("count expected 50 while got: %v", count) 154 | } 155 | len := l.Len() 156 | if len != count { 157 | t.Errorf("sync list length expect %v while got: %v", count, len) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /utils/syscall.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package utils 21 | 22 | import ( 23 | "os" 24 | "syscall" 25 | "time" 26 | ) 27 | 28 | var ( 29 | // keep the standard for recover 30 | standardStdoutFd, _ = syscall.Dup(int(os.Stdout.Fd())) 31 | standardStderrFd, _ = syscall.Dup(int(os.Stderr.Fd())) 32 | ) 33 | 34 | // SetHijackStdPipeline hijacks stdout and stderr outputs into the file path 35 | func SetHijackStdPipeline(filepath string, stdout, stderr bool) { 36 | files := []*os.File{} 37 | if stdout { 38 | files = append(files, os.Stdout) 39 | } 40 | if stderr { 41 | files = append(files, os.Stderr) 42 | } 43 | GoWithRecover(func() { 44 | ResetHjiackStdPipeline() 45 | setHijackFile(files, filepath) 46 | }, nil) 47 | } 48 | 49 | func ResetHjiackStdPipeline() { 50 | Dup(standardStdoutFd, int(os.Stdout.Fd())) 51 | Dup(standardStderrFd, int(os.Stderr.Fd())) 52 | } 53 | 54 | // setHijackFile hijacks the stdFile outputs into the new file 55 | // the new file will be rotated each {hijackRotateInterval}, and we keep one old file 56 | func setHijackFile(stdFiles []*os.File, newFilePath string) { 57 | hijack := func() { 58 | fp, err := os.OpenFile(newFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) 59 | if err != nil { 60 | return 61 | } 62 | for _, stdFile := range stdFiles { 63 | Dup(int(fp.Fd()), int(stdFile.Fd())) 64 | } 65 | } 66 | rotate := func(today string) { 67 | if err := os.Rename(newFilePath, newFilePath+"."+today); err != nil { 68 | return 69 | } 70 | hijack() 71 | } 72 | if len(stdFiles) > 0 { 73 | // call 74 | hijack() 75 | // rotate by day 76 | for { 77 | todayStr := time.Now().Format("2006-01-02") 78 | // use system localtion 79 | time.Sleep(nextDayDuration(time.Now(), time.Local)) 80 | rotate(todayStr) 81 | } 82 | } 83 | 84 | } 85 | 86 | // nextDayDuration returns the duration to next day 87 | func nextDayDuration(now time.Time, local *time.Location) time.Duration { 88 | today, _ := time.ParseInLocation("2006-01-02", now.Format("2006-01-02"), local) 89 | nextday := today.AddDate(0, 0, 1) 90 | return nextday.Sub(now) 91 | } 92 | -------------------------------------------------------------------------------- /utils/syscall_test.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package utils 21 | 22 | import ( 23 | "fmt" 24 | "io/ioutil" 25 | "os" 26 | "testing" 27 | "time" 28 | ) 29 | 30 | func TestSetHijackStdPipeline(t *testing.T) { 31 | // init 32 | stderrFile := "/tmp/test_stderr" 33 | os.Remove(stderrFile) 34 | // call, test std error only 35 | SetHijackStdPipeline(stderrFile, false, true) 36 | time.Sleep(time.Second) // wait goroutine run 37 | fmt.Fprintf(os.Stderr, "test stderr") 38 | // verify 39 | if !verifyFile(stderrFile, "test stderr") { 40 | t.Error("stderr hijack failed") 41 | } 42 | ResetHjiackStdPipeline() 43 | fmt.Fprintf(os.Stderr, "repaired\n") 44 | } 45 | 46 | func verifyFile(p string, data string) bool { 47 | b, err := ioutil.ReadFile(p) 48 | if err != nil { 49 | return false 50 | } 51 | return string(b) == data 52 | } 53 | 54 | func TestNextDay(t *testing.T) { 55 | t.Run("test dst in America/Los_Angeles", func(t *testing.T) { 56 | loc, _ := time.LoadLocation("America/Los_Angeles") 57 | firstTimeStr := "2020-11-01 00:00:00 -0700 PDT" 58 | ft, _ := time.ParseInLocation("2006-01-02 15:04:05 -0700 MST", firstTimeStr, loc) 59 | d := nextDayDuration(ft, loc) 60 | if d != 25*time.Hour { // rollback an hour, so next day is 25 hour 61 | t.Fatalf("next day duration is %s", d) 62 | } 63 | 64 | secondTimeStr := "2021-03-14 00:00:00 -0800 PST" 65 | st, _ := time.ParseInLocation("2006-01-02 15:04:05 -0700 MST", secondTimeStr, loc) 66 | d2 := nextDayDuration(st, loc) 67 | if d2 != 23*time.Hour { // dst, next day is 23 hour 68 | t.Fatalf("next day duration is %s", d) 69 | } 70 | }) 71 | t.Run("test utc time zone", func(t *testing.T) { 72 | loc, _ := time.LoadLocation("UTC") 73 | firstTimeStr := "2020-11-01 00:00:00 +0000 UTC" 74 | ft, _ := time.ParseInLocation("2006-01-02 15:04:05 -0700 MST", firstTimeStr, loc) 75 | d := nextDayDuration(ft, loc) 76 | if d != 24*time.Hour { 77 | t.Fatalf("next day duration is %s", d) 78 | } 79 | 80 | secondTimeStr := "2021-03-14 00:00:00 +0000 UTC" 81 | st, _ := time.ParseInLocation("2006-01-02 15:04:05 -0700 MST", secondTimeStr, loc) 82 | d2 := nextDayDuration(st, loc) 83 | if d2 != 24*time.Hour { 84 | t.Fatalf("next day duration is %s", d) 85 | } 86 | 87 | }) 88 | t.Run("test time.loal", func(t *testing.T) { 89 | firstTimeStr := "2020-11-01 00:00:00" 90 | ft, _ := time.ParseInLocation("2006-01-02 15:04:05", firstTimeStr, time.Local) 91 | d := nextDayDuration(ft, time.Local) 92 | if d != 24*time.Hour { 93 | t.Fatalf("next day duration is %s", d) 94 | } 95 | 96 | secondTimeStr := "2021-03-14 00:00:00" 97 | st, _ := time.ParseInLocation("2006-01-02 15:04:05", secondTimeStr, time.Local) 98 | d2 := nextDayDuration(st, time.Local) 99 | if d2 != 24*time.Hour { 100 | t.Fatalf("next day duration is %s", d) 101 | } 102 | }) 103 | } 104 | -------------------------------------------------------------------------------- /utils/syscall_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package utils 21 | 22 | import "fmt" 23 | 24 | // SetHijackStdPipeline hijacks stdout and stderr outputs into the file path 25 | func SetHijackStdPipeline(filepath string, stdout, stderr bool) { 26 | fmt.Println("windows not not support SetHijackStdPipeline") 27 | } 28 | 29 | func ResetHjiackStdPipeline() { 30 | } 31 | -------------------------------------------------------------------------------- /utils/ticker.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "runtime/debug" 22 | "sync/atomic" 23 | "time" 24 | ) 25 | 26 | // Ticker is a thread-safe reusable ticker 27 | type Ticker struct { 28 | innerTicker *time.Ticker 29 | interval time.Duration 30 | callback func() 31 | stopChan chan bool 32 | started int32 33 | stopped int32 34 | } 35 | 36 | func NewTicker(callback func()) *Ticker { 37 | return &Ticker{ 38 | callback: callback, 39 | stopChan: make(chan bool, 1), 40 | } 41 | } 42 | 43 | // Start starts a ticker running if it is not started 44 | func (t *Ticker) Start(interval time.Duration) { 45 | if !atomic.CompareAndSwapInt32(&t.started, 0, 1) { 46 | return 47 | } 48 | 49 | if t.innerTicker == nil { 50 | t.innerTicker = time.NewTicker(interval) 51 | } 52 | 53 | go func() { 54 | defer func() { 55 | if r := recover(); r != nil { 56 | debug.PrintStack() 57 | } 58 | t.Close() 59 | atomic.StoreInt32(&t.started, 0) 60 | atomic.StoreInt32(&t.stopped, 0) 61 | }() 62 | 63 | for { 64 | select { 65 | case <-t.innerTicker.C: 66 | t.callback() 67 | case <-t.stopChan: 68 | t.innerTicker.Stop() 69 | return 70 | } 71 | } 72 | }() 73 | 74 | } 75 | 76 | // Stop stops the ticker. 77 | func (t *Ticker) Stop() { 78 | if !atomic.CompareAndSwapInt32(&t.stopped, 0, 1) { 79 | return 80 | } 81 | 82 | t.stopChan <- true 83 | } 84 | 85 | // Close closes the ticker. 86 | func (t *Ticker) Close() { 87 | close(t.stopChan) 88 | } 89 | -------------------------------------------------------------------------------- /utils/time_cache.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "strconv" 22 | "sync/atomic" 23 | "time" 24 | ) 25 | 26 | var ( 27 | // lastTime is used to cache time 28 | lastTime atomic.Value 29 | ) 30 | 31 | // timeCache is used to reduce format 32 | type timeCache struct { 33 | t int64 34 | s string 35 | } 36 | 37 | // CacheTime returns a time cache in seconds. 38 | // we use a cache to reduce the format 39 | func CacheTime() string { 40 | var s string 41 | t := time.Now() 42 | nano := t.UnixNano() 43 | now := nano / 1e9 44 | value := lastTime.Load() 45 | if value != nil { 46 | last := value.(*timeCache) 47 | if now <= last.t { 48 | s = last.s 49 | } 50 | } 51 | if s == "" { 52 | s = t.Format("2006-01-02 15:04:05") 53 | lastTime.Store(&timeCache{now, s}) 54 | } 55 | mi := nano % 1e9 / 1e6 56 | s = s + "," + strconv.Itoa(int(mi)) 57 | return s 58 | } 59 | -------------------------------------------------------------------------------- /utils/time_cache_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "runtime" 22 | "testing" 23 | "time" 24 | ) 25 | 26 | func BenchmarkTimeNow(b *testing.B) { 27 | runtime.GOMAXPROCS(runtime.NumCPU()) 28 | for n := 0; n < b.N; n++ { 29 | time.Now() 30 | } 31 | } 32 | 33 | func BenchmarkTimeFormat(b *testing.B) { 34 | runtime.GOMAXPROCS(runtime.NumCPU()) 35 | for n := 0; n < b.N; n++ { 36 | time.Now().Format("2006/01/02 15:04:05.000") 37 | } 38 | } 39 | 40 | func BenchmarkCacheTime(b *testing.B) { 41 | runtime.GOMAXPROCS(runtime.NumCPU()) 42 | for n := 0; n < b.N; n++ { 43 | CacheTime() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /utils/timer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "sync/atomic" 22 | "time" 23 | ) 24 | 25 | type Timer struct { 26 | innerTimer *time.Timer 27 | stopped int32 28 | } 29 | 30 | func NewTimer(d time.Duration, callback func()) *Timer { 31 | return &Timer{ 32 | innerTimer: time.AfterFunc(d, callback), 33 | } 34 | } 35 | 36 | // Stop stops the timer. 37 | func (t *Timer) Stop() { 38 | if t == nil { 39 | return 40 | } 41 | if !atomic.CompareAndSwapInt32(&t.stopped, 0, 1) { 42 | return 43 | } 44 | 45 | t.innerTimer.Stop() 46 | } 47 | 48 | func (t *Timer) Reset(d time.Duration) bool { 49 | if t == nil { 50 | return false 51 | } 52 | // already stopped 53 | if atomic.LoadInt32(&t.stopped) == 1 { 54 | return false 55 | } 56 | return t.innerTimer.Reset(d) 57 | } 58 | -------------------------------------------------------------------------------- /utils/timer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "testing" 22 | "time" 23 | ) 24 | 25 | func TestTimer(t *testing.T) { 26 | ch := make(chan int, 1) 27 | _ = NewTimer(time.Second, func() { 28 | ch <- 100 29 | }) 30 | select { 31 | case i := <-ch: 32 | if i != 100 { 33 | t.Fatalf("unexpected channel %d", i) 34 | } 35 | case <-time.After(2 * time.Second): 36 | t.Fatalf("timeout") 37 | } 38 | } 39 | 40 | func TestTimerStop(t *testing.T) { 41 | ch := make(chan int, 1) 42 | timer := NewTimer(time.Second, func() { 43 | ch <- 100 44 | }) 45 | timer.Stop() 46 | // func never be called 47 | select { 48 | case <-ch: 49 | t.Fatalf("receive channel from func") 50 | case <-time.After(2 * time.Second): 51 | // expected, pass 52 | } 53 | } 54 | 55 | func TestTimerReset(t *testing.T) { 56 | ch := make(chan int, 1) 57 | timer := NewTimer(100*time.Second, func() { 58 | ch <- 100 59 | }) 60 | timer.Reset(0) // timeout right now 61 | select { 62 | case i := <-ch: 63 | if i != 100 { 64 | t.Fatalf("unexpected channel %d", i) 65 | } 66 | case <-time.After(100 * time.Millisecond): 67 | t.Fatalf("unexpected timeout") 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /utils/trylock.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import "time" 21 | 22 | type Mutex struct { 23 | c chan struct{} 24 | } 25 | 26 | func NewMutex() *Mutex { 27 | return &Mutex{make(chan struct{}, 1)} 28 | } 29 | 30 | func (m *Mutex) Lock() { 31 | m.c <- struct{}{} 32 | } 33 | 34 | func (m *Mutex) Unlock() { 35 | <-m.c 36 | } 37 | 38 | func (m *Mutex) TryLock(timeout time.Duration) bool { 39 | 40 | select { 41 | case m.c <- struct{}{}: 42 | return true 43 | default: 44 | timer := time.NewTimer(timeout) 45 | select { 46 | case m.c <- struct{}{}: 47 | timer.Stop() 48 | return true 49 | case <-timer.C: 50 | return false 51 | } 52 | 53 | } 54 | return false 55 | } 56 | -------------------------------------------------------------------------------- /utils/trylock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "testing" 22 | "time" 23 | ) 24 | 25 | func TestTrylock(t *testing.T) { 26 | m := NewMutex() 27 | ok := m.TryLock(time.Second) 28 | if !ok { 29 | t.Error("it should be lock suc but failed!") 30 | } 31 | 32 | ok = m.TryLock(time.Second * 3) 33 | if ok { 34 | t.Error("it should be lock failed but suc") 35 | } 36 | 37 | m.Unlock() 38 | 39 | ok = m.TryLock(time.Second) 40 | if !ok { 41 | t.Error("it should be lock suc but failed!") 42 | } 43 | 44 | } 45 | 46 | func BenchmarkTrylock(b *testing.B) { 47 | var number int 48 | lock := NewMutex() 49 | for i := 0; i < b.N; i++ { 50 | go func() { 51 | defer lock.Unlock() 52 | lock.TryLock(time.Second * 3) 53 | number++ 54 | }() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /utils/uuid.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package utils 19 | 20 | import ( 21 | "crypto/rand" 22 | "fmt" 23 | ) 24 | 25 | // GenerateUUID generates an uuid 26 | // https://tools.ietf.org/html/rfc4122 27 | // crypto.rand use getrandom(2) or /dev/urandom 28 | // It is maybe occur an error due to system error 29 | // panic if an error occurred 30 | func GenerateUUID() string { 31 | uuid := make([]byte, 16) 32 | _, err := rand.Read(uuid) 33 | if err != nil { 34 | panic("generate an uuid failed, error: " + err.Error()) 35 | } 36 | // see section 4.1.1 37 | uuid[8] = uuid[8]&^0xc0 | 0x80 38 | // see section 4.1.3 39 | uuid[6] = uuid[6]&^0xf0 | 0x40 40 | return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]) 41 | } 42 | -------------------------------------------------------------------------------- /variable/protocolres.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | //nolint 19 | package variable 20 | 21 | import ( 22 | "context" 23 | "errors" 24 | "fmt" 25 | 26 | "mosn.io/api" 27 | ) 28 | 29 | var ( 30 | errUnregisterProtocolResource = "unregister Protocol resource, Protocol: " 31 | protocolVar map[string]string 32 | ) 33 | 34 | func init() { 35 | protocolVar = make(map[string]string) 36 | } 37 | 38 | // RegisterProtocolResource registers the resource as ProtocolResourceName 39 | // forexample protocolVar[Http1+api.URI] = http_request_uri var 40 | func RegisterProtocolResource(protocol api.ProtocolName, resource api.ProtocolResourceName, varname string) error { 41 | pr := convert(protocol, resource) 42 | if _, ok := protocolVar[pr]; ok { 43 | return errors.New("protocol resource already exists, name: " + pr) 44 | } 45 | 46 | protocolVar[pr] = fmt.Sprintf("%s_%s", protocol, varname) 47 | 48 | return nil 49 | } 50 | 51 | func convert(p api.ProtocolName, name api.ProtocolResourceName) string { 52 | return string(p) + string(name) 53 | } 54 | 55 | // GetProtocol returns the protocol name in the context. 56 | // This allows user defines the way to get protocol. 57 | // If the GetProtocol is undefined, the GetProtocolResource always returns an error. 58 | var GetProtocol func(ctx context.Context) (api.ProtocolName, error) 59 | 60 | // GetProtocolResource get URI,PATH,ARG var depends on ProtocolResourceName 61 | func GetProtocolResource(ctx context.Context, name api.ProtocolResourceName, data ...interface{}) (string, error) { 62 | if GetProtocol == nil { 63 | return "", errNoGetProtocol 64 | } 65 | p, err := GetProtocol(ctx) 66 | if err != nil { 67 | return "", err 68 | } 69 | if v, ok := protocolVar[convert(p, name)]; ok { 70 | // apend data behind if data exists 71 | if len(data) == 1 { 72 | v = fmt.Sprintf("%s%s", v, data[0]) 73 | } 74 | 75 | return GetString(ctx, v) 76 | } 77 | return "", errors.New(errUnregisterProtocolResource + string(p)) 78 | } 79 | -------------------------------------------------------------------------------- /variable/protocolres_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package variable 19 | 20 | import ( 21 | "context" 22 | "errors" 23 | "os" 24 | "testing" 25 | 26 | "github.com/stretchr/testify/require" 27 | "mosn.io/api" 28 | ) 29 | 30 | const ( 31 | HTTP1 api.ProtocolName = "Http1" 32 | Dubbo api.ProtocolName = "Dubbo" 33 | ProtocolName = "protocol" 34 | ) 35 | 36 | func TestMain(m *testing.M) { 37 | GetProtocol = func(ctx context.Context) (api.ProtocolName, error) { 38 | v := ctx.Value(ProtocolName) 39 | if proto, ok := v.(api.ProtocolName); ok { 40 | return proto, nil 41 | } 42 | return api.ProtocolName(""), errors.New("no protocol found") 43 | } 44 | os.Exit(m.Run()) 45 | } 46 | 47 | func newVariableContextWithProtocol(proto api.ProtocolName) context.Context { 48 | ctx := context.WithValue(context.Background(), ProtocolName, proto) 49 | return NewVariableContext(ctx) 50 | } 51 | 52 | func TestGetProtocolResource(t *testing.T) { 53 | request_path := "request_path" 54 | 55 | httpKey := string(HTTP1) + "_" + request_path 56 | dubboKey := string(Dubbo) + "_" + request_path 57 | m := map[string]string{ 58 | httpKey: "/http", 59 | dubboKey: "/dubbo", 60 | } 61 | 62 | for k, _ := range m { 63 | val := m[k] 64 | // register test variable 65 | Register(NewStringVariable(k, nil, func(ctx context.Context, variableValue *IndexedValue, data interface{}) (s string, err error) { 66 | return val, nil 67 | }, nil, 0)) 68 | } 69 | 70 | // register HTTP protocol resource var 71 | RegisterProtocolResource(HTTP1, api.PATH, request_path) 72 | 73 | ctx := newVariableContextWithProtocol(HTTP1) 74 | vv, err := GetProtocolResource(ctx, api.PATH) 75 | require.Nil(t, err) 76 | require.Equal(t, m[httpKey], vv) 77 | 78 | ctx = newVariableContextWithProtocol(Dubbo) 79 | vv, err = GetProtocolResource(ctx, api.PATH) 80 | require.EqualError(t, err, errUnregisterProtocolResource+string(Dubbo)) 81 | } 82 | 83 | func BenchmarkGetProtocolResource(b *testing.B) { 84 | ctx := prepareProtocolResource() 85 | for i := 0; i < b.N; i++ { 86 | _, err := GetProtocolResource(ctx, api.PATH) 87 | if err != nil { 88 | b.Error("get variable failed:", err) 89 | } 90 | } 91 | } 92 | 93 | func BenchmarkGetValue(b *testing.B) { 94 | 95 | ctx := prepareProtocolResource() 96 | for i := 0; i < b.N; i++ { 97 | _, err := GetString(ctx, string(api.PATH)) 98 | if err != nil { 99 | b.Error("get variable failed:", err) 100 | } 101 | } 102 | } 103 | 104 | func prepareProtocolResource() context.Context { 105 | name := "http_request_path" 106 | value := "/path" 107 | 108 | // register test variable 109 | Register(NewStringVariable(name, nil, func(ctx context.Context, variableValue *IndexedValue, data interface{}) (s string, err error) { 110 | return value, nil 111 | }, nil, 0)) 112 | 113 | // register HTTP protocol resource var 114 | RegisterProtocolResource(HTTP1, api.PATH, name) 115 | 116 | ctx := newVariableContextWithProtocol(HTTP1) 117 | return ctx 118 | } 119 | -------------------------------------------------------------------------------- /variable/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package variable 19 | 20 | import ( 21 | "context" 22 | "errors" 23 | ) 24 | 25 | const ( 26 | ValueNotFound = "-" 27 | ) 28 | 29 | var ( 30 | ErrValueNotFound = errors.New("value not found") 31 | ) 32 | 33 | // StringGetterFunc used to get the value of string-typed variable, the implementation should handle the field 34 | // Valid of IndexedValue if it was not nil, Valid means the value is valid. 35 | // 36 | // Function should return ValueNotFound("-") if target value not exists. 37 | // E.g. reference to the header which is not existed in current request. 38 | type StringGetterFunc func(ctx context.Context, value *IndexedValue, data interface{}) (string, error) 39 | 40 | // GetterFunc used to get the value of interface-typed variable 41 | type GetterFunc func(ctx context.Context, value *IndexedValue, data interface{}) (interface{}, error) 42 | 43 | // Getter used to get the value of interface-typed variable 44 | type Getter interface { 45 | Get(ctx context.Context, value *IndexedValue, data interface{}) (interface{}, error) 46 | } 47 | 48 | // StringSetterFunc used to set the value of string-typed variable 49 | type StringSetterFunc func(ctx context.Context, variableValue *IndexedValue, value string) error 50 | 51 | // SetterFunc used to set the value of interface-typed variable 52 | type SetterFunc func(ctx context.Context, variableValue *IndexedValue, value interface{}) error 53 | 54 | // Setter used to set the value of interface-typed variable 55 | type Setter interface { 56 | Set(ctx context.Context, variableValue *IndexedValue, value interface{}) error 57 | } 58 | 59 | // Variable provides a flexible and convenient way to pass information 60 | type Variable interface { 61 | // variable name 62 | Name() string 63 | // variable data, which is useful for getter/setter 64 | Data() interface{} 65 | // value getter 66 | Getter() Getter 67 | // value setter 68 | Setter() Setter 69 | } 70 | 71 | // IndexedValue used to store result value 72 | type IndexedValue struct { 73 | Valid bool 74 | 75 | data interface{} 76 | } 77 | 78 | // Indexer indicates that variable needs to be cached by using pre-allocated IndexedValue 79 | type Indexer interface { 80 | // variable index 81 | GetIndex() uint32 82 | 83 | // set index to variable 84 | SetIndex(index uint32) 85 | } 86 | --------------------------------------------------------------------------------