In this article, I will discuss how to show real-time cricket score notification from chrome extension using serverless Azure Functions and Azure SignalR.
I have used cricapi.com free API service to get the live cricket score updates. The purpose of this article is to show the power of serverless architecture using azure functions and broadcasting to connected clients in real-time using Azure SignalR. The demo source code I attached to this article is for the personal educational purpose only and not production use.
Steps
Register Cricket Services API
As a first step, to consume the API Service from cricapi.com, register the account with the details to get the API Key. They allow 100 free hits per day for the testing purpose.
Creating Azure SignalR Service
Log into your Azure Portal (https://portal.azure.com/) and create a new resource of type SignalR Service. After the service is created, copy the connection string from the Keys section.
Creating Azure Function App
- Visual Studio 2017 Latest Version
- Azure Portal Account
Select the Azure Function v2 Preview and the Http trigger template.
- NegotiateFunction (HttpTrigger)
- This function will get the JWT token for the client so that SignalR client can connect to Azure Signalr Service Hub.
- BroadcastFunction (TimerTrigger)
- This function runs every 1 min (configurable) and calls the CricAPI Service to get the latest score for defined match id and broadcast it to all connected clients.
NegotiateFuntion.cs
public static class NegotiateFunction { [FunctionName("negotiate")] public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequest req, [SignalRConnectionInfo(HubName = "broadcasthub")]SignalRConnectionInfo info, ILogger log) { return info != null ? (ActionResult)new OkObjectResult(info) : new NotFoundObjectResult("Failed to load SignalR Info."); } }
BroadCastFunction.cs
public static class BroadcastFunction { private static HttpClient httpClient = new HttpClient(); [FunctionName("broadcast")] public static async void Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, [SignalR(HubName = "broadcasthub")]IAsyncCollector<signalrmessage> signalRMessages, ILogger log) { httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); //TODO: API key should be stored in Azure Key Vault . //For Demo purpose, i hard coded the value here. var values = new Dictionary<string string=""> { //Hard coded Cricket Match Unique ID. You can change the Match id based on ongoing matchers {"apikey", "_API_KEY_HERE"},{"unique_id", "1119553"} }; using (var response = httpClient.PostAsJsonAsync(new Uri("http://cricapi.com/api/cricketScore/"), values).Result) { var resultObj = response.Content.ReadAsStringAsync().Result; dynamic result = JsonConvert.DeserializeObject(resultObj); await signalRMessages.AddAsync(new SignalRMessage() { Target = "broadcastData", Arguments = new object[] { result.score } }); } } } </string></signalrmessage>
local.settings.json
{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "AzureWebJobsDashboard": "UseDevelopmentStorage=true", "FUNCTIONS_WORKER_RUNTIME": "dotnet", "AzureSignalRConnectionString": "Endpoint=https://magicpaste.service.signalr.net;AccessKey=" }, "Host": { "LocalHttpPort": 7071, "CORS": "*" } }
We are now done with the coding for the Azure functions, we can start testing it locally first before deploying into Azure Portal. In the local.settings.json, we have defined the localhttpport 7071 and allowed cross domains request by putting CORS : *
Run the Application by pressing F5 which will create the host and deploy the functions in localhost.
Publishing Azure Function App
Creating Chrome Extension
const apiBaseUrl = '<a href="https://azurefunctionscricketscore20180911095957.azurewebsites.net/">https://azurefunctionscricketscore20180911095957.azurewebsites.net</a>'; const hubName = 'broadcasthub'; getConnectionInfo().then(info => { const options = { accessTokenFactory: () => info.accessKey }; const connection = new signalR.HubConnectionBuilder() .withUrl(info.endpoint, options) .configureLogging(signalR.LogLevel.Information) .build(); connection.on('broadcastData', (message) => { new Notification(message, { icon: '48.png', body: message }); }); connection.onclose(() => console.log('disconnected')); console.log('connecting...'); connection.start() .then(() => console.log('connected!')) .catch(console.error); }).catch(alert); function getConnectionInfo() { return axios.post(`${apiBaseUrl}/api/negotiate`) .then(resp => resp.data); }
In the manifest.json, we defined the list of scripts to load (axios, signalr and signalrclient).
{ "name": "Real Time Cricket Score Demo", "version": "1.0", "description": "Real time Cricket Score Update from Serverless Azure Functions pop up on the desktop.", "icons": {"16": "16.png", "48": "48.png", "128": "128.png"}, "permissions": [ "background", "tabs", "notifications", "<a href="http://">http://</a>*/*", "<a href="https://">https://</a>*/*" ], "background": { "persistent": true, "scripts": ["axios.min.js","signalr.js","signalrclient.js"] }, "manifest_version": 2, "web_accessible_resources": [ "48.png" ] }
Conclusion
With the few lines of code, we have created the serverless azure functions, which will fetch the data from the API endpoint and broadcast the messages to all connected clients in real time using Azure SignalR. In this article, I have hardcoded the API key in the program but ideally, it should be stored in Azure Key Vault and read it from there. I hope this article helps you get started with Azure Functions. I have uploaded the entire source code in my github repository.
Happy Coding!
2 thoughts on “Real-Time Cricket Score Chrome Extension using Azure Functions and SignalR”