cycoresystems / ari Goto Github PK
View Code? Open in Web Editor NEWGolang Asterisk REST Interface (ARI) library
License: Apache License 2.0
Golang Asterisk REST Interface (ARI) library
License: Apache License 2.0
The response code for calls terminated with Busy()
or Congestion()
is 603 Declined
.
Instead, they should be:
486 Busy Here
503 Service Unavailable
Most likely, the HangupChannel
with cause code is not being used properly.
hi:
where I can found a example that is the push configure with ari. I don't understand Asterisk() Interface...
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")
}
Hi,
I'm having trouble trying to add a channel to a bridge and specify "absorbDTMF" as per the official docs, is it possible with this library ?
Many thanks
Needs implementing. GET, POST, DELETE, PUT methods
Create a README for the master and v3 branches.
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.
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
I think I forgot to add an ari.Bridge.Create?
404 Not Found is returned when attempting to Stop a live recording that has been created via channel.Record(...) .
Stopping a live recording via channel.Record can be done via OnTerminate DTMF signal instead, so there is a current workaround.
Add prometheus metrics to the various parts of the ARI codebase.
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:
Line 42 in e4c85dc
I think it should be return b.client.post("/bridges/"+key.ID, nil, &req)
Line 115 in f95c2e3
Should this not return err?
needs implementing
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
}
A working nats client and gateway server are in v3 now.
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 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.
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)
})
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:]
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{}.
Needs implementing
Testing with a real Asterisk box and connected endpoint is a pain. We could get most of the way there by building a mock Asterisk box, or even just providing an injector for tossing events into the Bus
.
We've discussed event filtering via these single method interfaces:
type ChannelEvent interface {
GetChannelID() string
}
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.
// 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.
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:
Assumptions:
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:
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"
Please provide a working Originate sample.
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).
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 !?
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?
OverallTimeout should begin after the end of the prompt playback, not at the beginning.
A TextMessageData struct needs to be made, for the text message received event in PR #48
Needs implementing
Looks like parallel audio playback is Phase 6 here https://wiki.asterisk.org/wiki/display/AST/Asterisk+14+Project+-+URI+Media+Playback .
Any way to do this without text/uri-list
support?
The ext/record
interface has been stubbed, but it needs to actually be implemented.
Needs implementing. GET, PUT, DELETE operations.
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?
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
Needs implementing
The bridge interface is missing MOH() and StopMOH(), making it impossible to start music for a bridge.
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?
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
array of subscriptions
in Bus.Send()
Options for Before/Between/Duration/After/etc. v2 has SendDTMFToChannelRequest.
Prompt package is in need of TLC due to API changes and incomplete tests.
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.
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).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.