Skip to content
This repository has been archived by the owner on Aug 14, 2019. It is now read-only.

Tiebout - Apple Push Notification Server App #1084

Merged
merged 4 commits into from
Mar 1, 2019
Merged
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
269 changes: 269 additions & 0 deletions app/tiebout.hoon
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
/- hall, tiebout
=, tiebout
tacryt-socryp marked this conversation as resolved.
Show resolved Hide resolved
=, eyre
|%
+$ move [bone card]
::
+$ card
$% [%poke wire dock poke]
[%peer wire dock path]
[%pull wire dock ~]
[%diff diff]
[%hiss wire [~ ~] %httr %hiss hiss]
==
::
+$ diff
$% [%hall-rumor rumor:hall]
[%tiebout-action action]
==
::
+$ poke
$% [%tiebout-action action]
==
::
+$ state
$% [%0 tiebout-zero]
==
::
+$ tiebout-zero
$:
:: iOS device token
::
token=@t
:: ship that routes notifications to Apple
::
king=@p
:: url of Apple server to send notifications to
::
baseurl=@t
:: name and last read
::
circles=(map name:hall @)
==
::
--
::
:: state:
::
|_ [bol=bowl:gall sta=state]
tacryt-socryp marked this conversation as resolved.
Show resolved Hide resolved
::
:: +this: app core subject
::
++ this .
::
:: +prep: set up app state, upgrade app state
::
++ prep
|= old=(unit state)
^- (quip move _this)
?~ old
:- ~
%= this
king.sta ~dabben-larbet
baseurl.sta 'https://api.push.apple.com/3/device/'
==
?- -.u.old
%0
[~ this(sta u.old)]
==
::
:: +coup: receive acknowledgement for poke, print error if it failed
::
++ coup
|= [wir=wire err=(unit tang)]
^- (quip move _this)
?~ err
[~ this]
(mean u.err)
::
:: +poke-noun: receive debugging actions
::
++ poke-noun
|= act=action
^- (quip move _this)
(poke-tiebout-action act)
::
:: +poke-tiebout-action: main action handler
::
++ poke-tiebout-action
|= act=action
^- (quip move _this)
?- -.act
$king (set-king +.act)
$token (set-token +.act)
$baseurl (set-baseurl +.act)
$add-circle (add-circle +.act)
$del-circle (del-circle +.act)
$notify (send-notify +.act)
==
tacryt-socryp marked this conversation as resolved.
Show resolved Hide resolved
::
:: +add-circle: add circle and subscribe for updates
::
++ add-circle
|= nom=name:hall
^- (quip move _this)
:_ this(circles.sta (~(put by circles.sta) nom 0))
[ost.bol %peer /our/[nom] [our.bol %hall] /circle/[nom]/config/grams]~
tacryt-socryp marked this conversation as resolved.
Show resolved Hide resolved
::
:: +del-circle: delete circle and unsubscribe from updates
::
++ del-circle
|= nom=name:hall
^- (quip move _this)
:_ this(circles.sta (~(del by circles.sta) nom))
[ost.bol %pull /our/[nom] [our.bol %hall] ~]~
::
:: +set-king: set king @p
::
++ set-king
|= kng=@p
^- (quip move _this)
[~ this(king.sta kng)]
::
:: +set-token: set iOS device token @t
::
++ set-token
|= tok=@t
^- (quip move _this)
[~ this(token.sta tok)]
::
:: +set-baseurl: set base url @t
::
++ set-baseurl
|= burl=@t
^- (quip move _this)
[~ this(baseurl.sta burl)]
::
:: +send-notify: if king, send hiss. if not, do nothing.
::
++ send-notify
|= not=notification
^- (quip move _this)
?: =(king.sta our.bol)
:_ this
[ost.bol %hiss /request [~ ~] %httr %hiss (create-apns-request not)]~
[~ this]
::
:: +diff-hall-prize: receive new circle data
::
++ diff-hall-prize
|= [wir=wire piz=prize:hall]
^- (quip move _this)
?+ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
:: %our: set config of circle and iterate through messages, sending
:: notifications for all messages where number is higher than our last-read
::
{%our @ @}
?> ?=(%circle -.piz)
=/ nom/name:hall i.t.wir
=/ red/@ud red.loc.cos.piz
Copy link
Member

Choose a reason for hiding this comment

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

-1 for old syntax It's in a bunch of other places too.

These two really should be =* anyway, it's specifically made for putting different/easier faces on things.

Do we not need to check for red to actually be bigger than what's currently stored for nom? I don't think so, but just checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you include type information in =*?

Copy link
Member

Choose a reason for hiding this comment

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

Yes! Since #585 you can do =* foo=bar baz. I actually forget this made it in already, and should've been using it more. Neat!

[~ this(circles.sta (~(put by circles.sta) nom red))]
==
::
:: +reap: recieve acknowledgement for peer
::
++ reap
|= [wir=wire err=(unit tang)]
^- (quip move _this)
?~ err
[~ this]
?+ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
{%our @ @}
?< ?=(~ t.wir)
[~ this]
==
::
:: +quit: receive subscription failed, resubscribe
::
++ quit
|= wir=wire
^- (quip move _this)
?+ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
{%our @ @}
?< ?=(~ t.wir)
:_ this
=/ doc/dock [our.bol %hall]
[ost.bol %peer /our/[i.t.wir] doc /circle/[i.t.wir]/config/grams]~
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we want to re-subscribe from the last-heard message going forward? I think the logic below ensures we don't send notifications for whatever old junk we may get here, but still.

Pretty sure this just gives you the last 100 messages, or all messages from the last ~d1 or something along those lines. Being more specific allows you to catch up from even further back when needed, and doesn't get you more info than you need.

==

::
:: +diff-hall-rumor: receive message or a read event from a hall circle
::
++ diff-hall-rumor
|= [wir=wire rum=rumor:hall]
^- (quip move _this)
?+ wir
(mean [leaf+"invalid wire for diff: {(spud wir)}"]~)
::
:: %our
::
{%our @ @}
Copy link
Member

Choose a reason for hiding this comment

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

While these are technically correct and will successfully match /our/whatever aka [%our %whatever ~], it's better to describe a limited-length wire by actually ending with ~ in the type description.

?> ?=(%circle -.rum)
=/ nom/name:hall i.t.wir
?+ -.rum.rum
[~ this]
::
:: %gram: send notification if envelope is lower than read number
::
%gram
=/ red (~(get by circles.sta) nom)
?~ red
(mean [leaf+"invalid circle for diff: {(spud wir)}"]~)
?: (gth num.nev.rum.rum u.red)
:_ this(circles.sta (~(put by circles.sta) nom u.red))
(conditional-msg-to-not u.red nev.rum.rum)
:_ this
(conditional-msg-to-not u.red nev.rum.rum)
::
:: %config: set our read number
::
%config
?+ -.dif.rum.rum
[~ this]
::
%read
[~ this(circles.sta (~(put by circles.sta) nom red.dif.rum.rum))]
==
==
==
::
:: generate notification move from hall message if conditions are met
::
++ conditional-msg-to-not
|= [red=@ud env=envelope:hall]
^- (list move)
Copy link
Member

Choose a reason for hiding this comment

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

This seems to always produce a list of either zero moves, or one move. Sounds like a (unit move) to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like the code style of sending back a list much more. I'd need to add another layer of conditional checks in diff-hall-rumor otherwise.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I guess (list move) is still fair game here. The contract between "notification" and "moves" is a bit weird, so maybe comment, but approved either way.

?: =(aut.gam.env our.bol)
~
=/ pay %- my :~
alert+s+'New message from {(cite:title aut.gam.env)}'
==
Copy link
Member

Choose a reason for hiding this comment

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

This could do with a type for pay. my isn't commonly used, ~(gas in *(map @t json)) is more verbose/clear on what it does (and type-checks early!). For this case, you could also ~(put by *(map @t json)) since you only have one element.

Or just do the dumbest thing and say [alert+s+'etc' ~ ~] and cast that to a map. (^:

(The most aggressive thing to do here, of course, is to tell @pilfer-pandex to put "map/set syntax" on the global hoon wishlist.)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, this is certainly on my radar.

Copy link
Member

Choose a reason for hiding this comment

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

Also wait a second, 'cords' don't support string interpolation! You need to (crip "tape {etc}") here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't like gas in map. It's less clear to me than my.

=/ not/notification [token.sta 'com.tlon.urbit-client' pay]
?: (lte num.env red)
~
=/ doc/dock [king.sta dap.bol]
[ost.bol %poke /ask-king doc %tiebout-action [%notify not]]~
Copy link
Member

Choose a reason for hiding this comment

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

Ah, so kings route your notifications for you? Is this because we don't want any old ship to access our push endpoint? idk about loading it all onto ~dopzod, we may want a dedicated ship for this, but the load probably isn't that big?


::
:: +create-apns-request: create hiss with payload for APNs
::
++ create-apns-request
|= not=notification
^- hiss
=/ furl=@t (crip (weld (trip baseurl.sta) (trip token.not)))
=/ url=purl (need (de-purl:html furl))
=/ jon=json :- %o
%- my :~
aps+o+payload.not
==
tacryt-socryp marked this conversation as resolved.
Show resolved Hide resolved
:^ url %post
%- my :~
apns-topic+[topic.not ~] :: generate map from raw noun
==
(some (as-octt:mimes:html (en-json:html jon)))
--
33 changes: 33 additions & 0 deletions mar/tiebout-action.hoon
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/- hall, tiebout
=, format
::
|_ act=action:tiebout
::
++ grow
|%
++ tank >act<
--
::
++ grab
|%
++ noun action:tiebout
++ json
|= jon=^json
^- action:tiebout
=< (action jon)
|%
++ action
Copy link
Member

Choose a reason for hiding this comment

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

|^ exists and might be nicer here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nest-failed in a weird way, skipping it.

Copy link
Member

Choose a reason for hiding this comment

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

Happy to help you figure it out if you want to, but I won't press you on it.

%- of:dejs
:~ token+so:dejs
add-circle+sa
del-circle+sa
==
++ sa :: string as ta
|= jon=^json
?> ?=([%s *] jon)
(scot %tas p.jon)
Copy link
Member

Choose a reason for hiding this comment

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

If you want a @tas from the @t p.jon, you can either just cast it, or ?> (sane %tas p.jon) and then cast, or similar. (scot %tas just gives you the "rendered" version, which may not be what you want.

--
--
::
--

21 changes: 21 additions & 0 deletions sur/tiebout.hoon
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/- hall
=, eyre
::
::
|%
+$ notification
$: token=@t
topic=@t
payload=(map @t json)
==
::
+$ action
$% [%token tok=@t] :: set device token
[%king kng=@p] :: set ship to route notifications through
[%baseurl bur=@t] :: set url to send notifications to
[%notify not=notification] :: send notification
[%add-circle nom=name:hall] :: send notifications for this circle
[%del-circle nom=name:hall] :: stop sending for this circle
==
::
--