{"id":20365867,"url":"https://github.com/cycoresystems/ari-proxy","last_synced_at":"2025-08-25T01:44:08.467Z","repository":{"id":54831296,"uuid":"69913760","full_name":"CyCoreSystems/ari-proxy","owner":"CyCoreSystems","description":"NATS or RabbitMQ message bus Asterisk REST Interface proxy system implemented in Go","archived":false,"fork":false,"pushed_at":"2024-06-08T11:37:35.000Z","size":1803,"stargazers_count":83,"open_issues_count":13,"forks_count":39,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-05-07T19:06:07.509Z","etag":null,"topics":["ari","asterisk","golang","nats","rabbitmq"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CyCoreSystems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-10-03T21:47:44.000Z","updated_at":"2025-03-20T12:26:23.000Z","dependencies_parsed_at":"2024-06-18T20:02:47.891Z","dependency_job_id":"cbef2edd-d3d0-4662-a084-cd16b1a36c04","html_url":"https://github.com/CyCoreSystems/ari-proxy","commit_stats":null,"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyCoreSystems%2Fari-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyCoreSystems%2Fari-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyCoreSystems%2Fari-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CyCoreSystems%2Fari-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CyCoreSystems","download_url":"https://codeload.github.com/CyCoreSystems/ari-proxy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252940934,"owners_count":21828769,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ari","asterisk","golang","nats","rabbitmq"],"created_at":"2024-11-15T00:20:43.525Z","updated_at":"2025-05-07T19:09:38.825Z","avatar_url":"https://github.com/CyCoreSystems.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ari-proxy\n[![Build Status](https://travis-ci.org/CyCoreSystems/ari-proxy.png)](https://travis-ci.org/CyCoreSystems/ari-proxy) [![](https://godoc.org/github.com/CyCoreSystems/ari-proxy?status.svg)](https://godoc.org/github.com/CyCoreSystems/ari-proxy)\n\nProxy for the Asterisk REST interface (ARI).\n\nThe ARI proxy facilitates scaling of both applications and Asterisk,\nindependently and with minimal coordination.  Each Asterisk instance and ARI\napplication pair runs an `ari-proxy` server instance, which talks to a common\nNATS or RabbitMQ cluster.  Each client application talks to the same message bus.  The\nclients automatically and continuously discover new Asterisk instances, so the\nonly coordination needed is the common location of the message bus.\n\nThe ARI proxy allows for:\n  - Any number of applications running the ARI client\n  - Any number of `ari-proxy` services running on any number of Asterisk\n    instances\n  - Simple call control throughout the cluster, regardless of which Asterisk\n    instance is controlling the call\n  - Simple call distribution regardless of the number of potential application\n    services.  (New calls are automatically sent to a single recipient\n    application.)\n  - Simple call event reception by any number of application clients.  (No\n    single-app lockout)\n\nSupported message buses:\n  - [NATS](https://nats.io)\n  - [RabbitMQ](https://rabbitmq.com)\n\n## Proxy server\n\n\nDocker images are kept up to date with releases and are tagged accordingly.  The\n`ari-proxy` does not expose any services, so no ports need to be opened for it.\nHowever, it does need to know how to connect to both Asterisk and the message\nbus.\n\n```\n   docker run \\\n     -e ARI_APPLICATION=\"my_test_app\" \\\n     -e ARI_USERNAME=\"demo-user\" \\\n     -e ARI_PASSWORD=\"supersecret\" \\\n     -e ARI_HTTP_URL=\"http://asterisk:8088/ari\" \\\n     -e ARI_WEBSOCKET_URL=\"ws://asterisk:8088/ari/events\" \\\n     -e MESSAGEBUS_URL=\"nats://nats:4222\" \\\n     cycoresystems/ari-proxy\n```\n\nBinary releases are available on the [releases page](https://github.com/CyCoreSystems/ari-proxy/releases).\n\nYou can also install the server manually:\n\n```\n   go install github.com/CyCoreSystems/ari-proxy/v5\n```\n\n## Client library\n\n`ari-proxy` uses semantic versioning and standard Go modules.  To use it in your\nown Go package, simply reference the\n`github.com/CyCoreSystems/ari-proxy/client/v5` package, and your dependency\nmanagement tool should be able to manage it.\n\n### Usage\n\nConnecting the client to NATS is simple:\n\n```go\nimport (\n   \"github.com/CyCoreSystems/ari/v5\"\n   \"github.com/CyCoreSystems/ari-proxy/v5/client\"\n)\n\nfunc connect(ctx context.Context, appName string) (ari.Client,error) {\n   c, err := client.New(ctx,\n      client.WithApplication(appName),\n      client.WithURI(\"nats://natshost:4222\"),\n   )\n}\n```\n\nConnecting the client to RabbitMQ is like:\n\n```go\nimport (\n   \"github.com/CyCoreSystems/ari/v5\"\n   \"github.com/CyCoreSystems/ari-proxy/v5/client\"\n)\n\nfunc connect(ctx context.Context, appName string) (ari.Client,error) {\n   c, err := client.New(ctx,\n      client.WithApplication(appName),\n      client.WithURI(\"amqp://user:password@rabbitmqhost:5679/\"),\n   )\n}\n```\n\nConfiguration of the client can also be done with environment variables.\n`ARI_APPLICATION` can be used to set the ARI application name, and `MESSAGEBUS_URL`\ncan be used to set the message bus URL.  Doing so allows you to get a client connection\nsimply with `client.New(ctx)`.\n\nOnce an `ari.Client` is obtained, the client functions exactly as the native\n[ari](https://github.com/CyCoreSystems/ari) client.\n\nMore documentation:\n\n  * [ARI library docs](https://godoc.org/github.com/CyCoreSystems/ari)\n\n  * [ARI client examples](https://github.com/CyCoreSystems/ari/tree/master/_examples)\n\n\n### Context\n\nNote the use of the `context.Context` parameter.  This can be useful to properly\nshutdown the client by a controlling context.  This shutdown will also close any\nopen subscriptions on the client.\n\nLayers of clients can be used efficiently with different contexts using the\n`New(context.Context)` function of each client instance.  Subtended clients will\nbe closed with their parents, use a common internal message bus connection, and can be\nseverally closed by their individual contexts.  This makes managing many active\nchannels easy and efficient.\n\n### Lifecycle\n\nThere are two levels of client in use.  The first is a connection, which is a\nlong-lived network connection to the message bus.  In general, the end user\nshould not close this connection.  However, it is available, if necessary, as\n`DefaultConn` and offers a `Close()` function for itself.\n\nThe second level is the ARI client.  Any number of ARI clients may make use of\nthe same underlying connection, but each client maintains its own separate bus\nand subscription implementation.  Thus, when a user closes its client, the\nconnection is maintained, but all subscriptions are released.  Users should\nalways `Close()` their clients when done with them to avoid accumulating stale\nsubscriptions.\n\n### Clustering\n\nThe ARI proxy works in a cluster setting by utilizing two coordinates:\n\n - The Asterisk ID\n - The ARI Application\n\nBetween the two of these, we can uniquely address each ARI resource, regardless\nof where the client is located.  These pieces of information are handled\ntransparently and internally by the ARI proxy and the ARI proxy client to route\ncommands and events where they should be sent.\n\n### Message bus protocol details\n\nThe protocol details described below are only necessary to know if you do not use the\nprovided client and/or server.  By using both components in this repository, the\nprotocol details below are transparently handled for you.\n\n#### Subject structure\n\nThe message bus subject prefix defaults to `ari.`, and all messages used by this proxy\nwill be prefixed by that term.\n\nNext is added one of four resource classifications:\n\n - `event` - Messages from Asterisk to clients\n - `get` - Read-only requests from clients to Asterisk\n - `command` - Non-creation operational requests from clients to Asterisk\n - `create` - Creation-related requests from clients to Asterisk\n\nAfter the resource, the ARI application is appended. \n\nFinally, the Asterisk ID will be added to the end.  Thus, the subject for an event for the\nARI application \"test\" from the Asterisk box with ID \"00:01:02:03:04:05\" would\nlook like:\n\n`ari.event.test.00:01:02:03:04:05`\n\nFor a channel creation command to the same app and node:\n\n`ari.create.test.00:01:02:03:04:05`\n\nThe Asterisk ID component of the subject is optional for commands.  If a command\ndoes not include an Asterisk ID, any ARI proxy running the provided ARI\napplication may respond to the request.  (Thus, implicitly, each ARI proxy\nservice listens to both its Asterisk ID-specific command subject and its generic\nARI application command subject.  In fact, each ARI proxy listens to each of the\nthree levels.  A request to `ari.command` will result in all ARI proxies\nresponding.)\n\nThis setup allows for a variable generalization in the listeners by using\nmessage bus\nwildcard subscriptions.  For instance, if you want to receive all events for the\n\"test\" application regardless from which Asterisk machine they come, you would subscribe to:\n\n`ari.event.test.\u003e` //NATS\n`ari.event.test.#` //RabbitMQ\n\n#### Dialogs\n\nEvents may be further classified by the arbitrary \"dialog\" ID.  If any command\nspecifies a Dialog ID in its metadata, the ARI proxy will further classify\nevents related to that dialog.  Relationships are defined by the entity type on\nwhich the Dialog-infused command operates.\n\nDialog-related events are published on their own message bus subject tree,\n`dialogevent`.  Thus dialogs abstract ARI application and Asterisk ID.  An event\nfor dialog \"testme123\" would be published to:\n\n`ari.dialogevent.testme123`\n\nKeep in mind that regardless of dialog associations, all events are _also_\npublished to their appropriate canonical message bus subjects.  Dialogs are intended as\na mechanism to:\n\n  - reduce client message traffic load\n  - transcend ARI Applications and/or Asterisk nodes while maintaining logical\n    separation of events\n\n#### Message delivery\n\nThe means of a delivery for a generically-routed message depends on the type of\nmessage it is.\n\n  - Events are always delivered to all listeners.\n  - Read-only commands are delivered to all listeners.\n  - Non-creation operation commands are delivered to all listeners.\n  - Creation-related commands are delivered to only one listener.\n\nThus, for efficiency, it is always recommended to use as precise a subject line\nas possible.\n\n#### Node discovery\n\nEach ARI proxy sends out a periodic ping announcing itself in the cluster.\nClients may aggregate these pings to construct an expected map of machines in\nthe cluster.  Knowing this map allows the client to optimize its all-listener\ncommands by cancelling the wait period if it receives responses from all nodes\nbefore the timeout has elapsed.\n\nARI proxies listen to `ari.ping` and send announcements on `ari.announce`.  The\nstructure of the announcement is thus:\n\n```json\n{\n   \"asterisk\": \"00:10:20:30:40:50\",\n   \"application\": \"test\"\n}\n```\n\n#### Payload structure\n\nFor most requests, payloads exactly match their ARI library values.  However,\ntreatment of handlers is slightly different.\n\nInstead of a handler, an `Entity` or array of `Entity`s is returned.  This\nresponse type contains the Metadata for the entity (ARI application, Asterisk\nID, and optionally Dialog) as well as the unique ID of the entity.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcycoresystems%2Fari-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcycoresystems%2Fari-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcycoresystems%2Fari-proxy/lists"}