feat: add asterisk ARI websocket interface (#159)

* chore: remove old files

* feat: ari outbound dialing

* feat: add websocket configuration for ARI

* feat: handling inbound calls

* delete ext channel from redis on stasis end

* fix: add lock in workflow run update, refactor _handle_stasis_start

* chore: update submodule

---------

Co-authored-by: Sabiha Khan <sabihak89@gmail.com>
This commit is contained in:
Abhishek 2026-02-17 19:32:03 +05:30 committed by GitHub
parent ee4a874e54
commit 7552b6c819
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 2076 additions and 4172 deletions

View file

@ -1,4 +1,4 @@
from typing import Any, Optional
from typing import Any, Dict, List, Optional
from sqlalchemy.future import select
@ -94,3 +94,27 @@ class OrganizationConfigurationClient(BaseDBClient):
"""Get the value of a configuration, returning default if not found."""
config = await self.get_configuration(organization_id, key)
return config.value if config else default
async def get_configurations_by_provider(
self, key: str, provider: str
) -> List[Dict[str, Any]]:
"""Get all organization configurations for a given key filtered by provider.
Returns a list of dicts with organization_id and the config value.
"""
async with self.async_session() as session:
result = await session.execute(
select(OrganizationConfigurationModel).where(
OrganizationConfigurationModel.key == key,
)
)
configs = result.scalars().all()
return [
{
"organization_id": config.organization_id,
"value": config.value,
}
for config in configs
if config.value and config.value.get("provider") == provider
]

View file

@ -321,8 +321,11 @@ class WorkflowRunClient(BaseDBClient):
state: str | None = None,
) -> WorkflowRunModel:
async with self.async_session() as session:
# Use SELECT FOR UPDATE to lock the row during the update
result = await session.execute(
select(WorkflowRunModel).where(WorkflowRunModel.id == run_id)
select(WorkflowRunModel)
.where(WorkflowRunModel.id == run_id)
.with_for_update()
)
run = result.scalars().first()
if not run: