Merge pull request #1037 from yileicn/master

optimize HooKEmitter
This commit is contained in:
Haiping 2025-05-06 21:49:01 -05:00 committed by GitHub
commit 16878b11e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 61 additions and 65 deletions

View file

@ -1,6 +1,11 @@
namespace BotSharp.Abstraction.Infrastructures;
public class HookEmitOption
public class HookEmitOption<T>
{
public bool OnlyOnce { get; set; }
/// <summary>
/// Optional predicate to determine if the hook action should be executed for a specific hook instance.
/// </summary>
public Func<T, bool>? ShouldExecute { get; set; }
}

View file

@ -4,7 +4,7 @@ namespace BotSharp.Core.Infrastructures;
public static class HookEmitter
{
public static HookEmittedResult Emit<T>(IServiceProvider services, Action<T> action, HookEmitOption? option = null)
public static HookEmittedResult Emit<T>(IServiceProvider services, Action<T> action, HookEmitOption<T>? option = null)
{
var logger = services.GetRequiredService<ILogger<T>>();
var result = new HookEmittedResult();
@ -15,12 +15,15 @@ public static class HookEmitter
{
try
{
logger.LogDebug($"Emit hook action on {action.Method.Name}({hook.GetType().Name})");
action(hook);
if (option.OnlyOnce)
if (option.ShouldExecute == null || option.ShouldExecute(hook))
{
break;
logger.LogDebug($"Emit hook action on {action.Method.Name}({hook.GetType().Name})");
action(hook);
if (option.OnlyOnce)
{
break;
}
}
}
catch (Exception ex)
@ -32,7 +35,7 @@ public static class HookEmitter
return result;
}
public static async Task<HookEmittedResult> Emit<T>(IServiceProvider services, Func<T, Task> action, HookEmitOption? option = null)
public static async Task<HookEmittedResult> Emit<T>(IServiceProvider services, Func<T, Task> action, HookEmitOption<T>? option = null)
{
var logger = services.GetRequiredService<ILogger<T>>();
var result = new HookEmittedResult();
@ -43,12 +46,15 @@ public static class HookEmitter
{
try
{
logger.LogDebug($"Emit hook action on {action.Method.Name}({hook.GetType().Name})");
await action(hook);
if (option.OnlyOnce)
if (option.ShouldExecute == null || option.ShouldExecute(hook))
{
break;
logger.LogDebug($"Emit hook action on {action.Method.Name}({hook.GetType().Name})");
await action(hook);
if (option.OnlyOnce)
{
break;
}
}
}
catch (Exception ex)

View file

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Twilio.Http;
using Task = System.Threading.Tasks.Task;
using BotSharp.Abstraction.Infrastructures;
namespace BotSharp.Plugin.Twilio.Controllers;
@ -341,62 +342,46 @@ public class TwilioVoiceController : TwilioController
public async Task<ActionResult> PhoneCallStatus(ConversationalVoiceRequest request)
{
var twilio = _services.GetRequiredService<TwilioService>();
if (request.CallStatus == "completed")
// Define the options with the predicate
var emitOptions = new HookEmitOption<ITwilioCallStatusHook>
{
if (twilio.MachineDetected(request))
{
// voicemail
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
async hook =>
{
if (hook.IsMatch(request)) await hook.OnVoicemailLeft(request);
});
}
else
{
// phone call completed
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
async hook =>
{
if (hook.IsMatch(request)) await hook.OnUserDisconnected(request);
});
}
}
else if (request.CallStatus == "busy")
ShouldExecute = hook => hook.IsMatch(request)
};
switch (request.CallStatus)
{
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
async hook =>
case "completed":
if (twilio.MachineDetected(request))
{
if (hook.IsMatch(request)) await hook.OnCallBusyStatus(request);
});
}
else if (request.CallStatus == "no-answer")
{
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
async hook =>
// voicemail
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnVoicemailLeft(request), emitOptions);
}
else
{
if (hook.IsMatch(request)) await hook.OnCallNoAnswerStatus(request);
});
}
else if (request.CallStatus == "canceled")
{
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
async hook =>
{
if (hook.IsMatch(request)) await hook.OnCallCanceledStatus(request);
});
}
else if (request.CallStatus == "failed")
{
await HookEmitter.Emit<ITwilioCallStatusHook>(_services,
async hook =>
{
if (hook.IsMatch(request)) await hook.OnCallFailedStatus(request);
});
}
else
{
_logger.LogError($"Unknown call status: {request.CallStatus}, {request.CallSid}");
// phone call completed
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnUserDisconnected(request), emitOptions);
}
break;
case "busy":
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallBusyStatus(request), emitOptions);
break;
case "no-answer":
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallNoAnswerStatus(request), emitOptions);
break;
case "canceled":
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallCanceledStatus(request), emitOptions);
break;
case "failed":
await HookEmitter.Emit<ITwilioCallStatusHook>(_services, hook => hook.OnCallFailedStatus(request), emitOptions);
break;
default:
_logger.LogError($"Unknown call status: {request.CallStatus}, {request.CallSid}");
break;
}
return Ok();