305 lines
12 KiB
C#
305 lines
12 KiB
C#
using Eqn.Sender.Services;
|
|
using FirebaseAdmin;
|
|
using FirebaseAdmin.Messaging;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
|
|
namespace Eqn.Sender.Controllers
|
|
{
|
|
[Route("api/[controller]")]
|
|
[ApiController]
|
|
public class fbmsController : ControllerBase
|
|
{
|
|
#region Public Constructors
|
|
|
|
public fbmsController(ILogger<fbmsController> logger, FireBaseService sharedService)
|
|
{
|
|
_logger = logger;
|
|
fbService = sharedService;
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Methods
|
|
|
|
[HttpGet("GetInfo")]
|
|
public async Task<string> GetInfo()
|
|
{
|
|
var currProg = typeof(Program).Assembly.GetName();
|
|
string answ = $"{currProg.Name} | v.{currProg.Version ?? new Version("0.0.0")}";
|
|
//_logger.LogInformation(answ);
|
|
await Task.Delay(1);
|
|
// restituisco esito...
|
|
return answ;
|
|
}
|
|
|
|
#if false
|
|
[HttpGet("SearchNum/{id}")]
|
|
public async Task<FirebaseAdmin.Auth.UserRecord> SearchNum(string id)
|
|
{
|
|
FirebaseAdmin.Auth.UserRecord answ = await fbService.GetUserByNumber(id);
|
|
await Task.Delay(1);
|
|
// restituisco esito...
|
|
return answ;
|
|
}
|
|
|
|
[HttpGet("SearchEmail/{id}")]
|
|
public async Task<FirebaseAdmin.Auth.UserRecord> SearchEmail(string id)
|
|
{
|
|
FirebaseAdmin.Auth.UserRecord answ = await fbService.GetUserByEmail(id);
|
|
await Task.Delay(1);
|
|
// restituisco esito...
|
|
return answ;
|
|
}
|
|
#endif
|
|
|
|
[HttpPost("sendAndroid")]
|
|
public async Task<string> SendAndroid([FromBody] MsgPayload rawData, bool fullReturn = false, int maxToken = 499, int numParall = 4, bool dryRun = false)
|
|
{
|
|
string answ = await DoSend(rawData, fullReturn, true, maxToken, numParall, dryRun);
|
|
// restituisco esito...
|
|
return answ;
|
|
}
|
|
|
|
[HttpPost("sendIOS")]
|
|
public async Task<string> SendIOS([FromBody] MsgPayload rawData, bool fullReturn = false, int maxToken = 499, int numParall = 4, bool dryRun = false)
|
|
{
|
|
string answ = await DoSend(rawData, fullReturn, false, maxToken, numParall, dryRun);
|
|
// restituisco esito...
|
|
return answ;
|
|
}
|
|
|
|
[HttpPost("test")]
|
|
public async Task<string> Test(int numTest = 10, int numParall = 1, bool dryRun = true)
|
|
{
|
|
string answ = "";
|
|
StringBuilder sb = new StringBuilder();
|
|
List<string> tokenList = new List<string>();
|
|
int numOk = 0;
|
|
int numErr = 0;
|
|
// preparare vera lista invio (multi messaggio)
|
|
List<MulticastMessage> messageList = new List<MulticastMessage>();
|
|
MulticastMessage newMessage = new MulticastMessage();
|
|
tokenList.Add("dzsSHj7kT9yRNFbLUEiLyE:APA91bHLBeSoff8okQG-Z6ZVc2e8xan72z2xOietApLfc7X7XDxhWKAb032miZ5sRGmmSy1QU8MsYzFasEebW_k05piXxDLqfBzpy0vvkr8KY_1Y_BeNB4H0JxIWOxbZHcsEzuK_zVoC");
|
|
tokenList.Add("f4-u_BKiTUalvB6Ly2PXvK:APA91bEqp0Hmlfu6D6AazXOLHaEZJBpbDlc8Ss6nBO_PgkxNZ6u0jt9kra6bb7lOVaS2YA_JRYIx-7hWznH_8xfOVLW2jz5a4g8Bh-whPlc3uSFUpW1jYkUYNqr186Ylybw4nIh1kqth");
|
|
for (int i = 0; i < numTest; i++)
|
|
{
|
|
newMessage = new MulticastMessage()
|
|
{
|
|
Notification = new Notification()
|
|
{
|
|
Title = "Prova Notifica Firebase",
|
|
Body = $"Notifica {i} | dotNet core | {DateTime.Now:yyyy.MM.dd HH:mm:ss}"
|
|
}
|
|
,
|
|
Tokens = tokenList
|
|
//,Data =
|
|
};
|
|
messageList.Add(newMessage);
|
|
}
|
|
List<BatchResponse> listBResp = new List<BatchResponse>();
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
if (numParall > 1)
|
|
{
|
|
var options = new ParallelOptions { MaxDegreeOfParallelism = numParall };
|
|
await Parallel.ForEachAsync(messageList, async (message, token) =>
|
|
{
|
|
var resp = await fbService.DoSendMessage(message, dryRun);
|
|
listBResp.Add(resp);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
foreach (var item in messageList)
|
|
{
|
|
var resp = await fbService.DoSendMessage(item, dryRun);
|
|
listBResp.Add(resp);
|
|
}
|
|
}
|
|
sw.Stop();
|
|
// compongo risultato:
|
|
sb.AppendLine($"Effettuate {numTest} chiamate in {sw.Elapsed.TotalSeconds:N3} msec");
|
|
numOk = listBResp.Sum(x => x.SuccessCount);
|
|
numErr = listBResp.Sum(x => x.FailureCount);
|
|
sb.AppendLine($"# Successi: {numOk} | # Errori: {numErr}");
|
|
answ = sb.ToString();
|
|
|
|
// restituisco esito...
|
|
return answ;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Private Fields
|
|
|
|
private readonly ILogger<fbmsController> _logger;
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Properties
|
|
|
|
private FireBaseService fbService { get; set; } = null!;
|
|
|
|
#endregion Private Properties
|
|
|
|
#region Private Methods
|
|
|
|
/// <summary>
|
|
/// Funzione effettiva di invio messaggi spacchettati
|
|
/// </summary>
|
|
/// <param name="rawData">Dati payload</param>
|
|
/// <param name="fullReturn">Indica se ritornare per intero il messaggio firebase</param>
|
|
/// <param name="isAndroid">Booleano: true = Android / false=iOS</param>
|
|
/// <param name="maxToken">Num max di token x singolo invio FireBase</param>
|
|
/// <param name="numParall">Parallelismo send ammesso</param>
|
|
/// <param name="dryRun">Se true fa solo SIMULAZIONE invio</param>
|
|
/// <returns></returns>
|
|
private async Task<string> DoSend(MsgPayload rawData, bool fullReturn, bool isAndroid, int maxToken, int numParall, bool dryRun)
|
|
{
|
|
string answ = "";
|
|
//limito a 499 se anche me ne richiedesse di +...
|
|
maxToken = maxToken <= 499 ? maxToken : 499;
|
|
Stopwatch sw = new Stopwatch();
|
|
sw.Start();
|
|
StringBuilder sb = new StringBuilder();
|
|
int numOk = 0;
|
|
int numErr = 0;
|
|
int numResp = 0;
|
|
// preparo statistiche invio
|
|
ConcurrentBag<double> elapsedList = new ConcurrentBag<double>();
|
|
// preparare vera lista invio (multi messaggio)
|
|
List<MulticastMessage> messageList = new List<MulticastMessage>();
|
|
MulticastMessage newMessage = new MulticastMessage();
|
|
// calcolo num invii
|
|
int numToken = rawData.tokenList.Count;
|
|
int numCall = (int)Math.Ceiling(((double)numToken / maxToken));
|
|
|
|
// costruisco messaggi con maxToken ognuno
|
|
for (int i = 0; i < numCall; i++)
|
|
{
|
|
// num mess da inviare...
|
|
int num2send = numToken - (i * maxToken) > maxToken ? maxToken : numToken - (i * maxToken);
|
|
if (isAndroid)
|
|
{
|
|
newMessage = new MulticastMessage()
|
|
{
|
|
Android = new AndroidConfig()
|
|
{
|
|
Priority = rawData.highPriority ? Priority.High : Priority.Normal,
|
|
TimeToLive = TimeSpan.FromSeconds(rawData.secTTL)
|
|
},
|
|
Tokens = rawData.tokenList.Skip(i * maxToken).Take(num2send).ToList(),
|
|
Data = rawData.varData
|
|
};
|
|
}
|
|
else
|
|
{
|
|
Dictionary<string, string> apnsHead = new Dictionary<string, string>();
|
|
apnsHead.Add("apns-priority", rawData.highPriority ? "10" : "5");
|
|
// expiration come epoch unix:
|
|
Int32 unixEpoch = (int)DateTime.UtcNow.AddSeconds(rawData.secTTL).Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
|
apnsHead.Add("apns-expiration", $"{unixEpoch}");
|
|
newMessage = new MulticastMessage()
|
|
{
|
|
Apns = new ApnsConfig()
|
|
{
|
|
Headers = apnsHead,
|
|
Aps = new Aps()
|
|
{
|
|
MutableContent = true,
|
|
ContentAvailable = true,
|
|
Sound = rawData.notifySound,
|
|
Alert = new ApsAlert()
|
|
{
|
|
ActionLocKey = rawData.iOSAction,
|
|
TitleLocKey = rawData.title,
|
|
LocKey = rawData.body,
|
|
LocArgs = new List<string> { rawData.iOSLockArg }
|
|
}
|
|
},
|
|
},
|
|
Notification = new Notification()
|
|
{
|
|
Title = rawData.title,
|
|
Body = rawData.body
|
|
},
|
|
Tokens = rawData.tokenList.Skip(i * maxToken).Take(num2send).ToList(),
|
|
Data = rawData.varData
|
|
};
|
|
}
|
|
messageList.Add(newMessage);
|
|
}
|
|
List<BatchResponse> listBResp = new List<BatchResponse>();
|
|
if (numParall > 1)
|
|
{
|
|
var options = new ParallelOptions { MaxDegreeOfParallelism = numParall };
|
|
await Parallel.ForEachAsync(messageList, async (message, token) =>
|
|
{
|
|
Stopwatch lsw = new Stopwatch();
|
|
lsw.Start();
|
|
var resp = await fbService.DoSendMessage(message, dryRun);
|
|
listBResp.Add(resp);
|
|
lsw.Stop();
|
|
elapsedList.Add(lsw.Elapsed.TotalSeconds);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
foreach (var item in messageList)
|
|
{
|
|
Stopwatch lsw = new Stopwatch();
|
|
lsw.Start();
|
|
var resp = await fbService.DoSendMessage(item, dryRun);
|
|
listBResp.Add(resp);
|
|
lsw.Stop();
|
|
elapsedList.Add(lsw.Elapsed.TotalSeconds);
|
|
}
|
|
}
|
|
sw.Stop();
|
|
// compongo risultato: se riechiesto serializzo risposte firebase...
|
|
if (fullReturn)
|
|
{
|
|
answ = JsonConvert.SerializeObject(listBResp, Formatting.Indented);
|
|
}
|
|
else
|
|
{
|
|
// altrimenti solo risultato x conteggio
|
|
numOk = listBResp.Sum(x => x.SuccessCount);
|
|
numErr = listBResp.Sum(x => x.FailureCount);
|
|
numResp = listBResp.Sum(x => x.Responses.Count);
|
|
sb.AppendLine($"Effettuate {numCall} chiamate in {sw.Elapsed.TotalSeconds:N3} sec");
|
|
sb.AppendLine($"Token IN: {rawData.tokenList.Count} | # Risposte {numResp} | # Successi: {numOk} | # Errori: {numErr}");
|
|
answ = sb.ToString();
|
|
}
|
|
// se durata > 5sec --> loggo!
|
|
if (sw.Elapsed.TotalSeconds > 5)
|
|
{
|
|
int numSend = elapsedList.Count;
|
|
string logVal = $"Warnng soglia, durata: {sw.Elapsed.TotalSeconds:N3} sec | chiamate: {numCall} | batch: {numSend}";
|
|
_logger.LogWarning(logVal);
|
|
// scrivo tutte le righe
|
|
int idx = 0;
|
|
foreach (var item in elapsedList)
|
|
{
|
|
_logger.LogWarning($"{idx:00}| {item:N3} sec");
|
|
}
|
|
|
|
//// calcolo numero esecuzioni
|
|
//double minTime = elapsedList.OrderBy(x => x).FirstOrDefault();
|
|
//double avgTime = numSend > 0 ? elapsedList.Sum(x => x) / numSend : 0;
|
|
//double maxTime = elapsedList.OrderByDescending(x => x).FirstOrDefault();
|
|
//string stats = $"Batch processati: {numSend} | minTime: {minTime:N3} | avgTime: {avgTime:N3} | maxTime: {maxTime:N3}";
|
|
//_logger.LogWarning(stats);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |