github.com/CyCoreSystems/ari@v4.8.4+incompatible/key.go (about)

     1  package ari
     2  
     3  import "fmt"
     4  
     5  const (
     6  	// ApplicationKey is the key kind for ARI Application resources.
     7  	ApplicationKey = "application"
     8  
     9  	// BridgeKey is the key kind for the ARI Bridge resources.
    10  	BridgeKey = "bridge"
    11  
    12  	// ChannelKey is the key kind for the ARI Channel resource
    13  	ChannelKey = "channel"
    14  
    15  	// DeviceStateKey is the key kind for the ARI DeviceState resource
    16  	DeviceStateKey = "devicestate"
    17  
    18  	// EndpointKey is the key kind for the ARI Endpoint resource
    19  	EndpointKey = "endpoint"
    20  
    21  	// LiveRecordingKey is the key kind for the ARI LiveRecording resource
    22  	LiveRecordingKey = "liverecording"
    23  
    24  	// LoggingKey is the key kind for the ARI Logging resource
    25  	LoggingKey = "logging"
    26  
    27  	// MailboxKey is the key kind for the ARI Mailbox resource
    28  	MailboxKey = "mailbox"
    29  
    30  	// ModuleKey is the key kind for the ARI Module resource
    31  	ModuleKey = "module"
    32  
    33  	// PlaybackKey is the key kind for the ARI Playback resource
    34  	PlaybackKey = "playback"
    35  
    36  	// SoundKey is the key kind for the ARI Sound resource
    37  	SoundKey = "sound"
    38  
    39  	// StoredRecordingKey is the key kind for the ARI StoredRecording resource
    40  	StoredRecordingKey = "storedrecording"
    41  
    42  	// VariableKey is the key kind for the ARI Asterisk Variable resource
    43  	VariableKey = "variable"
    44  )
    45  
    46  // Keys is a list of keys
    47  type Keys []*Key
    48  
    49  // Filter filters the key list using the given key type match
    50  func (kx Keys) Filter(mx ...Matcher) (ret Keys) {
    51  	for _, m := range mx {
    52  		for _, k := range kx {
    53  			if m.Match(k) {
    54  				ret = append(ret, k)
    55  			}
    56  		}
    57  	}
    58  	return
    59  }
    60  
    61  // Without removes keys that match the given matcher
    62  func (kx Keys) Without(m Matcher) (ret Keys) {
    63  	for _, k := range kx {
    64  		if !m.Match(k) {
    65  			ret = append(ret, k)
    66  		}
    67  	}
    68  	return
    69  }
    70  
    71  // First returns the first key from a list of keys.  It is safe to use on empty lists, in which case, it will return nil.
    72  func (kx Keys) First() *Key {
    73  	if len(kx) < 1 {
    74  		return nil
    75  	}
    76  	return kx[0]
    77  }
    78  
    79  // Bridges returns just the bridge keys from a set of Keys
    80  func (kx Keys) Bridges() Keys {
    81  	return kx.Filter(NewKey(BridgeKey, ""))
    82  }
    83  
    84  // Channels returns just the channel keys from a set of Keys
    85  func (kx Keys) Channels() Keys {
    86  	return kx.Filter(NewKey(ChannelKey, ""))
    87  }
    88  
    89  // ID returns the key from a set of keys with ID matching the given ID.  If the
    90  // key does not exist in the set, nil is returned.
    91  func (kx Keys) ID(id string) *Key {
    92  	return kx.Filter(NewKey("", id)).First()
    93  }
    94  
    95  // A Matcher provides the functionality for matching against a key.
    96  type Matcher interface {
    97  	Match(o *Key) bool
    98  }
    99  
   100  // MatchFunc is the functional type alias for providing functional `Matcher` implementations
   101  type MatchFunc func(*Key) bool
   102  
   103  // Match invokes the match function given the key
   104  func (mf MatchFunc) Match(o *Key) bool {
   105  	return mf(o)
   106  }
   107  
   108  // KeyOptionFunc is a functional argument alias for providing options for ARI keys
   109  type KeyOptionFunc func(Key) Key
   110  
   111  // WithDialog sets the given dialog identifier on the key.
   112  func WithDialog(dialog string) KeyOptionFunc {
   113  	return func(key Key) Key {
   114  		key.Dialog = dialog
   115  		return key
   116  	}
   117  }
   118  
   119  // WithNode sets the given node identifier on the key.
   120  func WithNode(node string) KeyOptionFunc {
   121  	return func(key Key) Key {
   122  		key.Node = node
   123  		return key
   124  	}
   125  }
   126  
   127  // WithApp sets the given node identifier on the key.
   128  func WithApp(app string) KeyOptionFunc {
   129  	return func(key Key) Key {
   130  		key.App = app
   131  		return key
   132  	}
   133  }
   134  
   135  // WithLocationOf copies the partial key fields Node, Application, Dialog from the reference key
   136  func WithLocationOf(ref *Key) KeyOptionFunc {
   137  	return func(key Key) Key {
   138  		if ref != nil {
   139  			key.Node = ref.Node
   140  			key.Dialog = ref.Dialog
   141  			key.App = ref.App
   142  		}
   143  		return key
   144  	}
   145  }
   146  
   147  // NewKey builds a new key given the kind, identifier, and any optional arguments.
   148  func NewKey(kind string, id string, opts ...KeyOptionFunc) *Key {
   149  	k := Key{
   150  		Kind: kind,
   151  		ID:   id,
   152  	}
   153  	for _, o := range opts {
   154  		k = o(k)
   155  	}
   156  
   157  	return &k
   158  }
   159  
   160  // AppKey returns a key that is bound to the given application.
   161  func AppKey(app string) *Key {
   162  	return NewKey("", "", WithApp(app))
   163  }
   164  
   165  // ConfigID returns the configuration Key ID for the given configuration class, type/kind, and id.
   166  func ConfigID(class, kind, id string) string {
   167  	return fmt.Sprintf("%s/%s/%s", class, kind, id)
   168  }
   169  
   170  // EndpointID returns the endpoint Key ID for the given tech and resource
   171  func EndpointID(tech, resource string) string {
   172  	return fmt.Sprintf("%s/%s", tech, resource)
   173  }
   174  
   175  // DialogKey returns a key that is bound to the given dialog.
   176  func DialogKey(dialog string) *Key {
   177  	return NewKey("", "", WithDialog(dialog))
   178  }
   179  
   180  // NodeKey returns a key that is bound to the given application and node
   181  func NodeKey(app, node string) *Key {
   182  	return NewKey("", "", WithApp(app), WithNode(node))
   183  }
   184  
   185  // KindKey returns a key that is bound by a type only
   186  func KindKey(kind string, opts ...KeyOptionFunc) *Key {
   187  	return NewKey(kind, "", opts...)
   188  }
   189  
   190  // Match returns true if the given key matches the subject. Empty partial key fields are wildcards.
   191  func (k *Key) Match(o *Key) bool {
   192  	if k == o {
   193  		return true
   194  	}
   195  
   196  	if k == nil || o == nil {
   197  		return true
   198  	}
   199  
   200  	if k.App != "" && o.App != "" && k.App != o.App {
   201  		return false
   202  	}
   203  	if k.Dialog != "" && o.Dialog != "" && k.Dialog != o.Dialog {
   204  		return false
   205  	}
   206  	if k.Node != "" && o.Node != "" && k.Node != o.Node {
   207  		return false
   208  	}
   209  	if k.Kind != "" && o.Kind != "" && k.Kind != o.Kind {
   210  		return false
   211  	}
   212  	if k.ID != "" && o.ID != "" && k.ID != o.ID {
   213  		return false
   214  	}
   215  
   216  	return true
   217  }
   218  
   219  // New returns a new key with the location information from the source key.
   220  // This includes the App, the Node, and the Dialog.  the `kind` and `id`
   221  // parameters are optional.  If kind is empty, the resulting key will not be
   222  // typed.  If id is empty, the key will not be unique.
   223  func (k *Key) New(kind, id string) *Key {
   224  	n := NodeKey(k.App, k.Node)
   225  	n.Dialog = k.Dialog
   226  	n.Kind = kind
   227  	n.ID = id
   228  
   229  	return n
   230  }
   231  
   232  func (k *Key) String() string {
   233  	if k.ID != "" {
   234  		return k.ID
   235  	}
   236  
   237  	if k.Dialog != "" {
   238  		return "[" + k.Dialog + "]"
   239  	}
   240  
   241  	if k.Node != "" {
   242  		return k.App + "@" + k.Node
   243  	}
   244  
   245  	return "emptyKey"
   246  }