Code Monkey home page Code Monkey logo

ari's People

Contributors

0perl avatar baldrailers avatar daninmadison avatar devishot avatar goharahmed avatar llccs avatar mikehall76 avatar mtryfoss avatar naapperas avatar raiansantos avatar realrainer avatar seanchann avatar serfreeman1337 avatar sharonallsup avatar sheenobu avatar theelee13 avatar truep avatar tsearle avatar ulexus avatar vipul-sharma20 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ari's Issues

ari 3.0 - Channels design

Design between Client struct to Channels interface to Channel struct.

Usage:

ch, _ := client.Channel.Get("channelID")
ch.Hangup()
// A Client is a connection to ARI
type Client struct {
        Channel Channel
        Bridge Bridge
        Playback Playback
        // ...
}
// Channels is the interface for working with ARI channels
type Channels interface {
        // Get gets the channel by ID
        Get(id string) (*ChannelHandle, error)

        // Create creates a new channel
        Create(id string) (*ChannelHandle, error)

        // Hangup hangs up the given channel
        Hangup(id string, reason string) error
}
type ChannelData struct {
        ID           string      `json:"id"`    // Unique id for this channel (same as for AMI)
        Name         string      `json:"name"`  // Name of this channel (tech/name-id format)
        State        string      `json:"state"` // State of the channel
        Accountcode  string      `json:"accountcode"`
        Caller       CallerID    `json:"caller"`    // CallerId of the calling endpoint
        Connected    CallerID    `json:"connected"` // CallerId of the connected line
        Creationtime DateTime    `json:"creationtime"`
        Dialplan     DialplanCEP `json:"dialplan"` // Current location in the dialplan
}
// Busy hangs up the channel with the busy cause code
func (ch *ChannelHandle) Busy() error {
        return ch.c.Busy(ch.id)
}

// Hangup hangs up the channel with the normal cause code
func (ch *ChannelHandle) Hangup() error {
        return ch.c.Hangup(ch.id, "normal")
}

README

Create a README for the master and v3 branches.

ari 3.0 - NATS Events

ARI v3 events are now being forwarded through the ari / NATS gateway to the ari v3 NATS client. Events are sent on the topic ari.events.eventType and the body is the raw message body sent from WebSockets.

For Subscriptions using handles, we are simply getting all events of a given type and checking if it matches some criteria. For the native client, this is mostly required.

