Telnyx activities enhancements
This commit is contained in:
parent
b4f83f43aa
commit
c2ce8a72b9
|
|
@ -1,8 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Telnyx.Client.Models;
|
||||
using Elsa.Activities.Telnyx.Client.Services;
|
||||
using Elsa.Activities.Telnyx.Extensions;
|
||||
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Builders;
|
||||
|
|
@ -18,7 +21,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
[Action(
|
||||
Category = Constants.Category,
|
||||
Description = "Bridge two call control calls.",
|
||||
Outcomes = new[] { OutcomeNames.Done, TelnyxOutcomeNames.CallIsNoLongerActive },
|
||||
Outcomes = new[] {TelnyxOutcomeNames.Bridging, TelnyxOutcomeNames.Bridged, TelnyxOutcomeNames.LegABridged, TelnyxOutcomeNames.LegBBridged, OutcomeNames.Done, TelnyxOutcomeNames.CallIsNoLongerActive},
|
||||
DisplayName = "Bridge Calls"
|
||||
)]
|
||||
public class BridgeCalls : Activity
|
||||
|
|
@ -30,40 +33,52 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
_telnyxClient = telnyxClient;
|
||||
}
|
||||
|
||||
[ActivityInput(Label = "Call Control ID A", Hint = "Unique identifier and token for controlling the call.", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public string? CallControlIdA { get; set; } = default!;
|
||||
[ActivityInput(Label = "Call Control ID A", Hint = "Unique identifier and token for controlling the call.", SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string? CallControlIdA { get; set; }
|
||||
|
||||
[ActivityInput(Label = "Call Control ID B", Hint = "The Call Control ID of the call you want to bridge with.", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public string CallControlIdB { get; set; } = default!;
|
||||
[ActivityInput(Label = "Call Control ID B", Hint = "The Call Control ID of the call you want to bridge with.", SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string? CallControlIdB { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Label = "Command ID",
|
||||
Hint = "Use this field to avoid duplicate commands. Telnyx will ignore commands with the same Command ID.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string? CommandId { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "Use this field to add state to every subsequent webhook. It must be a valid Base-64 encoded string.",
|
||||
Hint = "Use this field to add state to every subsequent webhook. It must be a valid Base-64 encoded string.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string? ClientState { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Label = "Park After Unbridged",
|
||||
Hint = "HTTP request type used for Webhook URL",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] { "", "self" },
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
Label = "Park After Unbridged",
|
||||
Hint = "HTTP request type used for Webhook URL",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] {"", "self"},
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string? ParkAfterUnbridged { get; set; }
|
||||
|
||||
[ActivityOutput] public CallBridgedPayload? CallBridgedPayloadA { get; set; }
|
||||
[ActivityOutput] public CallBridgedPayload? CallBridgedPayloadB { get; set; }
|
||||
|
||||
protected override async ValueTask<IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
var callControlIdA = context.GetCallControlId(CallControlIdA);
|
||||
CallBridgedPayloadA = null;
|
||||
CallBridgedPayloadB = null;
|
||||
|
||||
var callControlIdA = CallControlIdA = context.GetCallControlId(CallControlIdA);
|
||||
var callControlIdB = CallControlIdB = GetCallControlB(context);
|
||||
|
||||
if (callControlIdB == null)
|
||||
throw new WorkflowException("Cannot bridge calls because the second leg's call control ID was not specified and no incoming activities provided this value");
|
||||
|
||||
CallControlIdA = callControlIdA;
|
||||
|
||||
var request = new BridgeCallsRequest(
|
||||
CallControlIdB,
|
||||
callControlIdB,
|
||||
ClientState,
|
||||
CommandId,
|
||||
ParkAfterUnbridged
|
||||
|
|
@ -72,7 +87,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
try
|
||||
{
|
||||
await _telnyxClient.Calls.BridgeCallsAsync(callControlIdA, request, context.CancellationToken);
|
||||
return Done();
|
||||
return Combine(Outcome(TelnyxOutcomeNames.Bridging), Suspend());
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
|
|
@ -82,6 +97,50 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
throw new WorkflowException(e.Content ?? e.Message, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IActivityExecutionResult OnResume(ActivityExecutionContext context)
|
||||
{
|
||||
var payload = context.GetInput<CallBridgedPayload>()!;
|
||||
var results = new List<IActivityExecutionResult>();
|
||||
|
||||
if (payload.CallControlId == CallControlIdA)
|
||||
{
|
||||
CallBridgedPayloadA = payload;
|
||||
results.Add(Outcome(TelnyxOutcomeNames.LegABridged, payload));
|
||||
}
|
||||
|
||||
if (payload.CallControlId == CallControlIdB)
|
||||
{
|
||||
CallBridgedPayloadB = payload;
|
||||
results.Add(Outcome(TelnyxOutcomeNames.LegBBridged, payload));
|
||||
}
|
||||
|
||||
if (CallBridgedPayloadA != null && CallBridgedPayloadB != null)
|
||||
{
|
||||
results.Add(Outcome(TelnyxOutcomeNames.Bridged));
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(Suspend());
|
||||
}
|
||||
|
||||
return Combine(results);
|
||||
}
|
||||
|
||||
private string? GetCallControlB(ActivityExecutionContext context)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(CallControlIdB))
|
||||
return CallControlIdB;
|
||||
|
||||
var input = context.GetInput<CallAnsweredPayload>();
|
||||
|
||||
if (input != null)
|
||||
return input.CallControlId;
|
||||
|
||||
var inboundCallActivityId = context.WorkflowExecutionContext.GetInboundConnections(Id).Where(x => x.Source.Activity.Type == nameof(Dial)).Select(x => x.Source.Activity.Id).FirstOrDefault();
|
||||
var inboundCallActivityResponse = inboundCallActivityId != null ? context.WorkflowExecutionContext.GetActivityProperty<Dial, DialResponse>(inboundCallActivityId, x => x.DialResponse) : default;
|
||||
return inboundCallActivityResponse != null ? inboundCallActivityResponse.CallControlId : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BridgeCallsExtensions
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
[Action(
|
||||
Category = Constants.Category,
|
||||
Description = "Call a ring group.",
|
||||
Outcomes = new[] { "Connected", "No Response" },
|
||||
Outcomes = new[] {TelnyxOutcomeNames.Connected, TelnyxOutcomeNames.NoResponse},
|
||||
DisplayName = "Call Ring Group"
|
||||
)]
|
||||
public class CallRingGroup : CompositeActivity, IActivityPropertyDefaultValueProvider
|
||||
|
|
@ -38,14 +38,14 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
[ActivityInput(UIHint = ActivityInputUIHints.MultiText, DefaultSyntax = SyntaxNames.Json, SupportedSyntaxes = new[] { SyntaxNames.Json, SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
[ActivityInput(UIHint = ActivityInputUIHints.MultiText, DefaultSyntax = SyntaxNames.Json, SupportedSyntaxes = new[] {SyntaxNames.Json, SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public IList<string> Extensions
|
||||
{
|
||||
get => GetState<IList<string>>(() => new List<string>());
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(Label = "Call Control ID", Hint = "Unique identifier and token for controlling the call.", Category = PropertyCategories.Advanced, SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
[ActivityInput(Label = "Call Control ID", Hint = "Unique identifier and token for controlling the call.", Category = PropertyCategories.Advanced, SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string CallControlId
|
||||
{
|
||||
get => GetState<string>()!;
|
||||
|
|
@ -56,7 +56,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
Label = "Call Control App ID",
|
||||
Hint = "The ID of the Call Control App (formerly ID of the connection) to be used when dialing the destination.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? CallControlAppId
|
||||
{
|
||||
|
|
@ -64,7 +64,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
[ActivityInput(SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public RingGroupStrategy Strategy
|
||||
{
|
||||
get => GetState<RingGroupStrategy>();
|
||||
|
|
@ -73,7 +73,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
|
||||
[ActivityInput(
|
||||
Hint = "The 'from' number to be used as the caller id presented to the destination ('To' number). The number should be in +E164 format. This attribute will default to the 'From' number of the original call if omitted.",
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? From
|
||||
{
|
||||
|
|
@ -84,7 +84,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
[ActivityInput(
|
||||
Hint =
|
||||
"The string to be used as the caller id name (SIP From Display Name) presented to the destination ('To' number). The string should have a maximum of 128 characters, containing only letters, numbers, spaces, and -_~!.+ special characters. If omitted, the display name will be the same as the number in the 'From' field.",
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? FromDisplayName
|
||||
{
|
||||
|
|
@ -92,19 +92,13 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
set => SetState(value);
|
||||
}
|
||||
|
||||
[ActivityInput(DefaultValueProvider = typeof(CallRingGroup), SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
[ActivityInput(DefaultValueProvider = typeof(CallRingGroup), SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public Duration RingTime
|
||||
{
|
||||
get => GetState(() => Duration.FromSeconds(20));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
private string? DialedControlId
|
||||
{
|
||||
get => GetState<string?>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
private CallAnsweredPayload? CallAnsweredPayload
|
||||
{
|
||||
get => GetState<CallAnsweredPayload?>();
|
||||
|
|
@ -148,64 +142,53 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
private void BuildPrioritizedHuntFlow(IOutcomeBuilder builder) =>
|
||||
builder
|
||||
.ForEach(() => Extensions, iterate => iterate
|
||||
.Then<Dial>(a => a
|
||||
.WithConnectionId(() => CallControlAppId)
|
||||
.WithTo(async context => await ResolveExtensionAsync(context, context.GetInput<string>()!))
|
||||
.WithTimeoutSecs(() => (int) RingTime.TotalSeconds)
|
||||
.WithFrom(() => From)
|
||||
.WithFromDisplayName(() => FromDisplayName)
|
||||
.WithClientState(context => new ClientStatePayload(context.CorrelationId!).ToBase64())
|
||||
.Then<Dial>(dial => dial
|
||||
.WithConnectionId(() => CallControlAppId)
|
||||
.WithTo(ResolveExtensionAsync)
|
||||
.WithTimeoutSecs(() => (int) RingTime.TotalSeconds)
|
||||
.WithFrom(() => From)
|
||||
.WithFromDisplayName(() => FromDisplayName),
|
||||
dial =>
|
||||
{
|
||||
dial
|
||||
.When(TelnyxOutcomeNames.Answered)
|
||||
.Then<BridgeCalls>(bridgeCalls =>
|
||||
bridgeCalls.When(TelnyxOutcomeNames.Bridged)
|
||||
.Finish(TelnyxOutcomeNames.Connected));
|
||||
}
|
||||
)
|
||||
.Then(context => DialedControlId = context.GetInput<DialResponse>()!.CallControlId)
|
||||
.Then<Fork>(fork => fork.WithBranches("Connected", "No Response"), fork =>
|
||||
{
|
||||
fork
|
||||
.When("Connected")
|
||||
.ThenTypeNamed(CallAnsweredPayload.ActivityTypeName)
|
||||
.Then(context => CallAnsweredPayload = (CallAnsweredPayload) context.GetInput<TelnyxWebhook>()!.Data.Payload)
|
||||
.Then<BridgeCalls>(bridge => bridge
|
||||
.WithCallControlIdA(() => CallControlId)
|
||||
.WithCallControlIdB(() => DialedControlId))
|
||||
.ThenTypeNamed(CallBridgedPayload.ActivityTypeName)
|
||||
.ThenTypeNamed(CallBridgedPayload.ActivityTypeName)
|
||||
.Then<Finish>(finish => finish.WithOutcome("Connected").WithOutput(() => CallAnsweredPayload));
|
||||
|
||||
fork
|
||||
.When("No Response")
|
||||
.ThenTypeNamed(CallHangupPayload.ActivityTypeName);
|
||||
})
|
||||
)
|
||||
.Finish("No Response");
|
||||
.Finish(TelnyxOutcomeNames.NoResponse);
|
||||
|
||||
private void BuildRingAllFlow(IOutcomeBuilder builder) =>
|
||||
builder
|
||||
.Then<Fork>(fork => fork.WithBranches("Connected", "Timeout", "Dial Everyone"), fork =>
|
||||
{
|
||||
fork
|
||||
.When("Connected")
|
||||
.When(TelnyxOutcomeNames.Connected)
|
||||
.ThenTypeNamed(CallAnsweredPayload.ActivityTypeName)
|
||||
.Then(context => CallAnsweredPayload = (CallAnsweredPayload) context.GetInput<TelnyxWebhook>()!.Data.Payload)
|
||||
.Then<BridgeCalls>(bridge => bridge
|
||||
.WithCallControlIdA(() => CallControlId)
|
||||
.WithCallControlIdB(() => CallAnsweredPayload!.CallControlId))
|
||||
.ThenTypeNamed(CallBridgedPayload.ActivityTypeName)
|
||||
.Then<Finish>(finish => finish.WithOutcome("Connected").WithOutput(() => CallAnsweredPayload));
|
||||
.WithCallControlIdB(() => CallAnsweredPayload!.CallControlId), bridge => bridge
|
||||
.When(TelnyxOutcomeNames.Bridged)
|
||||
.Finish(TelnyxOutcomeNames.Connected));
|
||||
|
||||
fork
|
||||
.When("Timeout")
|
||||
.StartIn(() => RingTime)
|
||||
.Finish("No Response");
|
||||
.Finish(TelnyxOutcomeNames.NoResponse);
|
||||
|
||||
fork
|
||||
.When("Dial Everyone")
|
||||
.ParallelForEach(() => Extensions, iterate => iterate
|
||||
.Then<Dial>(a => a
|
||||
.WithSuspendWorkflow(false)
|
||||
.WithConnectionId(() => CallControlAppId)
|
||||
.WithTo(async context => await ResolveExtensionAsync(context, context.GetInput<string>()!))
|
||||
.WithTo(ResolveExtensionAsync)
|
||||
.WithTimeoutSecs(() => (int) RingTime.TotalSeconds)
|
||||
.WithFrom(() => From)
|
||||
.WithFromDisplayName(() => FromDisplayName)
|
||||
.WithClientState(context => new ClientStatePayload(context.CorrelationId!).ToBase64())
|
||||
)
|
||||
.Then(CollectCallControlIds));
|
||||
});
|
||||
|
|
@ -217,9 +200,13 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
collection.Add(dialResponse);
|
||||
CollectedDialResponses = collection;
|
||||
}
|
||||
|
||||
private static async Task<string> ResolveExtensionAsync(ActivityExecutionContext context, string extension)
|
||||
|
||||
private static async ValueTask<string> ResolveExtensionAsync(ActivityExecutionContext context)
|
||||
{
|
||||
if (context.Resuming)
|
||||
return context.GetActivityProperty<Dial, string>(x => x.To)!;
|
||||
|
||||
var extension = context.GetInput<string>()!;
|
||||
var extensionProvider = context.GetService<IExtensionProvider>();
|
||||
var resolvedExtension = await extensionProvider.GetAsync(extension, context.CancellationToken);
|
||||
return resolvedExtension?.Number ?? extension;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ using Elsa.Activities.Telnyx.Client.Models;
|
|||
using Elsa.Activities.Telnyx.Client.Services;
|
||||
using Elsa.Activities.Telnyx.Exceptions;
|
||||
using Elsa.Activities.Telnyx.Extensions;
|
||||
using Elsa.Activities.Telnyx.Models;
|
||||
using Elsa.Activities.Telnyx.Options;
|
||||
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Builders;
|
||||
|
|
@ -21,7 +23,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
[Action(
|
||||
Category = Constants.Category,
|
||||
Description = "Dial a number or SIP URI from a given connection.",
|
||||
Outcomes = new[] { OutcomeNames.Done },
|
||||
Outcomes = new[] { TelnyxOutcomeNames.Dialing, TelnyxOutcomeNames.CallInitiated, TelnyxOutcomeNames.Answered, TelnyxOutcomeNames.Hangup, OutcomeNames.Done },
|
||||
DisplayName = "Dial"
|
||||
)]
|
||||
public class Dial : Activity
|
||||
|
|
@ -76,12 +78,6 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public string? CommandId { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "Use this field to add state to every subsequent webhook. It must be a valid Base-64 encoded string.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public string? ClientState { get; set; }
|
||||
|
||||
[ActivityInput(Label = "Custom Headers", Hint = "Custom headers to be added to the SIP INVITE.", Category = PropertyCategories.Advanced, UIHint = ActivityInputUIHints.Json)]
|
||||
public IList<Header>? CustomHeaders { get; set; }
|
||||
|
||||
|
|
@ -116,10 +112,36 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
public string? WebhookUrlMethod { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "A flag indicating whether this activity should complete immediately or suspend the workflow.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
DefaultValue = true,
|
||||
SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public bool SuspendWorkflow { get; set; } = true;
|
||||
|
||||
[ActivityOutput] public DialResponse DialResponse { get; set; }
|
||||
|
||||
protected override async ValueTask<IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
var response = await DialAsync(context);
|
||||
return Done(response);
|
||||
DialResponse = response;
|
||||
|
||||
return !SuspendWorkflow
|
||||
? Done(response)
|
||||
: Combine(Outcome(TelnyxOutcomeNames.Dialing, response), Suspend());
|
||||
}
|
||||
|
||||
protected override IActivityExecutionResult OnResume(ActivityExecutionContext context)
|
||||
{
|
||||
var payload = context.GetInput<CallPayload>();
|
||||
|
||||
return payload switch
|
||||
{
|
||||
CallAnsweredPayload callAnsweredPayload => Outcome(TelnyxOutcomeNames.Answered, callAnsweredPayload),
|
||||
CallHangupPayload callHangupPayload => Outcome(TelnyxOutcomeNames.Hangup, callHangupPayload),
|
||||
CallInitiatedPayload callInitiatedPayload => Combine(Outcome(TelnyxOutcomeNames.CallInitiated, callInitiatedPayload), Suspend()),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(payload))
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<DialResponse> DialAsync(ActivityExecutionContext context)
|
||||
|
|
@ -131,6 +153,8 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
|
||||
var fromNumber = context.GetFromNumber(From);
|
||||
|
||||
var clientState = new ClientStatePayload(context.CorrelationId!).ToBase64();
|
||||
|
||||
var request = new DialRequest(
|
||||
connectionId,
|
||||
To,
|
||||
|
|
@ -138,7 +162,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
FromDisplayName,
|
||||
AnsweringMachineDetection,
|
||||
AnsweringMachineDetectionConfig,
|
||||
ClientState,
|
||||
clientState,
|
||||
CommandId,
|
||||
CustomHeaders,
|
||||
SipAuthUsername,
|
||||
|
|
@ -207,12 +231,6 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
public static ISetupActivity<Dial> WithCommandId(this ISetupActivity<Dial> setup, Func<string?> value) => setup.Set(x => x.CommandId, value);
|
||||
public static ISetupActivity<Dial> WithCommandId(this ISetupActivity<Dial> setup, string? value) => setup.Set(x => x.CommandId, value);
|
||||
|
||||
public static ISetupActivity<Dial> WithClientState(this ISetupActivity<Dial> setup, Func<ActivityExecutionContext, ValueTask<string?>> value) => setup.Set(x => x.ClientState, value);
|
||||
public static ISetupActivity<Dial> WithClientState(this ISetupActivity<Dial> setup, Func<ActivityExecutionContext, string?> value) => setup.Set(x => x.ClientState, value);
|
||||
public static ISetupActivity<Dial> WithClientState(this ISetupActivity<Dial> setup, Func<ValueTask<string?>> value) => setup.Set(x => x.ClientState, value);
|
||||
public static ISetupActivity<Dial> WithClientState(this ISetupActivity<Dial> setup, Func<string?> value) => setup.Set(x => x.ClientState, value);
|
||||
public static ISetupActivity<Dial> WithClientState(this ISetupActivity<Dial> setup, string? value) => setup.Set(x => x.ClientState, value);
|
||||
|
||||
public static ISetupActivity<Dial> WithCustomHeaders(this ISetupActivity<Dial> setup, Func<ActivityExecutionContext, ValueTask<IList<Header>?>> value) => setup.Set(x => x.CustomHeaders, value);
|
||||
public static ISetupActivity<Dial> WithCustomHeaders(this ISetupActivity<Dial> setup, Func<ActivityExecutionContext, IList<Header>?> value) => setup.Set(x => x.CustomHeaders, value);
|
||||
public static ISetupActivity<Dial> WithCustomHeaders(this ISetupActivity<Dial> setup, Func<ValueTask<IList<Header>?>> value) => setup.Set(x => x.CustomHeaders, value);
|
||||
|
|
@ -254,5 +272,11 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
public static ISetupActivity<Dial> WithWebhookUrlMethod(this ISetupActivity<Dial> setup, Func<ValueTask<string?>> value) => setup.Set(x => x.WebhookUrlMethod, value);
|
||||
public static ISetupActivity<Dial> WithWebhookUrlMethod(this ISetupActivity<Dial> setup, Func<string?> value) => setup.Set(x => x.WebhookUrlMethod, value);
|
||||
public static ISetupActivity<Dial> WithWebhookUrlMethod(this ISetupActivity<Dial> setup, string? value) => setup.Set(x => x.WebhookUrlMethod, value);
|
||||
|
||||
public static ISetupActivity<Dial> WithSuspendWorkflow(this ISetupActivity<Dial> setup, Func<ActivityExecutionContext, ValueTask<bool>> value) => setup.Set(x => x.SuspendWorkflow, value);
|
||||
public static ISetupActivity<Dial> WithSuspendWorkflow(this ISetupActivity<Dial> setup, Func<ActivityExecutionContext, bool> value) => setup.Set(x => x.SuspendWorkflow, value);
|
||||
public static ISetupActivity<Dial> WithSuspendWorkflow(this ISetupActivity<Dial> setup, Func<ValueTask<bool>> value) => setup.Set(x => x.SuspendWorkflow, value);
|
||||
public static ISetupActivity<Dial> WithSuspendWorkflow(this ISetupActivity<Dial> setup, Func<bool> value) => setup.Set(x => x.SuspendWorkflow, value);
|
||||
public static ISetupActivity<Dial> WithSuspendWorkflow(this ISetupActivity<Dial> setup, bool value) => setup.Set(x => x.SuspendWorkflow, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
[Job(
|
||||
Category = Constants.Category,
|
||||
Description = "Play an audio file on the call until the required DTMF signals are gathered to build interactive menus.",
|
||||
Outcomes = new[] { TelnyxOutcomeNames.Pending, TelnyxOutcomeNames.GatherCompleted, TelnyxOutcomeNames.CallIsNoLongerActive },
|
||||
Outcomes = new[] { TelnyxOutcomeNames.GatheringInput, TelnyxOutcomeNames.GatherCompleted, TelnyxOutcomeNames.CallIsNoLongerActive },
|
||||
DisplayName = "Gather Using Audio"
|
||||
)]
|
||||
public class GatherUsingAudio : Activity
|
||||
|
|
@ -121,7 +121,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
try
|
||||
{
|
||||
await _telnyxClient.Calls.GatherUsingAudioAsync(callControlId, request, context.CancellationToken);
|
||||
return Combine(Outcome(TelnyxOutcomeNames.Pending), Suspend());
|
||||
return Combine(Outcome(TelnyxOutcomeNames.GatheringInput), Suspend());
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
[Action(
|
||||
Category = Constants.Category,
|
||||
Description = "Convert text to speech and play it on the call until the required DTMF signals are gathered to build interactive menus.",
|
||||
Outcomes = new[] { TelnyxOutcomeNames.Pending, TelnyxOutcomeNames.GatherCompleted, TelnyxOutcomeNames.CallIsNoLongerActive },
|
||||
Outcomes = new[] { TelnyxOutcomeNames.GatheringInput, TelnyxOutcomeNames.GatherCompleted, TelnyxOutcomeNames.CallIsNoLongerActive },
|
||||
DisplayName = "Gather Using Speak"
|
||||
)]
|
||||
public class GatherUsingSpeak : Activity
|
||||
|
|
@ -151,7 +151,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
try
|
||||
{
|
||||
await _telnyxClient.Calls.GatherUsingSpeakAsync(callControlId, request, context.CancellationToken);
|
||||
return Combine(Outcome(TelnyxOutcomeNames.Pending), Suspend());
|
||||
return Combine(Outcome(TelnyxOutcomeNames.GatheringInput), Suspend());
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
try
|
||||
{
|
||||
await _telnyxClient.Calls.SpeakTextAsync(callControlId, request, context.CancellationToken);
|
||||
return Combine(Outcome(TelnyxOutcomeNames.Pending), Suspend());
|
||||
return Combine(Outcome(TelnyxOutcomeNames.Speaking), Suspend());
|
||||
}
|
||||
catch (ApiException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||
using Elsa.Activities.Telnyx.Client.Models;
|
||||
using Elsa.Activities.Telnyx.Client.Services;
|
||||
using Elsa.Activities.Telnyx.Extensions;
|
||||
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
|
||||
using Elsa.ActivityResults;
|
||||
using Elsa.Attributes;
|
||||
using Elsa.Builders;
|
||||
|
|
@ -19,7 +20,14 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
[Action(
|
||||
Category = Constants.Category,
|
||||
Description = "Transfer a call to a new destination",
|
||||
Outcomes = new[] { OutcomeNames.Done },
|
||||
Outcomes = new[]
|
||||
{
|
||||
TelnyxOutcomeNames.Transferring,
|
||||
TelnyxOutcomeNames.CallInitiated,
|
||||
TelnyxOutcomeNames.Bridged,
|
||||
TelnyxOutcomeNames.Answered,
|
||||
TelnyxOutcomeNames.Hangup
|
||||
},
|
||||
DisplayName = "Transfer Call"
|
||||
)]
|
||||
public class TransferCall : Activity
|
||||
|
|
@ -35,23 +43,23 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
Label = "Call Control ID",
|
||||
Hint = "Unique identifier and token for controlling the call.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? CallControlId { get; set; } = default!;
|
||||
|
||||
[ActivityInput(Label = "To", Hint = "The DID or SIP URI to dial out and bridge to the given call.", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
[ActivityInput(Label = "To", Hint = "The DID or SIP URI to dial out and bridge to the given call.", SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string To { get; set; } = default!;
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "The 'from' number to be used as the caller id presented to the destination ('To' number). The number should be in +E164 format. This attribute will default to the 'From' number of the original call if omitted.",
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? From { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Hint =
|
||||
"The string to be used as the caller id name (SIP From Display Name) presented to the destination ('To' number). The string should have a maximum of 128 characters, containing only letters, numbers, spaces, and -_~!.+ special characters. If omitted, the display name will be the same as the number in the 'From' field.",
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? FromDisplayName { get; set; }
|
||||
|
||||
|
|
@ -59,8 +67,8 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
Label = "Answering Machine Detection",
|
||||
Hint = "Enables Answering Machine Detection.",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] { "disabled", "detect", "detect_beep", "detect_words", "greeting_end" },
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
Options = new[] {"disabled", "detect", "detect_beep", "detect_words", "greeting_end"},
|
||||
SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? AnsweringMachineDetection { get; set; }
|
||||
|
||||
|
|
@ -76,46 +84,46 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
Label = "Command ID",
|
||||
Hint = "Use this field to avoid duplicate commands. Telnyx will ignore commands with the same Command ID.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? CommandId { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Label = "Audio URL",
|
||||
Hint = "Audio URL to be played back when the transfer destination answers before bridging the call. The URL can point to either a WAV or MP3 file.",
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public Uri? AudioUrl { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "Use this field to add state to every subsequent webhook. It must be a valid Base-64 encoded string.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string? ClientState { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Hint = "Use this field to add state to every subsequent webhook for the new leg. It must be a valid Base-64 encoded string.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? TargetLegClientState { get; set; }
|
||||
|
||||
[ActivityInput(Hint = "Custom headers to be added to the SIP INVITE.", Category = PropertyCategories.Advanced, UIHint = ActivityInputUIHints.Json)]
|
||||
public IList<Header>? CustomHeaders { get; set; }
|
||||
|
||||
[ActivityInput(Label = "SIP Authentication Username", Hint = "SIP Authentication username used for SIP challenges.", Category = "SIP Authentication", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
[ActivityInput(Label = "SIP Authentication Username", Hint = "SIP Authentication username used for SIP challenges.", Category = "SIP Authentication", SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string? SipAuthUsername { get; set; }
|
||||
|
||||
[ActivityInput(Label = "SIP Authentication Password", Hint = "SIP Authentication password used for SIP challenges.", Category = "SIP Authentication", SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
[ActivityInput(Label = "SIP Authentication Password", Hint = "SIP Authentication password used for SIP challenges.", Category = "SIP Authentication", SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public string? SipAuthPassword { get; set; }
|
||||
|
||||
[ActivityInput(Label = "Time Limit", Hint = "Sets the maximum duration of a Call Control Leg in seconds.", Category = PropertyCategories.Advanced, SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })]
|
||||
[ActivityInput(Label = "Time Limit", Hint = "Sets the maximum duration of a Call Control Leg in seconds.", Category = PropertyCategories.Advanced, SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid})]
|
||||
public int? TimeLimitSecs { get; set; }
|
||||
|
||||
[ActivityInput(
|
||||
Label = "Timeout",
|
||||
Hint = "The number of seconds that Telnyx will wait for the call to be answered by the destination to which it is being transferred.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public int? TimeoutSecs { get; set; }
|
||||
|
||||
|
|
@ -123,7 +131,7 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
Label = "Webhook URL",
|
||||
Hint = "Use this field to override the URL for which Telnyx will send subsequent webhooks to for this call.",
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? WebhookUrl { get; set; }
|
||||
|
||||
|
|
@ -131,22 +139,36 @@ namespace Elsa.Activities.Telnyx.Activities
|
|||
Label = "Webhook URL Method",
|
||||
Hint = "HTTP request type used for Webhook URL",
|
||||
UIHint = ActivityInputUIHints.Dropdown,
|
||||
Options = new[] { "GET", "POST" },
|
||||
Options = new[] {"GET", "POST"},
|
||||
Category = PropertyCategories.Advanced,
|
||||
SupportedSyntaxes = new[] { SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid }
|
||||
SupportedSyntaxes = new[] {SyntaxNames.Literal, SyntaxNames.JavaScript, SyntaxNames.Liquid}
|
||||
)]
|
||||
public string? WebhookUrlMethod { get; set; }
|
||||
|
||||
protected override async ValueTask<IActivityExecutionResult> OnExecuteAsync(ActivityExecutionContext context)
|
||||
{
|
||||
await TransferCallAsync(context);
|
||||
return Done();
|
||||
return Combine(Outcome(TelnyxOutcomeNames.Transferring), Suspend());
|
||||
}
|
||||
|
||||
protected override IActivityExecutionResult OnResume(ActivityExecutionContext context)
|
||||
{
|
||||
var payload = context.GetInput<CallPayload>();
|
||||
|
||||
return payload switch
|
||||
{
|
||||
CallAnsweredPayload callAnsweredPayload => Outcome(TelnyxOutcomeNames.Answered, callAnsweredPayload),
|
||||
CallBridgedPayload callBridgedPayload => Outcome(TelnyxOutcomeNames.Bridged, callBridgedPayload),
|
||||
CallHangupPayload callHangupPayload => Outcome(TelnyxOutcomeNames.Hangup, callHangupPayload),
|
||||
CallInitiatedPayload callInitiatedPayload => Outcome(TelnyxOutcomeNames.CallInitiated, callInitiatedPayload),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(payload))
|
||||
};
|
||||
}
|
||||
|
||||
private async ValueTask TransferCallAsync(ActivityExecutionContext context)
|
||||
{
|
||||
var fromNumber = context.GetFromNumber(From);
|
||||
|
||||
|
||||
var request = new TransferCallRequest(
|
||||
To,
|
||||
fromNumber,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using Elsa.Activities.Telnyx.Activities;
|
||||
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
|
||||
using Elsa.Services;
|
||||
|
||||
namespace Elsa.Activities.Telnyx.Handlers
|
||||
{
|
||||
public class ResumeBridgeCalls : ResumeWebhookDrivenActivity<BridgeCalls, CallBridgedPayload>
|
||||
{
|
||||
public ResumeBridgeCalls(IWorkflowLaunchpad workflowLaunchpad) : base(workflowLaunchpad)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/activities/Elsa.Activities.Telnyx/Handlers/ResumeDial.cs
Normal file
17
src/activities/Elsa.Activities.Telnyx/Handlers/ResumeDial.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.Activities.Telnyx.Activities;
|
||||
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
|
||||
using Elsa.Services;
|
||||
|
||||
namespace Elsa.Activities.Telnyx.Handlers
|
||||
{
|
||||
public class ResumeDial : ResumeWebhookDrivenActivity<Dial>
|
||||
{
|
||||
public ResumeDial(IWorkflowLaunchpad workflowLaunchpad) : base(workflowLaunchpad)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<Type> GetSupportedPayloadTypes() => new[] {typeof(CallInitiatedPayload), typeof(CallAnsweredPayload), typeof(CallHangupPayload)};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.Activities.Telnyx.Activities;
|
||||
using Elsa.Activities.Telnyx.Webhooks.Payloads.Call;
|
||||
using Elsa.Services;
|
||||
|
||||
namespace Elsa.Activities.Telnyx.Handlers
|
||||
{
|
||||
public class ResumeTransferCall : ResumeWebhookDrivenActivity<TransferCall>
|
||||
{
|
||||
public ResumeTransferCall(IWorkflowLaunchpad workflowLaunchpad) : base(workflowLaunchpad)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<Type> GetSupportedPayloadTypes() => new[] {typeof(CallAnsweredPayload), typeof(CallInitiatedPayload), typeof(CallBridgedPayload), typeof(CallHangupPayload)};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Telnyx.Activities;
|
||||
using Elsa.Activities.Telnyx.Models;
|
||||
using Elsa.Activities.Telnyx.Providers.Bookmarks;
|
||||
using Elsa.Activities.Telnyx.Webhooks.Events;
|
||||
|
|
@ -11,27 +13,41 @@ using MediatR;
|
|||
|
||||
namespace Elsa.Activities.Telnyx.Handlers
|
||||
{
|
||||
public abstract class ResumeWebhookDrivenActivity<TActivity, TPayload> : INotificationHandler<TelnyxWebhookReceived> where TPayload: CallPayload
|
||||
public abstract class ResumeWebhookDrivenActivity<TActivity, TPayload> : ResumeWebhookDrivenActivity<TActivity> where TPayload : CallPayload
|
||||
{
|
||||
protected ResumeWebhookDrivenActivity(IWorkflowLaunchpad workflowLaunchpad) : base(workflowLaunchpad)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<Type> GetSupportedPayloadTypes() => new[] {typeof(TPayload)};
|
||||
}
|
||||
|
||||
public abstract class ResumeWebhookDrivenActivity<TActivity> : INotificationHandler<TelnyxWebhookReceived>
|
||||
{
|
||||
private readonly IWorkflowLaunchpad _workflowLaunchpad;
|
||||
protected ResumeWebhookDrivenActivity(IWorkflowLaunchpad workflowLaunchpad) => _workflowLaunchpad = workflowLaunchpad;
|
||||
protected virtual string ActivityTypeName => typeof(TActivity).Name;
|
||||
protected abstract IEnumerable<Type> GetSupportedPayloadTypes();
|
||||
|
||||
public async Task Handle(TelnyxWebhookReceived notification, CancellationToken cancellationToken)
|
||||
{
|
||||
if (notification.Webhook.Data.Payload is not TPayload payload)
|
||||
var supportedPayloadTypes = GetSupportedPayloadTypes().ToHashSet();
|
||||
var receivedPayload = (CallPayload) notification.Webhook.Data.Payload;
|
||||
var receivedPayloadType = receivedPayload.GetType();
|
||||
|
||||
if (!supportedPayloadTypes.Contains(receivedPayloadType))
|
||||
return;
|
||||
|
||||
var correlationId = GetCorrelationId(payload);
|
||||
|
||||
var correlationId = GetCorrelationId(receivedPayload);
|
||||
var trigger = CreateBookmark();
|
||||
var bookmark = CreateBookmark();
|
||||
var context = new CollectWorkflowsContext(ActivityTypeName, bookmark, trigger, correlationId);
|
||||
await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, payload, cancellationToken);
|
||||
await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, receivedPayload, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
protected virtual IBookmark CreateBookmark() => new GatherUsingSpeakBookmark();
|
||||
|
||||
private string GetCorrelationId(TPayload payload)
|
||||
|
||||
private string GetCorrelationId(CallPayload payload)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(payload.ClientState))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,9 +4,21 @@
|
|||
{
|
||||
public const string CallIsNoLongerActive = "Call Is No Longer Active";
|
||||
public const string Pending = "Pending";
|
||||
public const string Connected = "Connected";
|
||||
public const string NoResponse = "No Response";
|
||||
public const string Dialing = "Dialing";
|
||||
public const string CallInitiated = "CallInitiated";
|
||||
public const string Answered = "Answered";
|
||||
public const string Hangup = "Hangup";
|
||||
public const string GatheringInput = "Gathering Input";
|
||||
public const string GatherCompleted = "Gather Completed";
|
||||
public const string InputReceived = "Input Received";
|
||||
public const string Transferring = "Transferring";
|
||||
public const string Bridging = "Bridging";
|
||||
public const string Bridged = "Bridged";
|
||||
public const string LegABridged = "Call A Answered";
|
||||
public const string LegBBridged = "Call B Answered";
|
||||
public const string MachineDetectionEnded = "Machine Detection Ended";
|
||||
public const string MachineGreetingEnded = "Machine Greeting Ended";
|
||||
public const string FinishedSpeaking = "Finished Speaking";
|
||||
public const string Speaking = "Speaking";
|
||||
public const string Recording = "Recording";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using Elsa.Activities.Telnyx.Activities;
|
||||
using Elsa.Bookmarks;
|
||||
|
||||
namespace Elsa.Activities.Telnyx.Providers.Bookmarks
|
||||
{
|
||||
public class BridgeCallsBookmark : IBookmark
|
||||
{
|
||||
}
|
||||
|
||||
public class BridgeCallsBookmarkProvider : DefaultBookmarkProvider<BridgeCallsBookmark, BridgeCalls>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using Elsa.Activities.Telnyx.Activities;
|
||||
using Elsa.Bookmarks;
|
||||
|
||||
namespace Elsa.Activities.Telnyx.Providers.Bookmarks
|
||||
{
|
||||
public class DialBookmark : IBookmark
|
||||
{
|
||||
}
|
||||
|
||||
public class DialBookmarkProvider : DefaultBookmarkProvider<DialBookmark, Dial>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using Elsa.Activities.Telnyx.Activities;
|
||||
using Elsa.Bookmarks;
|
||||
|
||||
namespace Elsa.Activities.Telnyx.Providers.Bookmarks
|
||||
{
|
||||
public class TransferCallBookmark : IBookmark
|
||||
{
|
||||
}
|
||||
|
||||
public class TransferCallBookmarkProvider : DefaultBookmarkProvider<TransferCallBookmark, TransferCall>
|
||||
{
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue