hyperledger-archives / aries-framework-dotnet

Aries Framework .NET for building multiplatform SSI services
https://wiki.hyperledger.org/display/aries
Apache License 2.0
84 stars 74 forks source link

Mediator agent InboxItemEvent #181

Open juvebogdan opened 3 years ago

juvebogdan commented 3 years ago

Hello,

Can someone please give some guidance on how to use InboxItemEvent to implement push notifications. Is InboxId field that identifies Edge agent? At what point i cn hook into and tie this filed to notification token?

Thank you

sahil-khanna commented 3 years ago

@juvebogdan,

You can search for the Push Token from walletRecordService.SearchAsync<DeviceInfoRecord>. Use the search query for inboxItemEvent.InboxId. This will list the DeviceInfoRecords from where you can get the DeviceId

mat-work commented 3 years ago

One more possible issue. Push tokens can change over time for different reasons (app upgrade, etc..).

It seems that RoutingInboxHandler returns a WalletItemAlreadyExistsException when invoking AddDeviceInfoAsync

https://github.com/hyperledger/aries-framework-dotnet/blob/ee0ec833ff80f166fd1250dcd49f1e223ef964c0/src/Hyperledger.Aries.Routing.Mediator/Handlers/RoutingInboxHandler.cs#L83

Could anybody confirm this is the case? Maybe it should update the record instead?

TIA

sahil-khanna commented 3 years ago

One more possible issue. Push tokens can change over time for different reasons (app upgrade, etc..).

It seems that RoutingInboxHandler returns a WalletItemAlreadyExistsException when invoking AddDeviceInfoAsync

https://github.com/hyperledger/aries-framework-dotnet/blob/ee0ec833ff80f166fd1250dcd49f1e223ef964c0/src/Hyperledger.Aries.Routing.Mediator/Handlers/RoutingInboxHandler.cs#L83

Could anybody confirm this is the case? Maybe it should update the record instead?

TIA

@mat-work, from what I have been doing so far is as described below. It works without any issue.

await edgeClientService.AddDeviceAsync(agentContext, deviceInfoMessage);


- On the Mediator Agent, get the most recent `DeviceInfoRecord` (sort by CreatedAtUtc.Value) and use that to send the Push Notification
Drilmo commented 3 years ago

Hello @sahil-khanna

I'm sorry but I'm lost in the implementation of push notifications.

Do you have a concrete example of use? a tutorial?

Indeed I do not know where to place the portion of code that you have indicated above in the mediator.

(I use the mediator contained in the repository: https://github.com/hyperledger/aries-mobile-agent-xamarin)

Thanks in advance for your answer

sahil-khanna commented 3 years ago

@Drilmo ,

You can try the below code. Replace it with this line

IHost Container = CreateHostBuilder(args).Build();

var eventAggregator = (IEventAggregator)Program.Container.Services.GetService(typeof(IEventAggregator));
_ = eventAggregator.GetEventByType<InboxItemEvent>().Subscribe(inboxItemEvent =>
{
   // Get the device token
   await walletRecordService.SearchAsync<DeviceInfoRecord>(
                wallet: agentContext.Wallet,
                query: SearchQuery.Equal(nameof(DeviceInfoRecord.InboxId), inboxItemEvent.InboxId.ToString()),
                count: int.MaxValue);
   Console.WriteLine(deviceInfoRecords.First().DeviceId);

   // Send Push Notification. The DeviceId is the token of the device
});

Container.Run();
Drilmo commented 3 years ago

@Drilmo ,

You can try the below code. Place it just below this line

eventAggregator = (IEventAggregator)Program.Container.Services.GetService(typeof(IEventAggregator));

_ = eventAggregator.GetEventByType<InboxItemEvent>().Subscribe(inboxItemEvent =>
{
   // Get the device token
   await walletRecordService.SearchAsync<DeviceInfoRecord>(
                wallet: agentContext.Wallet,
                query: SearchQuery.Equal(nameof(DeviceInfoRecord.InboxId), inboxItemEvent.InboxId.ToString()),
                count: int.MaxValue);
   Console.WriteLine(deviceInfoRecords.First().DeviceId);

   // Send Push Notification. The DeviceId is the token of the device
});

@sahil-khanna, thank you very much for your answer!

Is it possible to set up 1 notification per type of event? if yes how to manage them?

I'm sorry for these questions but I'm completely lost with this mediator.

Thank you for your help.

sahil-khanna commented 3 years ago

@Drilmo , You can try the below code. Place it just below this line

eventAggregator = (IEventAggregator)Program.Container.Services.GetService(typeof(IEventAggregator));

_ = eventAggregator.GetEventByType<InboxItemEvent>().Subscribe(inboxItemEvent =>
{
   // Get the device token
   await walletRecordService.SearchAsync<DeviceInfoRecord>(
                wallet: agentContext.Wallet,
                query: SearchQuery.Equal(nameof(DeviceInfoRecord.InboxId), inboxItemEvent.InboxId.ToString()),
                count: int.MaxValue);
   Console.WriteLine(deviceInfoRecords.First().DeviceId);

   // Send Push Notification. The DeviceId is the token of the device
});

@sahil-khanna, thank you very much for your answer!

Is it possible to set up 1 notification per type of event? if yes how to manage them?

I'm sorry for these questions but I'm completely lost with this mediator.

Thank you for your help.

@Drilmo, I doubt this can be done. The Mediator Agent cannot read the contents of the payload as the payload is encrypted. All it knows is the source and the recipient of the payload. Hence, you can send a common message for all the events the Mediator Agent receives.

Drilmo commented 3 years ago

This code works in mediator :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Hyperledger.Aries.Contracts;
using Hyperledger.Aries.Routing;
using Hyperledger.Aries.Storage;
using Hyperledger.Aries.Agents;
using System.Net.Http;
namespace mediator 
{
    public class Program 
    {
        private static HttpClient client = new HttpClient();
        public static async Task Main(string[] args)
        {
            IHost Container = CreateHostBuilder(args).Build();
            var eventAggregator = (IEventAggregator)Container.Services.GetService(typeof(IEventAggregator));
            _ = eventAggregator.GetEventByType<InboxItemEvent>().Subscribe(async inboxItemEvent => 
            {
                // Get the device token
                var walletRecordService = (IWalletRecordService)Container.Services.GetService(typeof(IWalletRecordService));
                var agentProvider = (IAgentProvider)Container.Services.GetService(typeof(IAgentProvider));
                var agentContext = await agentProvider.GetContextAsync();
                List<DeviceInfoRecord> deviceInfoRecords = await walletRecordService.SearchAsync<DeviceInfoRecord>(
                                wallet: agentContext.Wallet,
                                query: SearchQuery.Equal(nameof(DeviceInfoRecord.InboxId), inboxItemEvent.InboxId.ToString()),
                                count: int.MaxValue);
                if (deviceInfoRecords.Any()){
                    Console.WriteLine("Push Token : " + deviceInfoRecords.First().DeviceId);
                    Console.WriteLine("Mobile Platform : " + deviceInfoRecords.First().DeviceVendor);
                    // Send Push Notification.                 
                }
            });
            Container.Run();
        }
    }
}
naman20sharma commented 2 years ago
  • You need to AddDeviceInfoMessage from the Edge Agent whenever the Push Notification Token is updated. This will add a new entry in the Mediator Agent for the connection
AddDeviceInfoMessage deviceInfoMessage = new()
{
    DeviceId = token,
    DeviceVendor = DeviceInfo.Platform.ToString()
};

await edgeClientService.AddDeviceAsync(agentContext, deviceInfoMessage);
  • On the Mediator Agent, get the most recent DeviceInfoRecord (sort by CreatedAtUtc.Value) and use that to send the Push Notification

Hi @sahil-khanna ,

Can you please guide me with this, I have some doubts:

  1. Where should we add these line of code in the Mobile wallet code ?

  2. Can we implement 3rd party Push notification service like Google Firebase here ?

  3. Do we still require to call FetchInboxAsync in Mobile code to process the messages from Mediator, if Push notification is successfully implemented ?

sahil-khanna commented 2 years ago

@naman20sharma, below are my responses to your questions.

  1. Where should we add these line of code in the Mobile wallet code ? A: You need to add the code at the Token Refresh event of the Push Notification. Refer to the example below.
  CrossPushNotification.Current.OnTokenRefresh += (s,p) =>
  {
        AddDeviceInfoMessage deviceInfoMessage = new()
        {
            DeviceId = p.Token,
            DeviceVendor = DeviceInfo.Platform.ToString()
        };

        await edgeClientService.AddDeviceAsync(agentContext, deviceInfoMessage);
  };
  1. Can we implement 3rd party Push notification service like Google Firebase here ? A. Yes. You may check out the Push Notification Plugin for Xamarin forms. It supports Firebase Cloud Messaging

  2. Do we still require to call FetchInboxAsync in Mobile code to process the messages from Mediator, if Push notification is successfully implemented ? A. Probably yes. Below are a few reasons.

    • Push Notifications are not reliable, i.e., they may fail
    • The user may turn off Push Notifications from the device settings (or by turning on Battery Saver)