For the nats client, this may or may not be required (We could send on ari.events.general.eventType and ari.events.channel.eventType.channelID... this requires encoding each event struct or event type with instructions on how to convert it to an appropriate series of NATS subjects. It means we can make smarter subscriptions: ari.events.channel.*.ID for all channel events for the given channel ID.

Code

Channel specific subscription:

https://github.com/CyCoreSystems/ari/blob/v3/client/nc/channel.go#L149

Event forwarding code:

https://github.com/CyCoreSystems/ari/blob/v3/server/natsgw/events.go#L12

ari 3.0 - Examples can only support a single call

The NATS examples under _examples can currently only support a single call. Once a call enters Stasis it won't seem to leave. Additional calls created during the same invocation lockup.

I'm guessing there is /something/ the nats gateway code isn't doing to ensure:

  1. Multiple calls can enter stasis
  2. Calls leave Stasis on hangup

ari 3.0 - NATS timeouts

The v3 API is synchronous, even over NATS. This is /fine/ but it means the code for NATS communication has timeouts (this is also fine). But what do we want to do with timeouts?

There are certain functions which, if timed out, can be re-retried automatically (this is now done).

These operations are written with nc.Conn.readRequest and they are guaranteed to be retried a maximum of nc.Options.ReadOperationRetryCount .

func (a *natsAsteriskVariables) Get(variable string) (ret string, err error) {
        err = a.conn.readRequest("ari.asterisk.variables.get."+variable, nil, &ret)
        return
}
Outsanding issues:
  • This is less about "read" operations and more about idempotent operations: Operations which can be repeated but have little effect. Both Get and Set variable apply, as setting a variable to the same value twice does little, except possible trigger an update variable event twice.
  • Even Delete is a repeatable operation, a deletion of an already deleted item does nothing. However, it may return a "Not Found" error that will need to be detected and ignored on repeat requests.
  • When an operation on NATS times out, there may be no guarantee that the operation did not succeed. This means that certain operations should not be retried, ever, and some special code needs to be written (The ARI nats gateway can be made more robust. Some (terrible) diagrams are attached).
Diagrams of operations between the different components:
  1. Current Operation of NATS client and gateway on success: nats-gw-list-success
  2. Current Operation of NATS client and gateway on timeout:

nats-gw-list-timeout

  1. Possible Operation of NATS gateway with message ids:

nats-gw-list-messageid

ari 3.0 - NATS client and server design

A working nats client and gateway server are in v3 now.

server/natsgw

This is the ARI gateway server, ready for embedding (with just Application implemented and no Bus). The tests in here test the ARI v3 nats client and server alongside an example Application client interface.

wildcards

Wildcards in nats only work if you use a dot separator. Confirmed via automated testing in the natsgw package. No colons in the nats code now.

handle.ID()

All handles now have ID methods. Required for this case, where ari.applications.all returns a list of strings but upstream returns a list of Handles.

srv.subscribe("ari.applications.all", func(_ string, _ []byte, reply Reply) {
        ax, err := srv.upstream.Application.List()
        if err != nil {
                reply(nil, err)
                return
        }

        var apps []string
        for _, a := range ax {
                apps = append(apps, a.ID())
        }

        reply(apps, nil)
})

natsgw.Handle and natsgw.Reply

Slight abstraction over standard nats. Reply is a two argument function, the left which contains the response and the right contains an error. (natsgw.Handler could just as easily have those as return values instead which would make Reply redundant)

Here is the translation:

 * reply(nil, errors.New("...")) ---------> err to nats queue "${replyID}.err"
 * reply(resp, errors.New("...")) ------> err to nats queue "${replyID}.err"
 * reply(resp, nil) ----------------------> resp to nats queue "${replyID}.resp"
 * reply(nil, nil) ----------------------> {} to nats queue "${replyID}.resp"

The (simplified) nats client side, to determine 'err' vs 'resp'.

replyID := uuid.NewV1().String()
sub, err = conn.ChanSubscribe(replyID+".>", ch)
msg <- ch
msgType := msg.Subject[len(replyID)+1:]

encoding

All encoding is manual. Without msg.Subject and msgType details from above, we have no idea whether to decode the raw body as an error type or the given interface{}.

Outstanding Questions

  • Does ChanSubscribe with a wildcard slow things down much? We are using it on /every/ response?

ari 3.0 - event filtering

We've discussed event filtering via these single method interfaces:

type ChannelEvent interface {
   GetChannelID() string
}

Issue

Certain events have multiple channel IDs, for example BridgeBlindTransfer:

type BridgeBlindTransfer struct {
   Bridge BridgeData
   Channel ChannelData
   ReplaceChannel ChannelData
   Transferee ChannelData
}

There is only one Bridge but multiple Channels.

  1. Should we just use one channel on GetChannelID()? so we only filter on one specific channel field?
  2. Should we refactor our filtering mechanism?

Refactoring

// Matcher is an interface Handles can implement to provide event filtering
type Matcher interface {
   Matches(evt ari.Event) bool
}

// ChannelEvent allows arbitrary events to give a Matcher a series of Channel IDs to operate on.
type ChannelEvent interface {
   GetChannelIDs() []string // multiple ID support
}

// Example code:

var channelHandle ChannelHandle
evt <- sub.Events()
if !channelHandle.Matches(evt) {
   //ignore event 
} else {
  // process event
}

Writing this up.... I think I'll go with the refactoring anyway. That will move the event filtering logic from the individual Subscribe implementations in client/native and client/nc into the main ari package and each client only needs to call handle.Matches(evt) before dispatching to the subscription.

ari 3.0 - ari.Player, ari.Play design.

We have this global ari.Play function in v2. How do we want to handle this in v3?

I think we want to move the global ari.Play function to client?

The items implementing ari.Player would be the Handles (ChannelHandle, BridgeHandle). The handles would be responsible for converting the common ari.Player call to their specific transports. client.Play still handles general lifecycle operations via Bus interactions.

Big changes:

  • ari.Play is now ari.Client.Play.
  • ari.Play does NOT take a x/net/context.
  • ari.Play returns an object which can be operated on (and hooked into x/net/context).

Assumptions:

  • the Bus that allows Playback event subscriptions is transport agnostic, like the other items within ari.Client.

Usage:

val, err := client.Play(handle, mediaURI)
defer val.Stop()

Methods, entiies:

/// implemented by ChannelHandle, BridgeHandle, etc
type Player interface {
    Play(string) (string, error)
}
// An interface or struct or anything else
type PlaybackOperation ? {
    Stop()
}
func (cl *Client) Play(p Player, mediaURI string) (PlaybackOperation, error) {
    ... current implementation, which subscribes to the clients event Bus ...
}

Other options/notes:

  • We can make ari.Player a namespaced interface, with different lifecycle managements for each transport.
  • Like the first, but part of ari.Playback.
  • ari.PlaybackQueue hasn't even been mentioned yet

Hangup a channel does not work

hi all
I have created a channel in a.go :

key := ari.Key{Kind: ari.ChannelKey, Node: "caller", App: "xx"}
org := ari.OriginateRequest{Endpoint: "SIP/x", App: "xx", CallerID: "test" , Timeout: 300}
t1, err := cl.Channel().StageOriginate(&key, org)
	if err != nil {
		fmt.Print("Cannot create channel : ", err)
	}
t1.Exec()

now in b.go I want to destroy the channel so I do the following :

key := ari.Key{ari.ChannelKey, "01d5sgk517qws4rsa91v5tzf3r-ch" ,"caller", " ", App: "xx"}
cl.Channel.Hangup(&key, "for test")

but it does not Hangup the channel
is there any way to destroy a channel like :

curl -s -u ehsan:esx -X  DELETE "http://localhost:8088/ari/channels/01d5sgk517qws4rsa91v5tzf3r-ch"

Originate

Please provide a working Originate sample.

boolean values are not being sent as part of the message struct.

The offending code is in the gorequest library here:

https://github.com/parnurzeal/gorequest/blob/85e45d300dea2897330729470524f2eaf2d7896e/main.go#L577

The gorequest library works by converting to JSON, then converting from JSON into a map[string]interface{} to create the form post. It iterates over the map key/values and ignores anything NOT a string or number.

This comment in the ARI library says:

Uses gorequest.PostForm since ARI returns bad request otherwise

but I am not able to replicate this. Switching to json (for now).

cannot have two active apps simultaneously

Hi all
I have two stasis app
A and B :
exten => 2018,1,NoOp()
same => n,Answer()
same => n,stasis(A)
same => n,Hangup()

exten => 2019,1,NoOp()
same => n,Answer()
same => n,stasis(B)
same => n,Hangup()

and two ari user :
[ehsan]
type = user
read_only = no
password = esx

[busy]
type = user
read_only = no
password = check

I connect to the asterisk through WebSocket by user "ehsan" to create app "A"
cl, err := native.Connect(&native.Options{
Application: "A",
Username: "ehsan",
Password: "esx",
URL: "http://localhost:8088/ari",
WebsocketURL: "ws://localhost:8088/ari/events",
})
....

but when I want to create app B through WebSocket by user "busy" it will deactivate the app "A" first
and then creates the app "B"
Deactivating Stasis app 'A'
Activating Stasis app 'B'

and also logs :
WARNING[9361]: res_http_websocket.c:516 ws_safe_read: Web socket closed abruptly
WARNING[9361]: ari/ari_websockets.c:126 ast_ari_websocket_session_read: WebSocket read error: Success

base on this link I can have two active apps simultaneously :
https://wiki.asterisk.org/wiki/display/AST/Getting+Started+with+ARI
how can I have two active apps simultaneously in golang ari !?

Missing dependencies in `_examples/statisStart/main.go`

I'd like to build example of statisStart.

[vodolaz095@steel stasisStart]$ go run main.go 
main.go:15:2: cannot find package "github.com/CyCoreSystems/ari/client/nc" in any of:
	/home/vodolaz095/go/src/github.com/CyCoreSystems/ari/vendor/github.com/CyCoreSystems/ari/client/nc (vendor tree)
	/usr/lib/golang/src/github.com/CyCoreSystems/ari/client/nc (from $GOROOT)
	/home/vodolaz095/go/src/github.com/CyCoreSystems/ari/client/nc (from $GOPATH)
[vodolaz095@steel stasisStart]$ go get -v .
github.com/CyCoreSystems/ari (download)
package github.com/CyCoreSystems/ari/client/nc: cannot find package "github.com/CyCoreSystems/ari/client/nc" in any of:
	/usr/lib/golang/src/github.com/CyCoreSystems/ari/client/nc (from $GOROOT)
	/home/vodolaz095/go/src/github.com/CyCoreSystems/ari/client/nc (from $GOPATH)

it looks like the github.com/CyCoreSystems/ari/client/nc package is missing.

Probably, the example code is affected by this commit - 3c9d1c8

So, my question is - how can i build this example?

Error while creating RecordingOptions

I am trying to record the bridge and i am using
**func (bh *BridgeHandle) Record(name string, opts RecordingOptions) (LiveRecordingHandle, error)
to record the bridge.

I have created RecordingOptions struct to pass in the params

var recOpt *ari.RecordingOptions
 recOpt.Format = "wav"
 recOpt.Exists = "overwrite"
 _, err = bridgeHandle.Record("testrec", recOpt)

i get the following error at runtime.

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x691a89]

