From dd306241ec57f3a8a396c86d4ec9703a6c53b09f Mon Sep 17 00:00:00 2001 From: pnguyen215 Date: Sat, 23 Sep 2023 10:13:00 +0700 Subject: [PATCH] :recycle: refactor: updated codebase #14 --- pkg/ami/ami_callback.go | 15 +- pkg/ami/ami_cdr.go | 41 +++--- pkg/ami/ami_channel.go | 9 +- pkg/ami/ami_chanspy.go | 19 ++- pkg/ami/ami_class.go | 31 ++--- pkg/ami/ami_command.go | 8 +- pkg/ami/ami_conf.go | 29 ++-- pkg/ami/ami_dialplan.go | 3 +- pkg/ami/ami_dictionary.go | 13 +- pkg/ami/ami_event.go | 3 +- pkg/ami/ami_helper.go | 248 ++++++++++++++++++++++++++++++++- pkg/ami/ami_manager.go | 5 +- pkg/ami/ami_map.go | 9 +- pkg/ami/ami_message.go | 21 ++- pkg/ami/ami_model.go | 2 +- pkg/ami/ami_originate.go | 7 +- pkg/ami/ami_socket.go | 23 ++- pkg/ami/ami_update_config.go | 4 +- pkg/ami/utils/ami_utils.go | 262 ----------------------------------- 19 files changed, 356 insertions(+), 396 deletions(-) diff --git a/pkg/ami/ami_callback.go b/pkg/ami/ami_callback.go index d8dd318..ba98ffa 100644 --- a/pkg/ami/ami_callback.go +++ b/pkg/ami/ami_callback.go @@ -7,7 +7,6 @@ import ( "time" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) type AMICallbackService interface { @@ -72,7 +71,7 @@ func (a *AMICallbackHandler) AppendIgnoredEvents(values ...string) *AMICallbackH } func (a *AMICallbackHandler) Json() string { - return utils.ToJson(a) + return JsonString(a) } func (h *AMICallbackHandler) Send() (AMIResultRaw, error) { @@ -100,14 +99,14 @@ func (h *AMICallbackHandler) Send() (AMIResultRaw, error) { } if len(response) > 0 && err == nil { - if h.Socket.AllowTrace { + if h.Socket.DebugMode { log.Printf("Send(). callback return for the %v time(s) and waste time = %v", i, _end) } break } } - if h.Socket.AllowTrace { + if h.Socket.DebugMode { log.Printf("Send(). callback total waste time = %v", total) } @@ -140,14 +139,14 @@ func (h *AMICallbackHandler) SendLevel() (AMIResultRawLevel, error) { } if len(response) > 0 && err == nil { - if h.Socket.AllowTrace { + if h.Socket.DebugMode { log.Printf("SendLevel(). callback return for the %v time(s) and waste time = %v", i, _end) } break } } - if h.Socket.AllowTrace { + if h.Socket.DebugMode { log.Printf("SendLevel(). callback total waste time = %v", total) } @@ -179,14 +178,14 @@ func (h *AMICallbackHandler) SendSuperLevel() ([]AMIResultRaw, error) { } if len(response) > 0 && err == nil { - if h.Socket.AllowTrace { + if h.Socket.DebugMode { log.Printf("SendSuperLevel(). callback return for the %v time(s) and waste time = %v", i, _end) } break } } - if h.Socket.AllowTrace { + if h.Socket.DebugMode { log.Printf("SendSuperLevel(). callback total waste time = %v", total) } diff --git a/pkg/ami/ami_cdr.go b/pkg/ami/ami_cdr.go index ff6b420..e898e67 100644 --- a/pkg/ami/ami_cdr.go +++ b/pkg/ami/ami_cdr.go @@ -8,7 +8,6 @@ import ( "time" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewAMICdr() *AMICdr { @@ -19,27 +18,27 @@ func NewAMICdr() *AMICdr { } func (r *AMICdr) SetEvent(value string) *AMICdr { - r.Event = utils.TrimAllSpace(value) + r.Event = TrimStringSpaces(value) return r } func (r *AMICdr) SetAccountCode(value string) *AMICdr { - r.AccountCode = utils.TrimAllSpace(value) + r.AccountCode = TrimStringSpaces(value) return r } func (r *AMICdr) SetSource(value string) *AMICdr { - r.Source = utils.TrimAllSpace(value) + r.Source = TrimStringSpaces(value) return r } func (r *AMICdr) SetDestination(value string) *AMICdr { - r.Destination = utils.TrimAllSpace(value) + r.Destination = TrimStringSpaces(value) return r } func (r *AMICdr) SetDestinationContext(value string) *AMICdr { - r.DestinationContext = utils.TrimAllSpace(value) + r.DestinationContext = TrimStringSpaces(value) return r } @@ -49,22 +48,22 @@ func (r *AMICdr) SetCallerId(value string) *AMICdr { } func (r *AMICdr) SetChannel(value string) *AMICdr { - r.Channel = utils.TrimAllSpace(value) + r.Channel = TrimStringSpaces(value) return r } func (r *AMICdr) SetDestinationChannel(value string) *AMICdr { - r.DestinationChannel = utils.TrimAllSpace(value) + r.DestinationChannel = TrimStringSpaces(value) return r } func (r *AMICdr) SetLastApplication(value string) *AMICdr { - r.LastApplication = utils.TrimAllSpace(value) + r.LastApplication = TrimStringSpaces(value) return r } func (r *AMICdr) SetLastData(value string) *AMICdr { - r.LastData = utils.TrimAllSpace(value) + r.LastData = TrimStringSpaces(value) return r } @@ -162,12 +161,12 @@ func (r *AMICdr) SetBillableSecondWith(value string) *AMICdr { } func (r *AMICdr) SetDisposition(value string) *AMICdr { - r.Disposition = utils.TrimAllSpace(value) + r.Disposition = TrimStringSpaces(value) return r } func (r *AMICdr) SetAmaFlag(value string) *AMICdr { - r.AmaFlags = utils.TrimAllSpace(value) + r.AmaFlags = TrimStringSpaces(value) return r } @@ -200,7 +199,7 @@ func (r *AMICdr) SetPrivilege(value string) *AMICdr { } func (r *AMICdr) SetDirection(value string) *AMICdr { - r.Direction = utils.TrimAllSpace(value) + r.Direction = TrimStringSpaces(value) return r } @@ -210,22 +209,22 @@ func (r *AMICdr) SetFlowCall(value string) *AMICdr { } func (r *AMICdr) SetTypeDirection(value string) *AMICdr { - r.TypeDirection = utils.TrimAllSpace(value) + r.TypeDirection = TrimStringSpaces(value) return r } func (r *AMICdr) SetUserExten(value string) *AMICdr { - r.UserExtension = utils.TrimAllSpace(value) + r.UserExtension = TrimStringSpaces(value) return r } func (r *AMICdr) SetPhoneNumber(value string) *AMICdr { - r.PhoneNumber = utils.TrimAllSpace(value) + r.PhoneNumber = TrimStringSpaces(value) return r } func (r *AMICdr) SetExtenSplitterSymbol(value string) *AMICdr { - r.ExtenSplitterSymbol = utils.TrimAllSpace(value) + r.ExtenSplitterSymbol = TrimStringSpaces(value) return r } @@ -235,7 +234,7 @@ func (r *AMICdr) SetPlaybackUrl(value string) *AMICdr { } func (r *AMICdr) Json() string { - return utils.ToJson(r) + return JsonString(r) } func (r *AMICdr) IsCdrNoAnswer() bool { @@ -346,8 +345,8 @@ func ParseCdr(e *AMIMessage, d *AMIDictionary) *AMICdr { // detect outbound, inbound // if the field destination is phone number, so mark this cdr belong to outbound, otherwise mark as inbound form := "flow_call_from_'%v'_to_'%v'" - phone := utils.RemovePrefix(r.Destination, e.PhonePrefix...) - if IsPhoneNumberAbsolute(phone, e.Region) { + phone := RemoveStringPrefix(r.Destination, e.PhonePrefix...) + if IsPhoneNumberWith(phone, e.Region) { flow := fmt.Sprintf(form, r.Channel, phone) r.SetFlowCall(flow) r.SetDirection(config.AmiOutboundDirection) @@ -386,7 +385,7 @@ func ParseCdr(e *AMIMessage, d *AMIDictionary) *AMICdr { r.SetPhoneNumber(r.Source) } if !inCase { - log.Printf("ParseCdr, CDR exception case = %v", utils.ToJson(r)) + log.Printf("ParseCdr, CDR exception case = %v", JsonString(r)) } } return r diff --git a/pkg/ami/ami_channel.go b/pkg/ami/ami_channel.go index 9f85854..571f526 100644 --- a/pkg/ami/ami_channel.go +++ b/pkg/ami/ami_channel.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewChannel() *AMIChannel { @@ -18,7 +17,7 @@ func NewChannel() *AMIChannel { func (c *AMIChannel) SetChannelProtocol(protocol string) *AMIChannel { if ok := config.AmiChannelProtocols[protocol]; !ok { - msg := fmt.Sprintf(config.AmiErrorProtocolMessage, strings.Join(utils.Keys(config.AmiChannelProtocols), ",")) + msg := fmt.Sprintf(config.AmiErrorProtocolMessage, strings.Join(GetKeys(config.AmiChannelProtocols), ",")) log.Panic(config.AmiErrorInvalidProtocol, "\n", msg) } c.ChannelProtocol = protocol @@ -66,10 +65,10 @@ func (c *AMIChannel) ValidWith(channelProtocol string, regex string, digitsExten if len(digitsExten) == 0 { return false } - if utils.IsEmptyAbsolute(extension) { + if IsStringEmpty(extension) { return false } - if utils.IsEmptyAbsolute(regex) { + if IsStringEmpty(regex) { return false } c.SetChannelProtocol(channelProtocol) @@ -103,7 +102,7 @@ func (c *AMIChannel) ValidSIPDefaultWith(digitsExten []interface{}, extension st // Return as form sip@127.0.0.1 func (c *AMIChannel) JoinHostChannel(protocol, ip string) string { c.SetChannelProtocol(protocol) - host, _, _ := utils.IPDecode(ip) + host, _, _ := DecodeIp(ip) form := "%v@%v" if len(host) > 0 { diff --git a/pkg/ami/ami_chanspy.go b/pkg/ami/ami_chanspy.go index 67eb393..0d2b110 100644 --- a/pkg/ami/ami_chanspy.go +++ b/pkg/ami/ami_chanspy.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewAMIPayloadChanspy() *AMIPayloadChanspy { @@ -18,20 +17,20 @@ func NewAMIPayloadChanspy() *AMIPayloadChanspy { func (s *AMIPayloadChanspy) SetJoin(value string) *AMIPayloadChanspy { ok := config.AmiChanspy[value] if !ok { - msg := fmt.Sprintf(config.AmiErrorChanspyMessage, strings.Join(utils.Keys(config.AmiChanspy), ",")) + msg := fmt.Sprintf(config.AmiErrorChanspyMessage, strings.Join(GetKeys(config.AmiChanspy), ",")) log.Panic(config.AmiErrorInvalidChanspy, "\n", msg) } - s.Join = utils.TrimAllSpace(value) + s.Join = TrimStringSpaces(value) return s } func (s *AMIPayloadChanspy) SetSourceExten(value string) *AMIPayloadChanspy { - s.SourceExten = utils.TrimAllSpace(value) + s.SourceExten = TrimStringSpaces(value) return s } func (s *AMIPayloadChanspy) SetCurrentExten(value string) *AMIPayloadChanspy { - s.CurrentExten = utils.TrimAllSpace(value) + s.CurrentExten = TrimStringSpaces(value) return s } @@ -47,10 +46,10 @@ func (s *AMIPayloadChanspy) SetAllowDebug(value bool) *AMIPayloadChanspy { } func (s *AMIPayloadChanspy) CommandChanspy(channelExten string) string { - if utils.IsEmptyAbsolute(s.Join) { + if IsStringEmpty(s.Join) { return "" } - if utils.IsEmptyAbsolute(channelExten) { + if IsStringEmpty(channelExten) { return "" } if strings.EqualFold(s.Join, config.AmiChanspySpy) { @@ -69,13 +68,13 @@ func (s *AMIPayloadChanspy) CommandChanspy(channelExten string) string { func Chanspy(ctx context.Context, s AMISocket, ch AMIPayloadChanspy) (AMIResultRawLevel, error) { ok := config.AmiChanspy[ch.Join] if !ok { - msg := fmt.Sprintf(config.AmiErrorChanspyMessage, strings.Join(utils.Keys(config.AmiChanspy), ",")) + msg := fmt.Sprintf(config.AmiErrorChanspyMessage, strings.Join(GetKeys(config.AmiChanspy), ",")) log.Panic(config.AmiErrorInvalidChanspy, "\n", msg) } - if utils.IsEmptyAbsolute(ch.SourceExten) { + if IsStringEmpty(ch.SourceExten) { return AMIResultRawLevel{}, fmt.Errorf("Source exten is required") } - if utils.IsEmptyAbsolute(ch.CurrentExten) { + if IsStringEmpty(ch.CurrentExten) { return AMIResultRawLevel{}, fmt.Errorf("Current exten is required") } sourceValid, err := HasSIPPeerStatus(ctx, s, ch.SourceExten) diff --git a/pkg/ami/ami_class.go b/pkg/ami/ami_class.go index 2b44d12..959b410 100644 --- a/pkg/ami/ami_class.go +++ b/pkg/ami/ami_class.go @@ -2,7 +2,6 @@ package ami import ( "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) var chargingEvents *map[string]string = &map[string]string{} @@ -16,20 +15,20 @@ func (e *AMIEvent) SnapChargingEvent() *map[string]string { _merged := make(map[string]string) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassCommands)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassSecurities)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassCalls)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassSystems)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassUsers)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassDialPlans)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassAgents)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassAgis)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassAocs)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassCallDetailRecords)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassChannelEventLoggings)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClasses)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassReports)) - _merged = utils.MergeMaps(_merged, e.SwapCharging(config.AmiClassDualToneMultiFrequencies)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassCommands)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassSecurities)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassCalls)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassSystems)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassUsers)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassDialPlans)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassAgents)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassAgis)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassAocs)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassCallDetailRecords)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassChannelEventLoggings)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClasses)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassReports)) + _merged = MergeMaps(_merged, e.SwapCharging(config.AmiClassDualToneMultiFrequencies)) chargingEvents = &_merged return chargingEvents @@ -37,7 +36,7 @@ func (e *AMIEvent) SnapChargingEvent() *map[string]string { // SnapChargingEventWith func (e *AMIEvent) SnapChargingEventWith(ls map[string][]string) *map[string]string { - chargingEvents := utils.MergeMaps(*chargingEvents, e.SwapCharging(ls)) + chargingEvents := MergeMaps(*chargingEvents, e.SwapCharging(ls)) return &chargingEvents } diff --git a/pkg/ami/ami_command.go b/pkg/ami/ami_command.go index 99d5cb1..9b00d16 100644 --- a/pkg/ami/ami_command.go +++ b/pkg/ami/ami_command.go @@ -106,7 +106,7 @@ func (a *AMICommand) DoGetResult(ctx context.Context, s AMISocket, c *AMICommand _response := raw.GetVal(strings.ToLower(config.AmiResponseKey)) if len(acceptedEvents) == 0 { - if s.AllowTrace { + if s.DebugMode { log.Printf(config.AmiErrorMissingSocketEvent, _event, _response) } break @@ -114,7 +114,7 @@ func (a *AMICommand) DoGetResult(ctx context.Context, s AMISocket, c *AMICommand if len(ignoreEvents) > 0 { if slices.Contains(ignoreEvents, _event) || (_response != "" && !strings.EqualFold(_response, config.AmiStatusSuccessKey)) { - if s.AllowTrace { + if s.DebugMode { log.Printf(config.AmiErrorBreakSocketIgnoredEvent, _event) } break @@ -145,7 +145,7 @@ func (a *AMICommand) Read(ctx context.Context, socket AMISocket) (AMIResultRaw, if socket.MaxConcurrencyMillis > 0 { if concurrency >= socket.MaxConcurrencyMillis { - if socket.AllowTrace { + if socket.DebugMode { log.Printf("Read(). max over concurrency = %v (millis), the concurrency allowed = %v (millis)", concurrency, socket.MaxConcurrencyMillis) } @@ -176,7 +176,7 @@ func (a *AMICommand) ReadLevel(ctx context.Context, socket AMISocket) (AMIResult if socket.MaxConcurrencyMillis > 0 { if concurrency >= socket.MaxConcurrencyMillis { - if socket.AllowTrace { + if socket.DebugMode { log.Printf("ReadLevel(). max over concurrency = %v (millis), the concurrency allowed = %v (millis)", concurrency, socket.MaxConcurrencyMillis) } diff --git a/pkg/ami/ami_conf.go b/pkg/ami/ami_conf.go index dd97ad5..cff7d25 100644 --- a/pkg/ami/ami_conf.go +++ b/pkg/ami/ami_conf.go @@ -5,7 +5,6 @@ import ( "time" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) var ( @@ -113,27 +112,27 @@ func (e *AMIExtensionStatus) SetActionId(value string) *AMIExtensionStatus { } func (e *AMIExtensionStatus) SetResponse(value string) *AMIExtensionStatus { - e.Response = utils.TrimAllSpace(value) + e.Response = TrimStringSpaces(value) return e } func (e *AMIExtensionStatus) SetMessage(value string) *AMIExtensionStatus { - e.Message = utils.TrimAllSpace(value) + e.Message = TrimStringSpaces(value) return e } func (e *AMIExtensionStatus) SetContext(value string) *AMIExtensionStatus { - e.Context = utils.TrimAllSpace(value) + e.Context = TrimStringSpaces(value) return e } func (e *AMIExtensionStatus) SetExtension(value string) *AMIExtensionStatus { - e.Extension = utils.TrimAllSpace(value) + e.Extension = TrimStringSpaces(value) return e } func (e *AMIExtensionStatus) SetHint(value string) *AMIExtensionStatus { - e.Hint = utils.TrimAllSpace(value) + e.Hint = TrimStringSpaces(value) return e } @@ -149,7 +148,7 @@ func (e *AMIExtensionStatus) SetStatusInt(value int) *AMIExtensionStatus { } func (e *AMIExtensionStatus) SetStatusText(value string) *AMIExtensionStatus { - e.StatusText = utils.TrimAllSpace(value) + e.StatusText = TrimStringSpaces(value) return e } @@ -189,27 +188,27 @@ func (e *AMIPeerStatus) SetActionId(value string) *AMIPeerStatus { } func (e *AMIPeerStatus) SetChannelType(value string) *AMIPeerStatus { - e.ChannelType = utils.TrimAllSpace(value) + e.ChannelType = TrimStringSpaces(value) return e } func (e *AMIPeerStatus) SetEvent(value string) *AMIPeerStatus { - e.Event = utils.TrimAllSpace(value) + e.Event = TrimStringSpaces(value) return e } func (e *AMIPeerStatus) SetPeer(value string) *AMIPeerStatus { - e.Peer = utils.TrimAllSpace(value) + e.Peer = TrimStringSpaces(value) return e } func (e *AMIPeerStatus) SetPeerStatus(value string) *AMIPeerStatus { - e.PeerStatus = utils.TrimAllSpace(value) + e.PeerStatus = TrimStringSpaces(value) return e } func (e *AMIPeerStatus) SetPrivilege(value string) *AMIPeerStatus { - e.Privilege = utils.TrimAllSpace(value) + e.Privilege = TrimStringSpaces(value) return e } @@ -229,7 +228,7 @@ func (e *AMIPeerStatus) SetTimeInMsInt(value int) *AMIPeerStatus { } func (e *AMIPeerStatus) SetPrePublishedAt(value string) *AMIPeerStatus { - e.PrePublishedAt = utils.TrimAllSpace(value) + e.PrePublishedAt = TrimStringSpaces(value) return e } @@ -239,11 +238,11 @@ func (e *AMIPeerStatus) SetPublishedAt(value time.Time) *AMIPeerStatus { } func (e *AMIPeerStatusGuard) SetDateTimeLayout(value string) *AMIPeerStatusGuard { - e.DateTimeLayout = utils.TrimAllSpace(value) + e.DateTimeLayout = TrimStringSpaces(value) return e } func (e *AMIPeerStatusGuard) SetTimezone(value string) *AMIPeerStatusGuard { - e.Timezone = utils.TrimAllSpace(value) + e.Timezone = TrimStringSpaces(value) return e } diff --git a/pkg/ami/ami_dialplan.go b/pkg/ami/ami_dialplan.go index eee3ee2..26f1641 100644 --- a/pkg/ami/ami_dialplan.go +++ b/pkg/ami/ami_dialplan.go @@ -4,7 +4,6 @@ import ( "context" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewAMIPayloadExtension() *AMIPayloadExtension { @@ -43,7 +42,7 @@ func (e *AMIPayloadExtension) SetReplace(value string) *AMIPayloadExtension { } func (e *AMIPayloadExtension) SetApplicationDataWith(v interface{}) *AMIPayloadExtension { - e.SetApplicationData(utils.ToJson(v)) + e.SetApplicationData(JsonString(v)) return e } diff --git a/pkg/ami/ami_dictionary.go b/pkg/ami/ami_dictionary.go index 8ad711c..d87fc9b 100644 --- a/pkg/ami/ami_dictionary.go +++ b/pkg/ami/ami_dictionary.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) var overlapDictionaries *[]AMIEventDictionary = &[]AMIEventDictionary{} @@ -269,7 +268,7 @@ func (d *AMIDictionary) TranslateField(field string) string { return strings.ToLower(value) } else { if d.AllowForceTranslate { - value = utils.TakeValueFromKey(dictionary.Dictionaries, field) + value = GetValByKey(dictionary.Dictionaries, field) if len(value) > 0 { return value } @@ -289,7 +288,7 @@ func (d *AMIDictionary) TranslateFieldWith(field string, dictionaries []AMIEvent return strings.ToLower(v) } else { if d.AllowForceTranslate { - value := utils.TakeValueFromKey(e.Dictionaries, field) + value := GetValByKey(e.Dictionaries, field) if len(value) > 0 { return value } @@ -303,7 +302,7 @@ func (d *AMIDictionary) TranslateFieldWith(field string, dictionaries []AMIEvent func (d *AMIDictionary) TranslateKey(value string) string { dictionary, _ := d.FindDictionaryByKey(config.AmiListenerEventCommon) - _key := utils.TakeKeyFromValue(dictionary.Dictionaries, value) + _key := GetKeyByVal(dictionary.Dictionaries, value) if !strings.EqualFold(_key, value) { return _key @@ -318,7 +317,7 @@ func (d *AMIDictionary) TranslateKeyWith(value string, dictionaries []AMIEventDi } for _, e := range dictionaries { - _key := utils.TakeKeyFromValue(e.Dictionaries, value) + _key := GetKeyByVal(e.Dictionaries, value) if !strings.EqualFold(_key, value) { return _key } @@ -337,7 +336,7 @@ func (d *AMIDictionary) Reset() { } func (d *AMIDictionary) Json() string { - return utils.ToJson(*overlapDictionaries) + return JsonString(*overlapDictionaries) } func (d *AMIDictionary) LenTranslatorCommon() int { @@ -379,7 +378,7 @@ func (d *AMIDictionary) AddKeysTranslator(script map[string]string) *AMIDictiona // Example: // https://raw.githubusercontent.com/pnguyen215/gear-insights-free/master/ami.dictionaries.json func (d *AMIDictionary) AddKeyLinkTranslator(link string) *AMIDictionary { - keys, err := utils.ForkDictionaryFromLink(link, false) + keys, err := ForkDictionaryFromLink(link, false) if err != nil { return d diff --git a/pkg/ami/ami_event.go b/pkg/ami/ami_event.go index af52b45..e5b8f03 100644 --- a/pkg/ami/ami_event.go +++ b/pkg/ami/ami_event.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewEventListener() *AMIEvent { @@ -31,7 +30,7 @@ func (m *AMIEvent) AppendPhonePrefix(values ...string) *AMIEvent { } func (m *AMIEvent) SetRegion(value string) *AMIEvent { - m.Region = utils.TrimAllSpace(value) + m.Region = TrimStringSpaces(value) return m } diff --git a/pkg/ami/ami_helper.go b/pkg/ami/ami_helper.go index 0c4910f..c579611 100644 --- a/pkg/ami/ami_helper.go +++ b/pkg/ami/ami_helper.go @@ -4,19 +4,26 @@ import ( "bufio" "bytes" "context" + "encoding/base64" + "encoding/json" "fmt" "log" "net" + "net/http" "net/textproto" + "net/url" "os" "reflect" "regexp" "strconv" "strings" + "time" + "github.com/go-resty/resty/v2" "github.com/nyaruka/phonenumbers" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" + + jsonI "github.com/json-iterator/go" ) // OpenContext @@ -64,7 +71,7 @@ func OpenDialWith(network, ip string, port int) (net.Conn, error) { return nil, AMIErrorNew("AMI: Port must be positive number") } - host, _port, _ := utils.IPDecode(ip) + host, _port, _ := DecodeIp(ip) if len(host) > 0 && len(_port) > 0 { form := net.JoinHostPort(host, _port) @@ -424,15 +431,15 @@ func TransformKeyLevel(response AMIResultRawLevel, d *AMIDictionary) AMIResultRa } func IsPhoneNumber(phone string) bool { - if utils.IsEmptyAbsolute(phone) { + if IsStringEmpty(phone) { return false } matcher := regexp.MustCompile(`^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$`) return matcher.MatchString(phone) } -func IsPhoneNumberAbsolute(phone string, region string) bool { - if utils.IsEmptyAbsolute(phone) { +func IsPhoneNumberWith(phone string, region string) bool { + if IsStringEmpty(phone) { return false } @@ -445,3 +452,234 @@ func IsPhoneNumberAbsolute(phone string, region string) bool { l := phonenumbers.IsPossibleNumber(p) return v && l && IsPhoneNumber(phone) } + +func RemoveStringPrefix(str string, prefix ...string) string { + if IsStringEmpty(str) { + return str + } + if len(prefix) == 0 { + return str + } + for _, v := range prefix { + str = strings.TrimPrefix(str, v) + } + return str +} + +func IsStringEmpty(str string) bool { + return len(str) == 0 || str == "" || strings.TrimSpace(str) == "" +} + +// ForkDictionaryFromLink +// Link must be provided to file formatted as json +// Return maps[string]string +func ForkDictionaryFromLink(link string, debug bool) (*map[string]string, error) { + client := resty.New() + result := &map[string]string{} + // Set retry count to non zero to enable retries + client.SetRetryCount(3). + // You can override initial retry wait time. + // Default is 100 milliseconds. + SetRetryWaitTime(10 * time.Second). + // MaxWaitTime can be overridden as well. + // Default is 2 seconds. + SetRetryMaxWaitTime(20 * time.Second). + AddRetryCondition( + // RetryConditionFunc type is for retry condition function + // input: non-nil Response OR request execution error + func(r *resty.Response, err error) bool { + return r.StatusCode() >= http.StatusBadRequest && r.StatusCode() <= http.StatusNetworkAuthenticationRequired + }, + ). + // Enable debug mode + SetDebug(debug). + // Add headers + SetHeaders(map[string]string{ + "Content-Type": "application/json", + }) + + _, err := client.R().SetResult(&result).ForceContentType("application/json").Get(link) + + if err != nil { + log.Printf("fork dictionary from link %v has error occurred %v", link, err.Error()) + return result, err + } + + return result, nil +} + +func VarsMap(values []string) map[string]string { + r := make(map[string]string) + for _, value := range values { + k, v := VarsSplit(value) + r[k] = v + } + return r +} + +func VarsSplit(value string) (string, string) { + s := strings.SplitN(value, "=", 2) + k := s[0] + if len(s) == 1 { + return k, "" + } + return k, s[1] +} + +func UsableRConnection(ip string, port int) (bool, error) { + timeout := time.Second + conn, err := net.DialTimeout(config.AmiNetworkTcpKey, net.JoinHostPort(ip, strconv.Itoa(port)), timeout) + if err != nil { + log.Printf("Connecting error: %v", err) + return false, err + } + if conn != nil { + defer conn.Close() + log.Printf("Opened on: %s", net.JoinHostPort(ip, strconv.Itoa(port))) + return true, nil + } + return false, nil +} + +func UsableRConnectionWith(ip string, ports []int) (bool, error) { + for _, port := range ports { + if ok, err := UsableRConnection(ip, port); err != nil { + return ok, err + } + } + return true, nil +} + +// DecodeIp +// Decode IP into 2 parts: host, port +func DecodeIp(ip string) (string, string, error) { + u, err := url.Parse(ip) + if err != nil { + return "", "", err + } + host, port, err := net.SplitHostPort(u.Host) + return host, port, err +} + +func GetKeyByVal(values map[string]string, value string) string { + if len(values) <= 0 { + return value + } + for k, v := range values { + if strings.EqualFold(v, value) { + return k + } + } + return value +} + +func GetValByKey(values map[string]string, key string) string { + if len(values) <= 0 { + return key + } + for k, v := range values { + if strings.EqualFold(k, key) { + return v + } + } + return "" +} + +func GetKeys(in interface{}) (keys []string) { + switch z := in.(type) { + case map[string]int: + case map[string]int32: + case map[string]int64: + case map[string]float32: + case map[string]float64: + case map[string]string: + case map[string]bool: + for k := range z { + keys = append(keys, k) + } + case []int: + for _, k := range z { + keys = append(keys, strconv.Itoa(k)) + } + default: + return []string{} + } + return keys +} + +func MergeMaps[K comparable, V any](m1 map[K]V, m2 map[K]V) map[K]V { + merged := make(map[K]V) + if len(m1) > 0 { + for key, value := range m1 { + merged[key] = value + } + } + if len(m2) > 0 { + for key, value := range m2 { + merged[key] = value + } + } + return merged +} + +// Contains check slice contains value or not +func Contains[T comparable](s []T, e T) bool { + for _, v := range s { + if v == e { + return true + } + } + return false +} + +func TrimStringSpaces(s string) string { + return strings.Join(strings.Fields(s), " ") +} + +// ApplyTimezone +func ApplyTimezone(at time.Time, timezone string) (time.Time, error) { + loc, err := time.LoadLocation(timezone) + now := at.In(loc) + return now, err +} + +// AdjustTimezone +func AdjustTimezone(at time.Time, timezone string) time.Time { + t, err := ApplyTimezone(at, timezone) + if err != nil { + return at + } + return t +} + +func Base64Encode(v interface{}) string { + d := JsonString(v) + return base64.StdEncoding.EncodeToString([]byte(d)) +} + +func Base64Decode(encoded string) string { + if IsStringEmpty(encoded) { + return encoded + } + d, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return "" + } + return string(d) +} + +var _json = jsonI.ConfigCompatibleWithStandardLibrary + +func JsonString(data interface{}) string { + s, ok := data.(string) + if ok { + return s + } + result, err := json.Marshal(data) + // result, err := MarshalToString(data) + if err != nil { + log.Printf(err.Error()) + return "" + } + return string(result) +} diff --git a/pkg/ami/ami_manager.go b/pkg/ami/ami_manager.go index 22c40c2..ca00020 100644 --- a/pkg/ami/ami_manager.go +++ b/pkg/ami/ami_manager.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewAuth() *AMIAuth { @@ -116,7 +115,7 @@ func Logoff(ctx context.Context, s AMISocket) error { if err != nil { return err } - log.Printf("Logoff, response = %v", utils.ToJson(response)) + log.Printf("Logoff, response = %v", JsonString(response)) return err } @@ -141,7 +140,7 @@ func Ping(ctx context.Context, s AMISocket) error { return err } - log.Printf("Ping, response = %v", utils.ToJson(response)) + log.Printf("Ping, response = %v", JsonString(response)) return err } diff --git a/pkg/ami/ami_map.go b/pkg/ami/ami_map.go index de5cd6c..badd334 100644 --- a/pkg/ami/ami_map.go +++ b/pkg/ami/ami_map.go @@ -6,7 +6,6 @@ import ( "time" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func (c *AMICore) ExtensionStatesMap(ctx context.Context, guard *AMIExtensionGuard) (response []AMIExtensionStatus, err error) { @@ -28,13 +27,13 @@ func (c *AMICore) ExtensionStatesMap(ctx context.Context, guard *AMIExtensionGua } if len(guard.Context) > 0 { - if !utils.Contains(guard.Context, v.GetVal(config.AmiJsonFieldContext)) { + if !Contains(guard.Context, v.GetVal(config.AmiJsonFieldContext)) { continue } } if len(guard.StatusesText) > 0 { - if !utils.Contains(guard.StatusesText, v.GetVal(config.AmiJsonFieldStatusText)) { + if !Contains(guard.StatusesText, v.GetVal(config.AmiJsonFieldStatusText)) { continue } } @@ -109,13 +108,13 @@ func (c *AMICore) convRaw2PeerStatus(v AMIResultRaw, g *AMIPeerStatusGuard) *AMI SetPeerStatus(v.GetVal(config.AmiJsonFieldPeerStatus)). SetPrivilege(v.GetVal(config.AmiJsonFieldPrivilege)). SetTimeInMs(v.GetVal(config.AmiJsonFieldTime)). - SetPublishedAt(utils.SetTimezone(time.Now(), g.Timezone)) + SetPublishedAt(AdjustTimezone(time.Now(), g.Timezone)) if e.TimeInMs > 0 { e.SetPublishedAt(e.PublishedAt.Add(-time.Millisecond * time.Duration(e.TimeInMs))) } - if utils.IsEmptyAbsolute(g.DateTimeLayout) { + if IsStringEmpty(g.DateTimeLayout) { e.SetPrePublishedAt(e.PublishedAt.Format(config.DateTimeFormatYYYYMMDDHHMMSS)) } else { e.SetPrePublishedAt(e.PublishedAt.Format(g.DateTimeLayout)) diff --git a/pkg/ami/ami_message.go b/pkg/ami/ami_message.go index 0ce9e15..05654cc 100644 --- a/pkg/ami/ami_message.go +++ b/pkg/ami/ami_message.go @@ -13,7 +13,6 @@ import ( "time" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewActionWith(name string) *AMIMessage { @@ -43,7 +42,7 @@ func (m *AMIMessage) AppendPhonePrefix(values ...string) *AMIMessage { } func (m *AMIMessage) SetRegion(value string) *AMIMessage { - m.Region = utils.TrimAllSpace(value) + m.Region = TrimStringSpaces(value) return m } @@ -60,7 +59,7 @@ func ofMessageWithDictionary(d *AMIDictionary, header textproto.MIMEHeader) *AMI p := make(textproto.MIMEHeader) for k, v := range header { p.Add(d.TranslateField(k), header.Get(k)) - log.Printf("(AMI). header renew with key = %v and value = %v", k, utils.ToJson(v)) + log.Printf("(AMI). header renew with key = %v and value = %v", k, JsonString(v)) } m.Header = p } else { @@ -101,7 +100,7 @@ func (k *AMIMessage) FieldByDictionary(d *AMIDictionary, key string) string { func (k *AMIMessage) FieldDictionaryOrRefer(d *AMIDictionary, key, ref string) string { value := k.FieldByDictionary(d, key) - if value != "" && len(value) > 0 && !utils.IsEmptyAbsolute(value) { + if value != "" && len(value) > 0 && !IsStringEmpty(value) { return value } @@ -324,7 +323,7 @@ func (k *AMIMessage) VarWith(key string, vars []string) (string, bool) { } for _, value := range vars { - e, v := utils.VarsSplit(value) + e, v := VarsSplit(value) if e == key || strings.EqualFold(e, key) { return v, true } @@ -368,7 +367,7 @@ func (k *AMIMessage) ProduceMessageWithDictionaries(lowercaseField bool, transla if len(value) == 1 { data[field] = value[0] } else { - data[field] = utils.VarsMap(value) + data[field] = VarsMap(value) } } @@ -388,7 +387,7 @@ func (k *AMIMessage) ProduceMessagePure() map[string]interface{} { if len(value) == 1 { data[field] = value[0] } else { - data[field] = utils.VarsMap(value) + data[field] = VarsMap(value) } } @@ -397,17 +396,17 @@ func (k *AMIMessage) ProduceMessagePure() map[string]interface{} { // Return AMI message as Json string func (k *AMIMessage) Json() string { - return utils.ToJson(k.ProduceMessage()) + return JsonString(k.ProduceMessage()) } // Return AMI message as Json string func (k *AMIMessage) JsonTranslator(d *AMIDictionary) string { - return utils.ToJson(k.ProduceMessageTranslator(d)) + return JsonString(k.ProduceMessageTranslator(d)) } // Return AMI message as Json pure string func (k *AMIMessage) JsonPure() string { - return utils.ToJson(k.ProduceMessagePure()) + return JsonString(k.ProduceMessagePure()) } // Create AMI message from json string @@ -467,7 +466,7 @@ func (a *AMIPayloadMessage) SetBody(value string) *AMIPayloadMessage { } func (a *AMIPayloadMessage) SetBase64Body(value interface{}) *AMIPayloadMessage { - a.Base64Body = utils.Base64Encode(value) + a.Base64Body = Base64Encode(value) return a } diff --git a/pkg/ami/ami_model.go b/pkg/ami/ami_model.go index ebb060e..b8e0299 100644 --- a/pkg/ami/ami_model.go +++ b/pkg/ami/ami_model.go @@ -85,7 +85,7 @@ type AMISocket struct { IsUsedDictionary bool `json:"is_used_dictionary"` Retry bool `json:"retry"` MaxRetries int `json:"max_retries"` - AllowTrace bool `json:"allow_trace"` + DebugMode bool `json:"debug_mode"` MaxConcurrencyMillis int64 `json:"max_concurrency_millis"` } diff --git a/pkg/ami/ami_originate.go b/pkg/ami/ami_originate.go index 683c793..39bd605 100644 --- a/pkg/ami/ami_originate.go +++ b/pkg/ami/ami_originate.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewAMIPayloadOriginate() *AMIPayloadOriginate { @@ -60,7 +59,7 @@ func (o *AMIPayloadOriginate) SetData(value string) *AMIPayloadOriginate { } func (o *AMIPayloadOriginate) SetDataWith(value interface{}) *AMIPayloadOriginate { - o.SetData(utils.ToJson(value)) + o.SetData(JsonString(value)) return o } @@ -131,7 +130,7 @@ func (o *AMIPayloadOriginate) SetOtherChannelId(value string) *AMIPayloadOrigina } func (o *AMIPayloadOriginate) Json() string { - return utils.ToJson(o) + return JsonString(o) } func (o *AMIOriginateDirection) SetTelephone(value string) *AMIOriginateDirection { @@ -169,7 +168,7 @@ func (o *AMIOriginateDirection) SetAllowSysValidator(value bool) *AMIOriginateDi } func (o *AMIOriginateDirection) Json() string { - return utils.ToJson(o) + return JsonString(o) } // MakeCall diff --git a/pkg/ami/ami_socket.go b/pkg/ami/ami_socket.go index 7eaa437..4552294 100644 --- a/pkg/ami/ami_socket.go +++ b/pkg/ami/ami_socket.go @@ -11,15 +11,14 @@ import ( "strings" "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewAMISocket() *AMISocket { s := &AMISocket{ - Incoming: make(chan string, 32), - Shutdown: make(chan struct{}), - Errors: make(chan error), - AllowTrace: false, + Incoming: make(chan string, 32), + Shutdown: make(chan struct{}), + Errors: make(chan error), + DebugMode: false, } d := NewDictionary() d.SetAllowForceTranslate(true) @@ -55,7 +54,7 @@ func (s *AMISocket) SetMaxConcurrencyMillis(value int64) *AMISocket { } func (s *AMISocket) Json() string { - return utils.ToJson(s) + return JsonString(s) } // NewSocket provides a new socket client, connecting to a tcp server. @@ -124,8 +123,8 @@ func (s *AMISocket) SetUsedDictionary(value bool) *AMISocket { return s } -func (s *AMISocket) SetAllowTrace(value bool) *AMISocket { - s.AllowTrace = value +func (s *AMISocket) SetDebugMode(value bool) *AMISocket { + s.DebugMode = value return s } @@ -150,7 +149,7 @@ func (s *AMISocket) Close(ctx context.Context) error { // Send the message to socket using fprintf format func (s *AMISocket) Send(message string) error { v, err := fmt.Fprintf(s.Conn, message) - if s.AllowTrace { + if s.DebugMode { log.Printf("[>] Ami command, the number of byte(s) written = %v (byte)\n%v", v, message) } return err @@ -217,7 +216,7 @@ func (s AMIResultRaw) Values() []string { continue } v := s.GetVal(k) - if !utils.Contains(result, v) { + if !Contains(result, v) { result = append(result, v) } } @@ -267,7 +266,7 @@ func (s AMIResultRawLevel) GetVal(key string) string { if len(v) == 1 { return v[0] } - return utils.ToJson(v) + return JsonString(v) } func (s AMIResultRawLevel) Values() []string { @@ -280,7 +279,7 @@ func (s AMIResultRawLevel) Values() []string { continue } v := s.GetVal(k) - if !utils.Contains(result, v) { + if !Contains(result, v) { result = append(result, v) } } diff --git a/pkg/ami/ami_update_config.go b/pkg/ami/ami_update_config.go index 4a428b1..fafe9ac 100644 --- a/pkg/ami/ami_update_config.go +++ b/pkg/ami/ami_update_config.go @@ -3,8 +3,6 @@ package ami import ( "fmt" "strings" - - "github.com/pnguyen215/gobase-voip-core/pkg/ami/utils" ) func NewAMIUpdateConfigAction() *AMIUpdateConfigAction { @@ -47,7 +45,7 @@ func (a *AMIUpdateConfigAction) SetVarsMap(delimiter string, variables map[strin } _vars := make([]string, len(variables)) for k, v := range variables { - str := fmt.Sprintf("%s=%v", k, utils.ToJson(v)) + str := fmt.Sprintf("%s=%v", k, JsonString(v)) _vars = append(_vars, str) } a.SetVars(delimiter, _vars...) diff --git a/pkg/ami/utils/ami_utils.go b/pkg/ami/utils/ami_utils.go index b4b2b50..6c05e86 100644 --- a/pkg/ami/utils/ami_utils.go +++ b/pkg/ami/utils/ami_utils.go @@ -1,102 +1,24 @@ package utils import ( - "encoding/base64" "log" - "net" - "net/http" - "net/url" - "strconv" - "strings" - "time" - "unicode" - - "github.com/go-resty/resty/v2" - "github.com/pnguyen215/gobase-voip-core/pkg/ami/config" jsonI "github.com/json-iterator/go" ) var _json = jsonI.ConfigCompatibleWithStandardLibrary -func VarsMap(values []string) map[string]string { - r := make(map[string]string) - - for _, value := range values { - k, v := VarsSplit(value) - r[k] = v - } - - return r -} - -func VarsSplit(value string) (string, string) { - s := strings.SplitN(value, "=", 2) - k := s[0] - - if len(s) == 1 { - return k, "" - } - - return k, s[1] -} - -func HasRawConnection(ip string, port int) (bool, error) { - timeout := time.Second - conn, err := net.DialTimeout(config.AmiNetworkTcpKey, net.JoinHostPort(ip, strconv.Itoa(port)), timeout) - - if err != nil { - log.Printf("Connecting error: %v", err) - return false, err - } - - if conn != nil { - defer conn.Close() - log.Printf("Opened on: %s", net.JoinHostPort(ip, strconv.Itoa(port))) - return true, nil - } - - return false, nil -} - -func HasRawConnectionWith(ip string, ports []int) (bool, error) { - for _, port := range ports { - - if ok, err := HasRawConnection(ip, port); err != nil { - return ok, err - } - } - - return true, nil -} - -func IPDecode(ip string) (string, string, error) { - u, err := url.Parse(ip) - - if err != nil { - log.Printf("IP parse has error occurred = %v", err) - return "", "", err - } - - host, port, err := net.SplitHostPort(u.Host) - return host, port, err -} - func ToJson(data interface{}) string { s, ok := data.(string) - if ok { return s } - // result, err := json.Marshal(data) result, err := MarshalToString(data) - if err != nil { log.Printf(err.Error()) return "" } - return string(result) } @@ -117,119 +39,6 @@ func ToJsonPretty(data interface{}) string { return string(result) } -func TakeKeyFromValue(collection map[string]string, value string) string { - if len(collection) <= 0 { - return value - } - - for k, v := range collection { - if strings.EqualFold(v, value) { - return k - } - } - - return value -} - -func TakeValueFromKey(collection map[string]string, key string) string { - if len(collection) <= 0 { - return key - } - - for k, v := range collection { - if strings.EqualFold(k, key) { - return v - } - } - - return "" -} - -func Keys(in interface{}) (keys []string) { - switch z := in.(type) { - case map[string]int: - case map[string]int32: - case map[string]int64: - case map[string]float32: - case map[string]float64: - case map[string]string: - case map[string]bool: - for k := range z { - keys = append(keys, k) - } - case []int: - for _, k := range z { - keys = append(keys, strconv.Itoa(k)) - } - default: - return []string{} - } - return keys -} - -func MergeMaps[K comparable, V any](m1 map[K]V, m2 map[K]V) map[K]V { - merged := make(map[K]V) - if len(m1) > 0 { - for key, value := range m1 { - merged[key] = value - } - } - if len(m2) > 0 { - for key, value := range m2 { - merged[key] = value - } - } - return merged -} - -// Contains check slice contains value or not -func Contains[T comparable](s []T, e T) bool { - for _, v := range s { - if v == e { - return true - } - } - return false -} - -// ForkDictionaryFromLink -// Link must be provided to file formatted as json -// Return maps[string]string -func ForkDictionaryFromLink(link string, debug bool) (*map[string]string, error) { - client := resty.New() - result := &map[string]string{} - // Set retry count to non zero to enable retries - client.SetRetryCount(3). - // You can override initial retry wait time. - // Default is 100 milliseconds. - SetRetryWaitTime(10 * time.Second). - // MaxWaitTime can be overridden as well. - // Default is 2 seconds. - SetRetryMaxWaitTime(20 * time.Second). - AddRetryCondition( - // RetryConditionFunc type is for retry condition function - // input: non-nil Response OR request execution error - func(r *resty.Response, err error) bool { - return r.StatusCode() >= http.StatusBadRequest && r.StatusCode() <= http.StatusNetworkAuthenticationRequired - }, - ). - // Enable debug mode - SetDebug(debug). - // Add headers - SetHeaders(map[string]string{ - "Content-Type": "application/json", - }) - - _, err := client.R().SetResult(&result).ForceContentType("application/json").Get(link) - - if err != nil { - log.Printf("fork dictionary from link %v has error occurred %v", link, err.Error()) - return result, err - } - - return result, nil -} - func MarshalToString(v interface{}) (string, error) { return _json.MarshalToString(v) } @@ -249,74 +58,3 @@ func UnmarshalFromString(str string, v interface{}) error { func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { return _json.MarshalIndent(v, prefix, indent) } - -func Base64Encode(v interface{}) string { - d := ToJson(v) - return base64.StdEncoding.EncodeToString([]byte(d)) -} - -func Base64Decode(encoded string) string { - if encoded == "" { - return encoded - } - d, err := base64.StdEncoding.DecodeString(encoded) - if err != nil { - return "" - } - return string(d) -} - -func TrimAllSpace(s string) string { - return strings.Join(strings.Fields(s), " ") -} - -func IsSpace(str string) bool { - for _, c := range str { - if !unicode.IsSpace(c) { - return false - } - } - return true -} - -func IsEmptyAbsolute(str string) bool { - return len(str) == 0 || str == "" || strings.TrimSpace(str) == "" -} - -func IsLetter(s string) bool { - for _, r := range s { - if !unicode.IsLetter(r) { - return false - } - } - return true -} - -// AddTimezone -func AddTimezone(at time.Time, timezone string) (time.Time, error) { - loc, err := time.LoadLocation(timezone) - now := at.In(loc) - return now, err -} - -// SetTimezone -func SetTimezone(at time.Time, timezone string) time.Time { - t, err := AddTimezone(at, timezone) - if err != nil { - return at - } - return t -} - -func RemovePrefix(str string, prefix ...string) string { - if IsEmptyAbsolute(str) { - return str - } - if len(prefix) == 0 { - return str - } - for _, v := range prefix { - str = strings.TrimPrefix(str, v) - } - return str -}