Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/keri/app/delegating.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def handle(self, serder, attachments=None):
if "aids" in pay:
data["aids"] = pay["aids"]

self.notifier.add(attrs=data)
self.notifier.add(attrs=data, rid=serder.said)


def delegateRequestExn(hab, delpre, evt, aids=None):
Expand Down
4 changes: 2 additions & 2 deletions src/keri/app/grouping.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ def add(self, serder):
d=serder.said
)

self.notifier.add(attrs=data)
self.notifier.add(attrs=data, rid=serder.said)

self.hby.db.meids.add(keys=(esaid,), val=coring.Saider(qb64=serder.said))
self.hby.db.maids.add(keys=(esaid,), val=coring.Prefixer(qb64=serder.pre))
Expand Down Expand Up @@ -674,7 +674,7 @@ def add(self, serder):
e=embed['d']
)

self.notifier.add(attrs=data)
self.notifier.add(attrs=data, rid=serder.said)

def get(self, esaid):
saiders = self.hby.db.meids.get(keys=(esaid,))
Expand Down
21 changes: 12 additions & 9 deletions src/keri/app/notifying.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
from keri.db import dbing, subing


def notice(attrs, dt=None, read=False):
def notice(attrs, dt=None, read=False, rid=None):
"""

Parameters:
attrs (dict): payload of the notice
dt(Optional(str, datetime)): iso8601 formatted datetime of notice
read (bool): message read indicator
rid (str): qb64 ID of the notice. Defaults to a random nonce. Pass the SAID of the
exn that caused the notice so that a re-delivery of that exn dedups in Noter.add

Returns:
Notice: Notice instance
Expand All @@ -30,7 +32,7 @@ def notice(attrs, dt=None, read=False):
if hasattr(dt, "isoformat"):
dt = dt.isoformat()

pad = dict(i="",
pad = dict(i=rid if rid is not None else "",
dt=dt,
r=read,
a=attrs
Expand Down Expand Up @@ -278,7 +280,7 @@ def get(self, rid):
Adds note to database, keyed by the datetime and said of the note.

Parameters:
rid (str): qb64 random ID of note to get
rid (str): qb64 ID of note to get

Returns:
(Notice, Cigar) = couple of notice object and accompanying signature
Expand All @@ -298,7 +300,7 @@ def rem(self, rid):
Remove note from database if it exists

Parameters:
rid (str): qb64 random ID of note to remove
rid (str): qb64 ID of note to remove

Returns:
bool: True if deleted
Expand Down Expand Up @@ -375,18 +377,19 @@ def __init__(self, hby, signaler=None, noter=None):
self.signaler = signaler if signaler is not None else signaling.Signaler()
self.noter = noter if noter is not None else Noter(name=hby.name, temp=hby.temp)

def add(self, attrs):
def add(self, attrs, rid=None):
""" Add unread notice to the end of the current list of notices

Args:
attrs (dict): body of a new unread notice to append to the current list of notices
rid (str): qb64 ID of the notice, defaults to a random nonce

Returns:
bool: returns True if the notice was added

"""

note = notice(attrs, dt=helping.nowIso8601())
note = notice(attrs, dt=helping.nowIso8601(), rid=rid)
cig = self.hby.signator.sign(ser=note.raw)
if self.noter.add(note, cig):
signal = dict(
Expand All @@ -402,10 +405,10 @@ def add(self, attrs):
def rem(self, rid):
""" Mark as Read

Delete the note identified by the provided random ID
Delete the note identified by the provided ID

Parameters:
rid (str): qb64 random ID of the Note to delete
rid (str): qb64 ID of the Note to delete

Returns:
bool: True means the note was deleted, False otherwise
Expand Down Expand Up @@ -434,7 +437,7 @@ def mar(self, rid):
Mark the note identified by the provided SAID as having been read by the controller of the agent

Parameters:
rid (str): qb64 random ID of the Note to mark as read
rid (str): qb64 ID of the Note to mark as read

Returns:
bool: True means the note was marked as read, False otherwise
Expand Down
2 changes: 1 addition & 1 deletion src/keri/app/oobiing.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def handle(self, serder, attachments=None):
if "name" in params:
data["oobialias"] = params["name"][0]

self.notifier.add(attrs=data)
self.notifier.add(attrs=data, rid=serder.said)


def oobiRequestExn(hab, dest, oobi):
Expand Down
2 changes: 1 addition & 1 deletion src/keri/vc/protocoling.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def handle(self, serder, attachments=None):
m=attrs["m"]
)

self.notifier.add(attrs=data)
self.notifier.add(attrs=data, rid=serder.said)