goroutine 20 [running]:
stasis.ensureBridge(0x96c780, 0xc000188000, 0x970740, 0xc000122000, 0xc0000b2cd0, 0x2, 0xc00006ac60)
/home/prabhat/go/src/stasis/stasis.go:128 +0x199
stasis.app(0x96c780, 0xc000188000, 0x970740, 0xc000122000, 0xc000148810)
/home/prabhat/go/src/stasis/stasis.go:96 +0x340
created by stasis.App
/home/prabhat/go/src/stasis/stasis.go:56 +0x8f0
exit status 2

What am i doing wrong?

changes in satori/go.uuid gives error when run `go get`

There satori/go.uuid#66 mentioned changes for uuid.NewV1(). Now it also return error.
It causes an error:

client/native/bridge.go:28:22: multiple-value uuid.NewV1() in single-value context
client/native/bridge.go:140:26: multiple-value uuid.NewV1() in single-value context
client/native/channel.go:92:29: multiple-value uuid.NewV1() in single-value context
client/native/channel.go:121:29: multiple-value uuid.NewV1() in single-value context
client/native/channel.go:343:23: multiple-value uuid.NewV1() in single-value context
client/native/client.go:89:33: multiple-value uuid.NewV1() in single-value context

Bridges don't support MOH

The bridge interface is missing MOH() and StopMOH(), making it impossible to start music for a bridge.

