| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package utils |
| |
| import ( |
| "bytes" |
| "compress/gzip" |
| "context" |
| "encoding/hex" |
| "fmt" |
| "io/ioutil" |
| "net" |
| "net/url" |
| "os" |
| "runtime" |
| "strconv" |
| "strings" |
| "sync/atomic" |
| "time" |
| |
| "github.com/apache/rocketmq-clients/golang/v5/metadata" |
| v2 "github.com/apache/rocketmq-clients/golang/v5/protocol/v2" |
| "github.com/valyala/fastrand" |
| "go.opencensus.io/trace" |
| MD "google.golang.org/grpc/metadata" |
| ) |
| |
| func Mod(n int32, m int) int { |
| if int32(m) <= 0 { |
| return 0 |
| } |
| i := int32(n % int32(m)) |
| if i < 0 { |
| i += int32(m) |
| } |
| return int(i) |
| } |
| |
| func Mod64(n int64, m int) int { |
| if int64(m) <= 0 { |
| return 0 |
| } |
| i := int64(n % int64(m)) |
| if i < 0 { |
| i += int64(m) |
| } |
| return int(i) |
| } |
| |
| func ParseAddress(address *v2.Address) string { |
| if address == nil { |
| return "" |
| } |
| return fmt.Sprintf("%s:%d", address.Host, address.Port) |
| } |
| |
| func ParseTarget(target string) (*v2.Endpoints, error) { |
| ret := &v2.Endpoints{ |
| Scheme: v2.AddressScheme_DOMAIN_NAME, |
| } |
| addressRawList := strings.Split(target, ";") |
| for _, path := range addressRawList { |
| if len(path) == 0 { |
| continue |
| } |
| address := &v2.Address{ |
| Host: "", |
| Port: 80, |
| } |
| if u, err := url.Parse(path); err != nil { |
| address.Host = path |
| ret.Scheme = v2.AddressScheme_IPv4 |
| } else { |
| if u.Host != "" { |
| address.Host = u.Host |
| } |
| } |
| paths := strings.Split(path, ":") |
| if len(paths) > 1 { |
| if port, err2 := strconv.ParseInt(paths[1], 10, 32); err2 == nil { |
| address.Port = int32(port) |
| } |
| address.Host = paths[0] |
| } else { |
| return nil, fmt.Errorf("parse target failed, target=%s", target) |
| } |
| ret.Addresses = append(ret.Addresses, address) |
| } |
| return ret, nil |
| } |
| |
| func GetOsDescription() string { |
| osName := os.Getenv("os.name") |
| if len(osName) == 0 { |
| return "" |
| } |
| version := os.Getenv("os.version") |
| if len(version) == 0 { |
| return osName |
| } |
| return osName + " " + version |
| } |
| |
| var hostName = "" |
| |
| func HostName() string { |
| if len(hostName) != 0 { |
| return hostName |
| } |
| hostName_, err := os.Hostname() |
| if err != nil { |
| hostName_ = "HOST_NAME_NOT_FOUND" |
| } else { |
| hostName = hostName_ |
| } |
| return hostName |
| } |
| |
| func MatchMessageType(mq *v2.MessageQueue, messageType v2.MessageType) bool { |
| for _, item := range mq.GetAcceptMessageTypes() { |
| if item == messageType { |
| return true |
| } |
| } |
| return false |
| } |
| |
| func GZIPDecode(in []byte) ([]byte, error) { |
| reader, err := gzip.NewReader(bytes.NewReader(in)) |
| if err != nil { |
| var out []byte |
| return out, err |
| } |
| defer reader.Close() |
| return ioutil.ReadAll(reader) |
| } |
| |
| var clientIdx int64 = 0 |
| |
| func GenClientID() string { |
| hostName := HostName() |
| processID := os.Getpid() |
| nextIdx := atomic.AddInt64(&clientIdx, 1) - 1 |
| nanotime := time.Now().UnixNano() / 1000 |
| return fmt.Sprintf("%s@%d@%d@%s", hostName, processID, nextIdx, strconv.FormatInt(nanotime, 36)) |
| } |
| |
| func SelectAnAddress(endpoints *v2.Endpoints) *v2.Address { |
| if endpoints == nil { |
| return nil |
| } |
| addresses := endpoints.GetAddresses() |
| idx := fastrand.Uint32n(uint32(len(addresses))) |
| selectAddress := addresses[idx] |
| return selectAddress |
| } |
| |
| func CompareEndpoints(e1, e2 *v2.Endpoints) bool { |
| if e1 == e2 { |
| return true |
| } |
| if e1 == nil || e2 == nil { |
| return false |
| } |
| if e1.Scheme != e2.Scheme { |
| return false |
| } |
| |
| return CompareAddress(e1.GetAddresses(), e2.GetAddresses()) |
| } |
| |
| func CompareAddress(a1, a2 []*v2.Address) bool { |
| if len(a1) != len(a2) { |
| return false |
| } |
| tmpMap := make(map[string]bool) |
| for _, a := range a1 { |
| tmpMap[a.String()] = true |
| } |
| for _, a := range a2 { |
| str := a.String() |
| if _, ok := tmpMap[str]; ok { |
| delete(tmpMap, str) |
| } else { |
| return false |
| } |
| } |
| return len(tmpMap) == 0 |
| } |
| |
| func FromTraceParentHeader(header string) (*trace.SpanContext, bool) { |
| if len(header) != 55 || header[0] != '0' || |
| header[1] != '0' || |
| header[2] != '-' || |
| header[35] != '-' || |
| header[52] != '-' { |
| return nil, false |
| } |
| trace_id_str := header[3 : 3+32] |
| span_id_str := header[36 : 36+16] |
| options_str := header[53 : 53+2] |
| trace_id, err := hex.DecodeString(trace_id_str) |
| if err != nil || len(trace_id) != 16 { |
| return nil, false |
| } |
| span_id, err := hex.DecodeString(span_id_str) |
| if err != nil || len(span_id) != 8 { |
| return nil, false |
| } |
| options, err := hex.DecodeString(options_str) |
| if err != nil || len(options) != 1 { |
| return nil, false |
| } |
| sc := trace.SpanContext{ |
| TraceOptions: trace.TraceOptions(options[0]), |
| } |
| copy(sc.TraceID[:], trace_id[:]) |
| copy(sc.SpanID[:], span_id[:]) |
| return &sc, true |
| } |
| |
| func ToTraceParentHeader(sc *trace.SpanContext) string { |
| if sc == nil { |
| return "00-00000000000000000000000000000000-0000000000000000-00" |
| } |
| return fmt.Sprintf("00-%s-%s-%02s", sc.TraceID.String(), sc.SpanID.String(), strconv.FormatUint(uint64(sc.TraceOptions), 16)) |
| } |
| |
| func GetenvWithDef(key, def string) string { |
| val := os.Getenv(key) |
| if val == "" { |
| val = def |
| } |
| return val |
| } |
| |
| func DumpStacks() string { |
| buf := make([]byte, 16384) |
| buf = buf[:runtime.Stack(buf, true)] |
| return string(buf) |
| } |
| |
| func GetMacAddress() []byte { |
| netInterfaces, err := net.Interfaces() |
| if err != nil { |
| return nil |
| } |
| |
| for _, netInterface := range netInterfaces { |
| macAddr := netInterface.HardwareAddr |
| if len(macAddr) == 0 { |
| continue |
| } |
| return macAddr |
| } |
| return nil |
| } |
| |
| func GetRequestID(ctx context.Context) string { |
| ret := "nil" |
| md, ok := MD.FromOutgoingContext(ctx) |
| if ok { |
| ret = fmt.Sprintf("%v", md.Get(metadata.RequestID)) |
| } |
| return ret |
| } |