def ipexApplyExn(hab, recp, message, schema, attrs):
Expand Down
1 change: 1 addition & 0 deletions tests/app/test_delegating.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,4 @@ def test_delegation_request_handler(mockHelpingNowUTC):
handler.handle(serder=exn)

assert len(notifier.getNotes()) == 1
assert notifier.getNotes()[0].rid == exn.said
1 change: 1 addition & 0 deletions tests/app/test_grouping.py
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ def test_multisig_rotate_handler(mockHelpingNowUTC):

# One notification
assert len(notifier.signaler.signals) == 1
assert notifier.getNotes()[0].rid == exn.said

esaid = exn.ked['e']['d']
saiders = hby1.db.meids.get(keys=(esaid, ))
Expand Down
59 changes: 59 additions & 0 deletions tests/app/test_notifying.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pytest

from keri.app import notifying, habbing
from keri.vc import protocoling
from keri.core import coring
from keri.db import dbing
from keri.help import helping
Expand Down Expand Up @@ -221,3 +222,61 @@ def test_notifier(mockHelpingNowUTC):

assert notifier.mar(note.rid) is False
assert notifier.rem(note.rid) is True


def test_notice_rid():
payload = dict(name="John", msg="test")
said = "EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao"

note = notifying.notice(attrs=payload, rid=said)
assert note.rid == said
assert note.pad['i'] == said

# a second notice for the same exn keeps the id even though the datetime moves
other = notifying.notice(attrs=payload, rid=said, dt="2022-07-08T15:01:05.453632")
assert other.rid == said
assert other.datetime != note.datetime

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this impact notifications received on Signify side, or this is an internal test? (i.e. .add de-dups stopping this)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this impact notifications received on Signify side

Yes, but only in the data - no client change needed:

  • the notification id is the exn SAID instead of a random nonce;
  • a re-delivered exn no longer adds a second notification;
  • the stored notification keeps the first delivery's datetime, since the later one is refused.

this is an internal test? (i.e. .add de-dups stopping this)

Yes, internal - nothing is added there. .add de-dups; verified on KERIA, same exn twice gives one notification.


# unchanged default: no rid means a random nonce, so two notices differ
assert notifying.notice(attrs=payload).rid != notifying.notice(attrs=payload).rid


def test_notifier_dedups_on_rid():
with habbing.openHby(name="test") as hby:
notifier = notifying.Notifier(hby=hby)
said = "EBfdlu8R27Fbx-ehrqwImnK-8Cm79sqbAQ4MmvEAYqao"

assert notifier.add(attrs=dict(r="/exn/ipex/grant", d=said), rid=said) is True
assert notifier.add(attrs=dict(r="/exn/ipex/grant", d=said), rid=said) is False

notes = notifier.getNotes()
assert len(notes) == 1
assert notes[0].rid == said

# a deleted notice may legitimately come back on a later re-delivery
assert notifier.rem(said) is True
assert notifier.add(attrs=dict(r="/exn/ipex/grant", d=said), rid=said) is True
assert len(notifier.getNotes()) == 1

# a read notice still dedups
assert notifier.mar(said) is True
assert notifier.add(attrs=dict(r="/exn/ipex/grant", d=said), rid=said) is False
assert len(notifier.getNotes()) == 1


def test_ipex_handler_redelivery_notifies_once():
with habbing.openHab(name="sid", temp=True, salt=b'0123456789abcdef') as (hby, hab):
notifier = notifying.Notifier(hby=hby)
ipexhan = protocoling.IpexHandler(resource="/ipex/apply", hby=hby, notifier=notifier)

apply0, _ = protocoling.ipexApplyExn(hab, message="Please give me a credential",
schema="EMQWEcCnVRk1hatTNyK3sIykYSrrFvafX3bHQ9Gkk1kC",
recp=hab.pre, attrs={})

ipexhan.handle(serder=apply0)
ipexhan.handle(serder=apply0)

notes = notifier.getNotes()
assert len(notes) == 1
assert notes[0].rid == apply0.said
assert notes[0].attrs['d'] == apply0.said
1 change: 1 addition & 0 deletions tests/app/test_oobiing.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def test_oobi_share(mockHelpingNowUTC):
signal = notifier.signaler.signals.popleft()
assert signal.pad['r'] == '/notification'
rid = signal.attrs['note']['i']
assert rid == exn.said

note, _ = notifier.noter.get(rid)
assert note.attrs == {'oobi': 'http://127.0.0.1:5642/oobi/Egw3N07Ajdkjvv4LB2Mhx2qxl6TOCFdWNJU6cYR_ImFg/witness/'
Expand Down
Loading