ari3 - List() Design

Many of the interfaces (bridge, application) need List methods. The v2 code all return []Bridge, []Application, etc.

Should the new List interface methods return []BridgeHandle or []BridgeData?

Race condition: Bus should lock subscriptions array while reading in Send method

I have ran into a problem with the Bus.Send() method in stdbus/ implementation.
It raised error when tried read .key from one of the subscriptions which was nil.

This bug may happen when run concurrently:
a) remove subcription from array of subscriptions in bus and
b) loop over this array of subscriptions in Send() method.

For check this problem, you can run single test with -race flag for execute with Go's race detector:

cd stdbus 
go test -race -run TestEvents

Output will be:

==================
WARNING: DATA RACE
Read at 0x00c00006f350 by goroutine 11:
  github.com/devishot/ari/stdbus.(*bus).Send()
      C:/Users/stamkulov/Documents/Kolesa/go/src/github.com/devishot/ari/stdbus/bus.go:50 +0x59
  github.com/devishot/ari/stdbus.TestEventsDataRace.func2()
      C:/Users/stamkulov/Documents/Kolesa/go/src/github.com/devishot/ari/stdbus/bus_test.go:208 +0xaa

Previous write at 0x00c00006f350 by goroutine 10:
  github.com/devishot/ari/stdbus.(*bus).add()
      C:/Users/stamkulov/Documents/Kolesa/go/src/github.com/devishot/ari/stdbus/bus.go:82 +0xe8
  github.com/devishot/ari/stdbus.(*bus).Subscribe()
      C:/Users/stamkulov/Documents/Kolesa/go/src/github.com/devishot/ari/stdbus/bus.go:75 +0x186
  github.com/devishot/ari/stdbus.TestEventsDataRace.func1()
      C:/Users/stamkulov/Documents/Kolesa/go/src/github.com/devishot/ari/stdbus/bus_test.go:194 +0x21a

Goroutine 11 (running) created at:
  github.com/devishot/ari/stdbus.TestEventsDataRace()
      C:/Users/stamkulov/Documents/Kolesa/go/src/github.com/devishot/ari/stdbus/bus_test.go:204 +0x377
  testing.tRunner()
      C:/Go/src/testing/testing.go:827 +0x169

Goroutine 10 (running) created at:
  github.com/devishot/ari/stdbus.TestEventsDataRace()
      C:/Users/stamkulov/Documents/Kolesa/go/src/github.com/devishot/ari/stdbus/bus_test.go:187 +0x33f
  testing.tRunner()
      C:/Go/src/testing/testing.go:827 +0x169
==================
--- FAIL: TestEventsDataRace (0.00s)
    testing.go:771: race detected during execution of test
FAIL
exit status 1
FAIL    github.com/devishot/ari/stdbus  0.426s
  • Please have a look my PR for this problem. It uses mutex Lock for array of subscriptions in Bus.Send()

More tutorials

I appreciate all the work you've done to make this library. but I'm having a hell of a time navigating it on my own. Everything seems to be a circular reference, for instance when I want to create a channel for an out outbound call everything I can find seems to require a channel as input. A tutorial on creating channels would be very helpful, among others.

v4: add key getters for events

Presently, events have getters for IDs (GetChannelIDs, GetBridgeIDs, GetPlaybackIDs, etc). Since v4 is key-based rather than ID-based, we need to have corresponding getters for those keys (GetChannels, GetBridges, GetPlaybacks, etc).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.