mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-01 03:23:09 +03:00
Merge branch 'master' into jam-cue-rock
* master: soto: ignores backspace at position 0 zuse: fix outdated docs on vanes [ci skip] sh: fix merge-and-update-solid name [ci skip] Revert "hoon: refactor royl float parsers to separate arms" hoon: refactor royl float parsers to separate arms publish: add subscribe generator hoon: refactor royl float parsers to separate arms chat: added temporary chat-two-update mark with new %messages type chat: oust correctness fix and js style fix chat-store: factored out functions used in both message and messages chat: style fixes soto: style changes chat: fixes to cli parser and increased page size in hook interface: add soto source code chat-js: updated to support %messages events sur: added rw-security to replace chat-security chat: add history functionality. optionally request backlog. drum: Boot with %soto arvo: adds soto application mar/sole: add %tab conversion
This commit is contained in:
commit
077ad76488
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8d5434f92c35d11e4a8cb9f63d02c26cf4ac20fd0b454997a90f396c45f8639c
|
||||
size 8957682
|
||||
oid sha256:bccc640d030d2ec49b24a5f3413b305cb4823f1b5bf86f5d0dbfe7f6dc38ac2a
|
||||
size 8951763
|
||||
|
@ -39,12 +39,14 @@
|
||||
[%say letter] :: send message
|
||||
[%eval cord hoon] :: send #-message
|
||||
::
|
||||
[%create chat-security path (unit glyph)] :: create chat
|
||||
::
|
||||
:: create chat
|
||||
[%create rw-security path (unit glyph) (unit ?)]
|
||||
[%delete path] :: delete chat
|
||||
[%invite ?(%r %w %rw) path (set ship)] :: allow
|
||||
[%banish ?(%r %w %rw) path (set ship)] :: disallow
|
||||
::
|
||||
[%join target (unit glyph)] :: join target
|
||||
[%join target (unit glyph) (unit ?)] :: join target
|
||||
[%leave target] :: nuke target
|
||||
::
|
||||
[%bind glyph target] :: bind glyph
|
||||
@ -178,6 +180,11 @@
|
||||
:- [prompt:sh-out ~]
|
||||
:: start with fresh sole state
|
||||
this(state.cli *sole-share:sole-sur)
|
||||
::
|
||||
++ diff-chat-two-update
|
||||
|= [=wire upd=chat-two-update]
|
||||
^- (quip move _this)
|
||||
(read-envelopes (path-to-target path.upd) envelopes.upd)
|
||||
:: +diff-chat-update: get new mailboxes & messages
|
||||
::
|
||||
++ diff-chat-update
|
||||
@ -364,13 +371,24 @@
|
||||
;~ (glue ace)
|
||||
(tag %create)
|
||||
security
|
||||
;~(plug path (punt ;~(pfix ace glyph)))
|
||||
;~ plug
|
||||
path
|
||||
(punt ;~(pfix ace glyph))
|
||||
(punt ;~(pfix ace (fuss 'y' 'n')))
|
||||
==
|
||||
==
|
||||
;~((glue ace) (tag %delete) path)
|
||||
;~((glue ace) (tag %invite) rw path ships)
|
||||
;~((glue ace) (tag %banish) rw path ships)
|
||||
::
|
||||
;~((glue ace) (tag %join) ;~(plug targ (punt ;~(pfix ace glyph))))
|
||||
;~ (glue ace)
|
||||
(tag %join)
|
||||
;~ plug
|
||||
targ
|
||||
(punt ;~(pfix ace glyph))
|
||||
(punt ;~(pfix ace (fuss 'y' 'n')))
|
||||
==
|
||||
==
|
||||
;~((glue ace) (tag %leave) targ)
|
||||
::
|
||||
;~((glue ace) (tag %bind) glyph targ)
|
||||
@ -625,7 +643,7 @@
|
||||
:: +create: new local mailbox
|
||||
::
|
||||
++ create
|
||||
|= [security=chat-security =path gyf=(unit char)]
|
||||
|= [security=rw-security =path gyf=(unit char) allow-history=(unit ?)]
|
||||
^- (quip move _this)
|
||||
::TODO check if already exists
|
||||
=/ =target [our-self path]
|
||||
@ -636,18 +654,22 @@
|
||||
=- [[- moz] this]
|
||||
%^ act %do-create %chat-view
|
||||
:- %chat-view-action
|
||||
:^ %create path security
|
||||
:: ensure we can read from/write to our own chats
|
||||
::
|
||||
:- :: read
|
||||
:* %create
|
||||
path
|
||||
security
|
||||
:: ensure we can read from/write to our own chats
|
||||
::
|
||||
:: read
|
||||
?- security
|
||||
?(%channel %journal) ~
|
||||
?(%village %mailbox) [our-self ~ ~]
|
||||
==
|
||||
:: write
|
||||
?- security
|
||||
?(%channel %mailbox) ~
|
||||
?(%village %journal) [our-self ~ ~]
|
||||
:: write
|
||||
?- security
|
||||
?(%channel %mailbox) ~
|
||||
?(%village %journal) [our-self ~ ~]
|
||||
==
|
||||
(fall allow-history %.y)
|
||||
==
|
||||
:: +delete: delete local chats
|
||||
::
|
||||
@ -708,7 +730,7 @@
|
||||
:: +join: sync with remote mailbox
|
||||
::
|
||||
++ join
|
||||
|= [=target gyf=(unit char)]
|
||||
|= [=target gyf=(unit char) ask-history=(unit ?)]
|
||||
^- (quip move _this)
|
||||
=^ moz this
|
||||
?. ?=(^ gyf) [~ this]
|
||||
@ -720,7 +742,7 @@
|
||||
:: gives ugly %chat-hook-reap
|
||||
%^ act %do-join %chat-view
|
||||
:- %chat-view-action
|
||||
[%join target]
|
||||
[%join ship.target path.target (fall ask-history %.y)]
|
||||
:: +leave: unsync & destroy mailbox
|
||||
::
|
||||
::TODO allow us to "mute" local chats using this
|
||||
|
@ -8,16 +8,17 @@
|
||||
+$ move [bone card]
|
||||
::
|
||||
+$ card
|
||||
$% [%diff [%chat-update chat-update]]
|
||||
$% [%diff diff]
|
||||
[%quit ~]
|
||||
[%poke wire dock poke]
|
||||
[%pull wire dock ~]
|
||||
[%peer wire dock path]
|
||||
==
|
||||
::
|
||||
+$ state-both
|
||||
+$ versioned-state
|
||||
$% state-zero
|
||||
state-one
|
||||
state-two
|
||||
==
|
||||
::
|
||||
+$ state-zero
|
||||
@ -33,6 +34,14 @@
|
||||
invite-created=_|
|
||||
==
|
||||
::
|
||||
+$ state-two
|
||||
$: %2
|
||||
synced=(map path ship)
|
||||
boned=(map wire (list bone))
|
||||
invite-created=_|
|
||||
allow-history=(map path ?)
|
||||
==
|
||||
::
|
||||
+$ poke
|
||||
$% [%chat-action chat-action]
|
||||
[%permission-action permission-action]
|
||||
@ -40,15 +49,19 @@
|
||||
[%chat-view-action chat-view-action]
|
||||
==
|
||||
::
|
||||
+$ diff
|
||||
$% [%chat-update chat-update]
|
||||
[%chat-two-update chat-two-update]
|
||||
==
|
||||
--
|
||||
::
|
||||
|_ [bol=bowl:gall state-one]
|
||||
|_ [bol=bowl:gall state-two]
|
||||
::
|
||||
++ this .
|
||||
::
|
||||
++ prep
|
||||
|= old=(unit state-both)
|
||||
^- (quip move _this)
|
||||
|= old=(unit versioned-state)
|
||||
|^ ^- (quip move _this)
|
||||
?~ old
|
||||
:_ this(invite-created %.y)
|
||||
:~ (invite-poke [%create /chat])
|
||||
@ -56,19 +69,32 @@
|
||||
[ost.bol %peer /permissions [our.bol %permission-store] /updates]
|
||||
==
|
||||
?- -.u.old
|
||||
%1 [~ this(+<+ u.old)]
|
||||
%2 [~ this(+<+ u.old)]
|
||||
%1 [~ (migrate-state synced.u.old boned.u.old)]
|
||||
::
|
||||
%0
|
||||
=/ sta *state-one
|
||||
=: boned.sta boned.u.old
|
||||
synced.sta synced.u.old
|
||||
invite-created %.y
|
||||
==
|
||||
:_ this(+<+ sta)
|
||||
:_ (migrate-state synced.u.old boned.u.old)
|
||||
:~ (invite-poke [%create /chat])
|
||||
[ost.bol %peer /invites [our.bol %invite-store] /invitatory/chat]
|
||||
==
|
||||
==
|
||||
::
|
||||
++ migrate-state
|
||||
|= [synced=(map path ship) boned=(map wire (list bone))]
|
||||
^- _this
|
||||
=/ sta *state-two
|
||||
=: boned.sta boned
|
||||
synced.sta synced
|
||||
allow-history.sta (create-allow-history synced)
|
||||
invite-created %.y
|
||||
==
|
||||
this(+<+ sta)
|
||||
::
|
||||
++ create-allow-history
|
||||
|= synced=(map path ship)
|
||||
^- (map path ?)
|
||||
(~(run by synced) |=(* %.n))
|
||||
--
|
||||
::
|
||||
++ poke-json
|
||||
|= jon=json
|
||||
@ -110,7 +136,9 @@
|
||||
=/ chat-path [%mailbox path.act]
|
||||
?: (~(has by synced) path.act)
|
||||
[~ this]
|
||||
=. synced (~(put by synced) path.act our.bol)
|
||||
=: synced (~(put by synced) path.act our.bol)
|
||||
allow-history (~(put by allow-history) path.act allow-history.act)
|
||||
==
|
||||
:_ (track-bone chat-path)
|
||||
%+ weld
|
||||
[ost.bol %peer chat-path [our.bol %chat-store] chat-path]~
|
||||
@ -118,12 +146,13 @@
|
||||
::
|
||||
%add-synced
|
||||
?> (team:title our.bol src.bol)
|
||||
=/ chat-path [%mailbox (scot %p ship.act) path.act]
|
||||
=/ chat-path=path [%mailbox (scot %p ship.act) path.act]
|
||||
?: (~(has by synced) [(scot %p ship.act) path.act])
|
||||
[~ this]
|
||||
=. synced (~(put by synced) [(scot %p ship.act) path.act] ship.act)
|
||||
=/ history=path ?:(ask-history.act /0 /~)
|
||||
:_ (track-bone chat-path)
|
||||
[ost.bol %peer chat-path [ship.act %chat-hook] chat-path]~
|
||||
[ost.bol %peer chat-path [ship.act %chat-hook] (weld chat-path history)]~
|
||||
::
|
||||
%remove
|
||||
=/ ship (~(get by synced) path.act)
|
||||
@ -157,6 +186,13 @@
|
||||
++ peer-mailbox
|
||||
|= pax=path
|
||||
^- (quip move _this)
|
||||
?> ?=(^ pax)
|
||||
=/ last (dec (lent pax))
|
||||
=/ backlog-start=(unit @ud)
|
||||
%+ rush
|
||||
(snag last `(list @ta)`pax)
|
||||
dem:ag
|
||||
=> .(pax `path`(oust [last 1] `(list @ta)`pax))
|
||||
?> ?=([* ^] pax)
|
||||
?> (~(has by synced) pax)
|
||||
:: scry permissions to check if read is permitted
|
||||
@ -164,7 +200,43 @@
|
||||
=/ box (chat-scry pax)
|
||||
?~ box !!
|
||||
:_ this
|
||||
[ost.bol %diff %chat-update [%create (slav %p i.pax) pax]]~
|
||||
:- [ost.bol %diff %chat-update [%create (slav %p i.pax) pax]]
|
||||
?: ?&(?=(^ backlog-start) (~(got by allow-history) pax))
|
||||
(paginate-messages pax u.box u.backlog-start)
|
||||
~
|
||||
::
|
||||
++ paginate-messages
|
||||
|= [=path =mailbox start=@ud]
|
||||
^- (list move)
|
||||
=/ moves=(list move) ~
|
||||
=/ end (lent envelopes.mailbox)
|
||||
?: |((gte start end) =(end 0))
|
||||
moves
|
||||
=. envelopes.mailbox (slag start `(list envelope)`envelopes.mailbox)
|
||||
|- ^- (list move)
|
||||
?~ envelopes.mailbox
|
||||
moves
|
||||
?: (lte end 5.000)
|
||||
=. moves
|
||||
%+ snoc moves
|
||||
%- messages-move
|
||||
[path start (lent envelopes.mailbox) envelopes.mailbox]
|
||||
$(envelopes.mailbox ~)
|
||||
=. moves
|
||||
%+ snoc moves
|
||||
%- messages-move
|
||||
:^ path start
|
||||
(add start 5.000)
|
||||
(scag 5.000 `(list envelope)`envelopes.mailbox)
|
||||
=: start (add start 5.000)
|
||||
end (sub end 5.000)
|
||||
==
|
||||
$(envelopes.mailbox (slag 5.000 `(list envelope)`envelopes.mailbox))
|
||||
::
|
||||
++ messages-move
|
||||
|= [=path start=@ud end=@ud envelopes=(list envelope)]
|
||||
^- move
|
||||
[ost.bol %diff %chat-two-update [%messages path start end envelopes]]
|
||||
::
|
||||
++ diff-invite-update
|
||||
|= [wir=wire diff=invite-update]
|
||||
@ -173,8 +245,12 @@
|
||||
[~ this]
|
||||
::
|
||||
%accepted
|
||||
=/ ask-history
|
||||
?~ (chat-scry [(scot %p ship.invite.diff) path.invite.diff])
|
||||
%.y
|
||||
%.n
|
||||
:_ this
|
||||
[(chat-view-poke [%join ship.invite.diff path.invite.diff])]~
|
||||
[(chat-view-poke [%join ship.invite.diff path.invite.diff ask-history])]~
|
||||
==
|
||||
::
|
||||
++ diff-permission-update
|
||||
@ -211,6 +287,24 @@
|
||||
=/ bne (~(get by sup) [check-ship [%mailbox mail-path]])
|
||||
?~(bne ~ [u.bne %quit ~]~)
|
||||
::
|
||||
++ diff-chat-two-update
|
||||
|= [wir=wire diff=chat-two-update]
|
||||
^- (quip move _this)
|
||||
:: local
|
||||
?: (team:title our.bol src.bol)
|
||||
:_ this
|
||||
%+ turn (prey:pubsub:userlib [%mailbox path.diff] bol)
|
||||
|= [=bone *]
|
||||
^- move
|
||||
[bone %diff [%chat-two-update diff]]
|
||||
:: foreign
|
||||
:_ this
|
||||
?> ?=([* ^] path.diff)
|
||||
=/ shp (~(get by synced) path.diff)
|
||||
?~ shp ~
|
||||
?. =(src.bol u.shp) ~
|
||||
[(chat-poke [%messages path.diff envelopes.diff])]~
|
||||
::
|
||||
++ diff-chat-update
|
||||
|= [wir=wire diff=chat-update]
|
||||
^- (quip move _this)
|
||||
@ -222,10 +316,10 @@
|
||||
|= diff=chat-update
|
||||
^- (quip move _this)
|
||||
?- -.diff
|
||||
%keys [~ this]
|
||||
%config [~ this]
|
||||
%create [~ this]
|
||||
%read [~ this]
|
||||
%keys [~ this]
|
||||
%config [~ this]
|
||||
%create [~ this]
|
||||
%read [~ this]
|
||||
%delete
|
||||
?. (~(has by synced) path.diff)
|
||||
[~ this]
|
||||
@ -263,7 +357,7 @@
|
||||
?. =(u.shp src.bol)
|
||||
[~ this]
|
||||
:_ this(synced (~(del by synced) path.diff))
|
||||
:- (chat-poke diff)
|
||||
:- (chat-poke [%delete path.diff])
|
||||
[ost.bol %pull [%mailbox path.diff] [src.bol %chat-hook] ~]~
|
||||
::
|
||||
%message
|
||||
@ -272,7 +366,7 @@
|
||||
=/ shp (~(get by synced) path.diff)
|
||||
?~ shp ~
|
||||
?. =(src.bol u.shp) ~
|
||||
[(chat-poke diff)]~
|
||||
[(chat-poke [%message path.diff envelope.diff])]~
|
||||
==
|
||||
::
|
||||
++ quit
|
||||
@ -286,9 +380,13 @@
|
||||
?. (~(has by synced) t.wir)
|
||||
:: no-op
|
||||
[~ this]
|
||||
=/ mailbox (chat-scry t.wir)
|
||||
?~ mailbox [~ this]
|
||||
~& %chat-hook-resubscribe
|
||||
=/ pax=path (weld wir /(scot %ud (lent envelopes.u.mailbox)))
|
||||
~& pax
|
||||
:_ (track-bone wir)
|
||||
[ost.bol %peer wir [(slav %p i.t.wir) %chat-hook] wir]~
|
||||
[ost.bol %peer wir [(slav %p i.t.wir) %chat-hook] pax]~
|
||||
::
|
||||
++ reap
|
||||
|= [wir=wire saw=(unit tang)]
|
||||
@ -325,7 +423,7 @@
|
||||
[ost.bol %poke / [our.bol %invite-store] [%invite-action act]]
|
||||
::
|
||||
++ create-permission
|
||||
|= [pax=path sec=chat-security]
|
||||
|= [pax=path sec=rw-security]
|
||||
^- (list move)
|
||||
=/ read-perm (weld pax /read)
|
||||
=/ write-perm (weld pax /write)
|
||||
|
@ -21,6 +21,7 @@
|
||||
$% [%chat-initial inbox]
|
||||
[%chat-configs chat-configs]
|
||||
[%chat-update chat-update]
|
||||
[%chat-two-update chat-two-update]
|
||||
==
|
||||
--
|
||||
::
|
||||
@ -154,10 +155,11 @@
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
?- -.action
|
||||
%create (handle-create action)
|
||||
%delete (handle-delete action)
|
||||
%message (handle-message action)
|
||||
%read (handle-read action)
|
||||
%create (handle-create action)
|
||||
%delete (handle-delete action)
|
||||
%message (handle-message action)
|
||||
%messages (handle-messages action)
|
||||
%read (handle-read action)
|
||||
==
|
||||
::
|
||||
++ handle-create
|
||||
@ -187,17 +189,34 @@
|
||||
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
||||
?~ mailbox
|
||||
[~ this]
|
||||
=* letter letter.envelope.act
|
||||
=? letter &(?=(%code -.letter) ?=(~ output.letter))
|
||||
=/ =hoon (ream expression.letter)
|
||||
letter(output (eval bol hoon))
|
||||
=: length.config.u.mailbox +(length.config.u.mailbox)
|
||||
number.envelope.act +(length.config.u.mailbox)
|
||||
envelopes.u.mailbox (snoc envelopes.u.mailbox envelope.act)
|
||||
==
|
||||
=. letter.envelope.act (evaluate-letter letter.envelope.act)
|
||||
=. u.mailbox (append-envelope u.mailbox envelope.act)
|
||||
:- (send-diff path.act act)
|
||||
this(inbox (~(put by inbox) path.act u.mailbox))
|
||||
::
|
||||
++ handle-messages
|
||||
|= act=chat-action
|
||||
^- (quip move _this)
|
||||
?> ?=(%messages -.act)
|
||||
=/ mailbox=(unit mailbox) (~(get by inbox) path.act)
|
||||
?~ mailbox
|
||||
[~ this]
|
||||
=/ evaluated-envelopes=(list envelope) ~
|
||||
|- ^- (quip move _this)
|
||||
?~ envelopes.act
|
||||
:_ this(inbox (~(put by inbox) path.act u.mailbox))
|
||||
%+ send-two-diff path.act
|
||||
:* %messages
|
||||
path.act
|
||||
(sub length.config.u.mailbox (lent evaluated-envelopes))
|
||||
length.config.u.mailbox
|
||||
evaluated-envelopes
|
||||
==
|
||||
=. letter.i.envelopes.act (evaluate-letter letter.i.envelopes.act)
|
||||
=. evaluated-envelopes (snoc evaluated-envelopes i.envelopes.act)
|
||||
=. u.mailbox (append-envelope u.mailbox i.envelopes.act)
|
||||
$(envelopes.act t.envelopes.act)
|
||||
::
|
||||
++ handle-read
|
||||
|= act=chat-action
|
||||
^- (quip move _this)
|
||||
@ -209,26 +228,58 @@
|
||||
:- (send-diff path.act act)
|
||||
this(inbox (~(put by inbox) path.act u.mailbox))
|
||||
::
|
||||
++ evaluate-letter
|
||||
|= =letter
|
||||
^- ^letter
|
||||
=? letter &(?=(%code -.letter) ?=(~ output.letter))
|
||||
=/ =hoon (ream expression.letter)
|
||||
letter(output (eval bol hoon))
|
||||
letter
|
||||
::
|
||||
++ append-envelope
|
||||
|= [=mailbox =envelope]
|
||||
^- ^mailbox
|
||||
=. number.envelope +(length.config.mailbox)
|
||||
=: length.config.mailbox +(length.config.mailbox)
|
||||
envelopes.mailbox (snoc envelopes.mailbox envelope)
|
||||
==
|
||||
mailbox
|
||||
::
|
||||
++ update-subscribers
|
||||
|= [pax=path act=chat-action]
|
||||
|= [pax=path upd=chat-update]
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib pax bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %chat-update act]
|
||||
[bone %diff %chat-update upd]
|
||||
::
|
||||
++ send-diff
|
||||
|= [pax=path act=chat-action]
|
||||
|= [pax=path upd=chat-update]
|
||||
^- (list move)
|
||||
%- zing
|
||||
:~ (update-subscribers /all act)
|
||||
(update-subscribers /updates act)
|
||||
(update-subscribers [%mailbox pax] act)
|
||||
?. |(=(%read -.act) =(%message -.act))
|
||||
:~ (update-subscribers /all upd)
|
||||
(update-subscribers /updates upd)
|
||||
(update-subscribers [%mailbox pax] upd)
|
||||
?. |(|(=(%read -.upd) =(%message -.upd)) =(%messages -.upd))
|
||||
~
|
||||
(update-subscribers /configs act)
|
||||
?. |(=(%create -.act) =(%delete -.act))
|
||||
(update-subscribers /configs upd)
|
||||
?. |(=(%create -.upd) =(%delete -.upd))
|
||||
~
|
||||
(update-subscribers /keys act)
|
||||
(update-subscribers /keys upd)
|
||||
==
|
||||
::
|
||||
++ send-two-diff
|
||||
|= [pax=path upd=chat-two-update]
|
||||
^- (list move)
|
||||
%- zing
|
||||
:~ (update-two-subscribers /all upd)
|
||||
(update-two-subscribers /updates upd)
|
||||
(update-two-subscribers [%mailbox pax] upd)
|
||||
==
|
||||
::
|
||||
++ update-two-subscribers
|
||||
|= [pax=path upd=chat-two-update]
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib pax bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %chat-two-update upd]
|
||||
--
|
||||
|
@ -129,9 +129,8 @@
|
||||
%http-response
|
||||
%- json-response:app
|
||||
%- json-to-octs
|
||||
%+ envelopes-update
|
||||
envelopes
|
||||
[start end pax]
|
||||
%- two-update-to-json
|
||||
[%messages pax start end envelopes]
|
||||
==
|
||||
::
|
||||
:: inbox page
|
||||
@ -155,7 +154,6 @@
|
||||
[~ this]
|
||||
?- -.act
|
||||
%create
|
||||
:: TODO: add invites
|
||||
=/ pax [(scot %p our.bol) path.act]
|
||||
=/ group-read=path [%chat (weld pax /read)]
|
||||
=/ group-write=path [%chat (weld pax /write)]
|
||||
@ -166,7 +164,7 @@
|
||||
(group-poke [%add read.act group-read])
|
||||
(group-poke [%add write.act group-write])
|
||||
(chat-poke [%create our.bol path.act])
|
||||
(chat-hook-poke [%add-owned pax security.act])
|
||||
(chat-hook-poke [%add-owned pax security.act allow-history.act])
|
||||
==
|
||||
(create-security [%chat pax] security.act)
|
||||
:~ (permission-hook-poke [%add-owned group-read group-read])
|
||||
@ -190,7 +188,7 @@
|
||||
=/ group-read [%chat (scot %p ship.act) (weld path.act /read)]
|
||||
=/ group-write [%chat (scot %p ship.act) (weld path.act /write)]
|
||||
:_ this
|
||||
:~ (chat-hook-poke [%add-synced ship.act path.act])
|
||||
:~ (chat-hook-poke [%add-synced ship.act path.act ask-history.act])
|
||||
(permission-hook-poke [%add-synced ship.act group-write])
|
||||
(permission-hook-poke [%add-synced ship.act group-read])
|
||||
==
|
||||
@ -227,6 +225,21 @@
|
||||
|= [=bone *]
|
||||
[bone %diff %json configs-json]
|
||||
::
|
||||
++ diff-chat-two-update
|
||||
|= [wir=wire upd=chat-two-update]
|
||||
^- (quip move _this)
|
||||
=/ updates-json (two-update-to-json upd)
|
||||
=/ configs-json (configs-to-json configs-scry)
|
||||
:_ this
|
||||
%+ weld
|
||||
%+ turn (prey:pubsub:userlib /primary bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %json updates-json]
|
||||
%+ turn (prey:pubsub:userlib /configs bol)
|
||||
|= [=bone *]
|
||||
[bone %diff %json configs-json]
|
||||
|
||||
::
|
||||
++ quit
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
@ -281,7 +294,7 @@
|
||||
.^(chat-configs %gx /=chat-store/(scot %da now.bol)/configs/noun)
|
||||
::
|
||||
++ create-security
|
||||
|= [pax=path sec=chat-security]
|
||||
|= [pax=path sec=rw-security]
|
||||
^- (list move)
|
||||
=/ read (weld pax /read)
|
||||
=/ write (weld pax /write)
|
||||
@ -308,22 +321,6 @@
|
||||
::
|
||||
==
|
||||
::
|
||||
++ envelopes-update
|
||||
|= [envelopes=(list envelope) start=@ud end=@ud pax=path]
|
||||
^- json
|
||||
=, enjs:format
|
||||
%+ frond %chat-update
|
||||
%- pairs
|
||||
:~
|
||||
:- %messages
|
||||
%- pairs
|
||||
:~ [%path (path pax)]
|
||||
[%start (numb start)]
|
||||
[%end (numb end)]
|
||||
[%envelopes [%a (turn envelopes enve)]]
|
||||
==
|
||||
==
|
||||
::
|
||||
++ truncate-envelopes
|
||||
|= envelopes=(list envelope)
|
||||
^- (list envelope)
|
||||
@ -340,5 +337,4 @@
|
||||
^- mailbox
|
||||
:- config.mail
|
||||
(truncate-envelopes envelopes.mail)
|
||||
::
|
||||
--
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
171
pkg/arvo/app/soto.hoon
Normal file
171
pkg/arvo/app/soto.hoon
Normal file
@ -0,0 +1,171 @@
|
||||
::
|
||||
:: Soto: A Dojo relay for Urbit's Landscape interface
|
||||
:: Relays sole-effects to subscribers and forwards sole-action pokes
|
||||
::
|
||||
/- sole
|
||||
/+ *server, *soto
|
||||
/= index
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/soto/index
|
||||
/| /html/
|
||||
/~ ~
|
||||
==
|
||||
/= tile-js
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/soto/js/tile
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
/= script
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/soto/js/index
|
||||
/| /js/
|
||||
/~ ~
|
||||
==
|
||||
/= style
|
||||
/^ octs
|
||||
/; as-octs:mimes:html
|
||||
/: /===/app/soto/css/index
|
||||
/| /css/
|
||||
/~ ~
|
||||
==
|
||||
/= soto-png
|
||||
/^ (map knot @)
|
||||
/: /===/app/soto/img /_ /png/
|
||||
::
|
||||
|%
|
||||
+$ state
|
||||
:: bon: bone from Dojo peer
|
||||
::
|
||||
$% [%0 bon=bone]
|
||||
==
|
||||
::
|
||||
+$ move [bone card]
|
||||
::
|
||||
+$ poke
|
||||
$% [%launch-action [@tas path @t]]
|
||||
[%sole-action sole-action]
|
||||
[%json json]
|
||||
==
|
||||
::
|
||||
+$ card
|
||||
$% [%poke wire dock poke]
|
||||
[%peer wire dock path]
|
||||
[%http-response =http-event:http]
|
||||
[%connect wire binding:eyre term]
|
||||
[%diff diff]
|
||||
==
|
||||
::
|
||||
+$ diff
|
||||
$% [%json json]
|
||||
[%sole-effect sole-effect]
|
||||
==
|
||||
::
|
||||
--
|
||||
::
|
||||
|_ [bol=bowl:gall sta=state]
|
||||
::
|
||||
++ this .
|
||||
::
|
||||
++ prep
|
||||
|= old=(unit state)
|
||||
^- (quip move _this)
|
||||
=/ launcha=poke
|
||||
[%launch-action [%soto /sototile '/~soto/js/tile.js']]
|
||||
?~ old
|
||||
:_ this
|
||||
:~
|
||||
[ost.bol %connect / [~ /'~soto'] %soto]
|
||||
[ost.bol %poke /soto [our.bol %launch] launcha]
|
||||
==
|
||||
[~ this(sta u.old)]
|
||||
::
|
||||
++ peer-sototile
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
:_ this
|
||||
[ost.bol %diff %json *json]~
|
||||
::
|
||||
:: Peering Dojo when peered by front-end, initiating the session
|
||||
::
|
||||
++ peer-primary
|
||||
|= wir=wire
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
:: poke/peer need same wire
|
||||
::
|
||||
:_ this(bon.sta ost.bol)
|
||||
[ost.bol %peer / [our.bol %dojo] /sole]~
|
||||
::
|
||||
++ poke-json
|
||||
|= =json
|
||||
^- (quip move _this)
|
||||
?> (team:title our.bol src.bol)
|
||||
(poke-sole-action (json-to-action json))
|
||||
::
|
||||
++ poke-sole-action
|
||||
|= act=sole-action
|
||||
^- (quip move _this)
|
||||
:: poke/peer need same wire
|
||||
::
|
||||
:_ this
|
||||
[bon.sta %poke / [our.bol %dojo] [%sole-action act]]~
|
||||
::
|
||||
++ diff-sole-effect
|
||||
|= [=wire fec=sole-effect]
|
||||
^- (quip move _this)
|
||||
:_ this
|
||||
[bon.sta %diff %json (effect-to-json fec)]~
|
||||
::
|
||||
++ bound
|
||||
|= [wir=wire success=? binding=binding:eyre]
|
||||
^- (quip move _this)
|
||||
[~ this]
|
||||
::
|
||||
++ poke-handle-http-request
|
||||
%- (require-authorization:app ost.bol move this)
|
||||
|= =inbound-request:eyre
|
||||
^- (quip move _this)
|
||||
::
|
||||
=+ request-line=(parse-request-line url.request.inbound-request)
|
||||
=/ name=@t
|
||||
=+ back-path=(flop site.request-line)
|
||||
?~ back-path
|
||||
''
|
||||
i.back-path
|
||||
?: =(name 'tile')
|
||||
[[ost.bol %http-response (js-response:app tile-js)]~ this]
|
||||
?+ site.request-line
|
||||
:_ this
|
||||
[ost.bol %http-response not-found:app]~
|
||||
::
|
||||
:: styling
|
||||
::
|
||||
[%'~soto' %css %index ~]
|
||||
:_ this
|
||||
[ost.bol %http-response (css-response:app style)]~
|
||||
::
|
||||
:: javascript
|
||||
::
|
||||
[%'~soto' %js %index ~]
|
||||
:_ this
|
||||
[ost.bol %http-response (js-response:app script)]~
|
||||
::
|
||||
:: images
|
||||
::
|
||||
[%'~soto' %img *]
|
||||
=/ img (as-octs:mimes:html (~(got by soto-png) `@ta`name))
|
||||
:_ this
|
||||
[ost.bol %http-response (png-response:app img)]~
|
||||
::
|
||||
:: index page
|
||||
::
|
||||
[%'~soto' *]
|
||||
:_ this
|
||||
[ost.bol %http-response (html-response:app index)]~
|
||||
==
|
||||
::
|
||||
--
|
1
pkg/arvo/app/soto/css/index.css
Normal file
1
pkg/arvo/app/soto/css/index.css
Normal file
File diff suppressed because one or more lines are too long
BIN
pkg/arvo/app/soto/img/Tile.png
Normal file
BIN
pkg/arvo/app/soto/img/Tile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
16
pkg/arvo/app/soto/index.html
Normal file
16
pkg/arvo/app/soto/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dojo</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||
<link rel="stylesheet" href="/~soto/css/index.css" />
|
||||
</head>
|
||||
<body class="bg-black">
|
||||
<div id="root" />
|
||||
<script src="/~/channel/channel.js"></script>
|
||||
<script src="/~modulo/session.js"></script>
|
||||
<script src="/~soto/js/index.js"></script>
|
||||
</body>
|
||||
</html>
|
1
pkg/arvo/app/soto/js/index.js
Normal file
1
pkg/arvo/app/soto/js/index.js
Normal file
File diff suppressed because one or more lines are too long
1
pkg/arvo/app/soto/js/tile.js
Normal file
1
pkg/arvo/app/soto/js/tile.js
Normal file
File diff suppressed because one or more lines are too long
9
pkg/arvo/gen/publish/subscribe.hoon
Normal file
9
pkg/arvo/gen/publish/subscribe.hoon
Normal file
@ -0,0 +1,9 @@
|
||||
:: subscribe to a publish notebook
|
||||
::
|
||||
:- %say
|
||||
|= $: [now=@da eny=@uvJ =beak]
|
||||
[[=ship name=term ~] ~]
|
||||
==
|
||||
:- %publish-action
|
||||
[%subscribe ship name]
|
||||
|
@ -118,6 +118,25 @@
|
||||
[%config (conf config.mailbox)]
|
||||
==
|
||||
::
|
||||
++ two-update-to-json
|
||||
|= upd=chat-two-update
|
||||
=, enjs:format
|
||||
^- json
|
||||
%+ frond %chat-update
|
||||
%- pairs
|
||||
:~
|
||||
?: =(%messages -.upd)
|
||||
?> ?=(%messages -.upd)
|
||||
:- %messages
|
||||
%- pairs
|
||||
:~ [%path (path path.upd)]
|
||||
[%start (numb start.upd)]
|
||||
[%end (numb end.upd)]
|
||||
[%envelopes [%a (turn envelopes.upd enve)]]
|
||||
==
|
||||
[*@t *^json]
|
||||
==
|
||||
::
|
||||
++ update-to-json
|
||||
|= upd=chat-update
|
||||
=, enjs:format
|
||||
@ -166,6 +185,7 @@
|
||||
:~ [%create create]
|
||||
[%delete delete]
|
||||
[%message message]
|
||||
[%messages messages]
|
||||
[%read read]
|
||||
==
|
||||
::
|
||||
@ -184,6 +204,12 @@
|
||||
[%envelope envelope]
|
||||
==
|
||||
::
|
||||
++ messages
|
||||
%- ot
|
||||
:~ [%path pa]
|
||||
[%envelopes (ar envelope)]
|
||||
==
|
||||
::
|
||||
++ read
|
||||
(ot [%path pa] ~)
|
||||
::
|
||||
@ -225,6 +251,7 @@
|
||||
[%security sec]
|
||||
[%read (as (su ;~(pfix sig fed:ag)))]
|
||||
[%write (as (su ;~(pfix sig fed:ag)))]
|
||||
[%allow-history bo]
|
||||
==
|
||||
::
|
||||
++ delete
|
||||
@ -234,11 +261,12 @@
|
||||
%- ot
|
||||
:~ [%ship (su ;~(pfix sig fed:ag))]
|
||||
[%path pa]
|
||||
[%ask-history bo]
|
||||
==
|
||||
::
|
||||
++ sec
|
||||
=, dejs:format
|
||||
^- $-(json chat-security)
|
||||
^- $-(json rw-security)
|
||||
(su (perk %channel %village %journal %mailbox ~))
|
||||
--
|
||||
--
|
||||
|
@ -111,6 +111,7 @@
|
||||
%chat-hook
|
||||
%chat-view
|
||||
%chat-cli
|
||||
%soto
|
||||
==
|
||||
::
|
||||
++ deft-fish :: default connects
|
||||
|
98
pkg/arvo/lib/soto.hoon
Normal file
98
pkg/arvo/lib/soto.hoon
Normal file
@ -0,0 +1,98 @@
|
||||
/+ *sole
|
||||
::
|
||||
::TODO revert after #1946
|
||||
::
|
||||
|%
|
||||
::
|
||||
++ json-to-action
|
||||
|= jon=json ^- sole-action
|
||||
%- need %. jon
|
||||
=> [dejs-soft:format ..sole-action]
|
||||
|^ (fo %ret (of det+change tab+ni ~))
|
||||
++ fo
|
||||
|* [a=term b=fist]
|
||||
|=(c=json ?.(=([%s a] c) (b c) (some [a ~])))
|
||||
::
|
||||
++ ra
|
||||
|* [a=[term fist] b=fist]
|
||||
|= c=json %. c
|
||||
?.(=(%a -.c) b (pe -.a (ar +.a)))
|
||||
::
|
||||
++ ke :: callbacks
|
||||
|* [gar=* sef=(trap fist)]
|
||||
|= jon=json ^- (unit _gar)
|
||||
=- ~! gar ~! (need -) -
|
||||
((sef) jon)
|
||||
::
|
||||
++ change (ot ler+(at ni ni ~) ted+(pe 0v0 edit) ~)
|
||||
++ char (cu taft so)
|
||||
++ edit
|
||||
%+ ke *sole-edit |. ~+
|
||||
%+ fo %nop
|
||||
%+ ra mor+edit
|
||||
(of del+ni set+(cu tuba sa) ins+(ot at+ni cha+char ~) ~)
|
||||
--
|
||||
::
|
||||
++ effect-to-json
|
||||
|= sef=sole-effect
|
||||
|^ ^- json
|
||||
=, enjs:format
|
||||
?+ -.sef
|
||||
~|(unsupported-effect+-.sef !!)
|
||||
$mor [%a (turn p.sef |=(a/sole-effect ^$(sef a)))]
|
||||
$err (frond %hop (numb p.sef))
|
||||
$txt (frond %txt (tape p.sef))
|
||||
$tan (frond %tan (tape (wush 160 p.sef)))
|
||||
$det (frond %det json:~(grow mar-sole-change +.sef))
|
||||
::
|
||||
$pro
|
||||
%+ frond %pro
|
||||
(pairs vis+b+vis.sef tag+s+tag.sef cad+(tape (purge cad.sef)) ~)
|
||||
::
|
||||
$tab
|
||||
:- %a
|
||||
%+ turn p.sef
|
||||
|= [=cord =^tank]
|
||||
%- pairs
|
||||
:~ match+s+cord
|
||||
info+(tape ~(ram re tank))
|
||||
==
|
||||
::
|
||||
?($bel $clr $nex)
|
||||
(frond %act %s -.sef)
|
||||
==
|
||||
++ mar-sole-change
|
||||
|_ cha=sole-change
|
||||
++ grow
|
||||
|% ++ json
|
||||
^- ^json
|
||||
=, enjs:format
|
||||
=; edi
|
||||
=,(cha (pairs ted+(edi ted) ler+a+~[(numb own.ler) (numb his.ler)] ~))
|
||||
|= det=sole-edit
|
||||
?- -.det
|
||||
$nop [%s 'nop']
|
||||
$mor [%a (turn p.det ..$)]
|
||||
$del (frond %del (numb p.det))
|
||||
$set (frond %set (tape (tufa p.det)))
|
||||
$ins (frond %ins (pairs at+(numb p.det) cha+s+(tuft q.det) ~))
|
||||
==
|
||||
--
|
||||
--
|
||||
++ wush
|
||||
|= [wid=@u tan=tang]
|
||||
^- tape
|
||||
%- of-wall:format
|
||||
%+ turn (flop tan)
|
||||
|= =tank
|
||||
~! wid
|
||||
~! tank
|
||||
(of-wall:format (wash 0^wid tank))
|
||||
::
|
||||
++ purge
|
||||
|= a=styx ^- tape
|
||||
%- zing %+ turn a
|
||||
|= a=_?>(?=(^ a) i.a)
|
||||
?@(a (trip a) ^$(a q.a))
|
||||
--
|
||||
--
|
@ -20,16 +20,18 @@
|
||||
%- ot
|
||||
:~ [%path pa]
|
||||
[%security sec]
|
||||
[%allow-history bo]
|
||||
==
|
||||
::
|
||||
++ add-synced
|
||||
%- ot
|
||||
:~ [%ship (su ;~(pfix sig fed:ag))]
|
||||
[%path pa]
|
||||
[%ask-history bo]
|
||||
==
|
||||
::
|
||||
++ sec
|
||||
^- $-(^json chat-security)
|
||||
^- $-(^json rw-security)
|
||||
(su (perk %channel %village %journal %mailbox ~))
|
||||
::
|
||||
--
|
||||
|
13
pkg/arvo/mar/chat/two-update.hoon
Normal file
13
pkg/arvo/mar/chat/two-update.hoon
Normal file
@ -0,0 +1,13 @@
|
||||
/+ *chat-json
|
||||
|_ upd=chat-two-update
|
||||
++ grow
|
||||
|%
|
||||
++ json (two-update-to-json upd)
|
||||
--
|
||||
::
|
||||
++ grab
|
||||
|%
|
||||
++ noun chat-two-update
|
||||
--
|
||||
::
|
||||
--
|
@ -15,7 +15,7 @@
|
||||
|= jon/^json ^- sole-action
|
||||
%- need %. jon
|
||||
=> [dejs-soft:format ..sole-action]
|
||||
|^ (fo %ret (of det+change ~))
|
||||
|^ (fo %ret (of det+change tab+ni ~))
|
||||
++ fo
|
||||
|* {a/term b/fist}
|
||||
|=(c/json ?.(=([%s a] c) (b c) (some [a ~])))
|
||||
|
@ -63,6 +63,15 @@
|
||||
$pro
|
||||
%+ frond %pro
|
||||
(pairs vis+b+vis.sef tag+s+tag.sef cad+(tape (purge cad.sef)) ~)
|
||||
::
|
||||
$tab
|
||||
:- %a
|
||||
%+ turn p.sef
|
||||
|= [=cord =^tank]
|
||||
%- pairs
|
||||
:~ match+s+cord
|
||||
info+(tape ~(ram re tank))
|
||||
==
|
||||
::
|
||||
?($bel $clr $nex)
|
||||
(frond %act %s -.sef)
|
||||
|
@ -1,23 +1,16 @@
|
||||
/- *rw-security
|
||||
|%
|
||||
+$ chat-security
|
||||
$? $channel :: black r, black w
|
||||
$village :: white r, white w
|
||||
$journal :: black r, white w
|
||||
$mailbox :: white r, black w
|
||||
==
|
||||
::
|
||||
+$ chat-hook-action
|
||||
$% :: %add-owned: make a chatroom accessible to foreign ships
|
||||
:: specified by the chat-security model
|
||||
:: specified by the rw-security model
|
||||
::
|
||||
[%add-owned =path security=chat-security]
|
||||
[%add-owned =path security=rw-security allow-history=?]
|
||||
:: %add-synced: mirror a foreign chatroom to our chat-store
|
||||
::
|
||||
[%add-synced =ship =path]
|
||||
[%add-synced =ship =path ask-history=?]
|
||||
:: %remove: stop mirroring a foreign chatroom or allowing a local
|
||||
:: chatroom to be mirrored
|
||||
::
|
||||
[%remove =path]
|
||||
==
|
||||
--
|
||||
|
||||
|
@ -30,16 +30,26 @@
|
||||
::
|
||||
+$ chat-configs (map path config)
|
||||
::
|
||||
+$ chat-action
|
||||
+$ chat-base
|
||||
$% [%create =ship =path] :: %create: create a mailbox at ~ship/path
|
||||
[%delete =path] :: %delete: delete a mailbox at path
|
||||
[%message =path =envelope] :: %message: append a message to mailbox
|
||||
[%read =path] :: %read: set mailbox to read
|
||||
==
|
||||
::
|
||||
+$ chat-action
|
||||
$% :: %messages: append a list of messages to mailbox
|
||||
::
|
||||
[%messages =path envelopes=(list envelope)]
|
||||
chat-base
|
||||
==
|
||||
::
|
||||
+$ chat-update
|
||||
$% [%keys keys=(set path)]
|
||||
[%config =path =config]
|
||||
chat-action
|
||||
chat-base
|
||||
==
|
||||
::
|
||||
+$ chat-two-update
|
||||
[%messages =path start=@ud end=@ud envelopes=(list envelope)]
|
||||
--
|
||||
|
@ -1,14 +1,14 @@
|
||||
/- *rw-security
|
||||
|%
|
||||
+$ chat-security
|
||||
$? $channel :: black r, black w
|
||||
$village :: white r, white w
|
||||
$journal :: black r, white w
|
||||
$mailbox :: white r, black w
|
||||
==
|
||||
::
|
||||
+$ chat-view-action
|
||||
$% [%create =path security=chat-security read=(set ship) write=(set ship)]
|
||||
$% $: %create
|
||||
=path
|
||||
security=rw-security
|
||||
read=(set ship)
|
||||
write=(set ship)
|
||||
allow-history=?
|
||||
==
|
||||
[%delete =path]
|
||||
[%join =ship =path]
|
||||
[%join =ship =path ask-history=?]
|
||||
==
|
||||
--
|
||||
|
8
pkg/arvo/sur/rw-security.hoon
Normal file
8
pkg/arvo/sur/rw-security.hoon
Normal file
@ -0,0 +1,8 @@
|
||||
|%
|
||||
+$ rw-security
|
||||
$? $channel :: black r, black w
|
||||
$village :: white r, white w
|
||||
$journal :: black r, white w
|
||||
$mailbox :: white r, black w
|
||||
==
|
||||
--
|
@ -6124,47 +6124,54 @@
|
||||
==
|
||||
++ royl
|
||||
~+
|
||||
=+ ^= moo
|
||||
|= a/tape
|
||||
;~ pose
|
||||
(stag %rh royl-rh)
|
||||
(stag %rq royl-rq)
|
||||
(stag %rd royl-rd)
|
||||
(stag %rs royl-rs)
|
||||
==
|
||||
::
|
||||
++ royl-rh (cook rylh ;~(pfix ;~(plug sig sig) (cook royl-cell royl-rn)))
|
||||
++ royl-rq (cook rylq ;~(pfix ;~(plug sig sig sig) (cook royl-cell royl-rn)))
|
||||
++ royl-rd (cook ryld ;~(pfix sig (cook royl-cell royl-rn)))
|
||||
++ royl-rs (cook ryls (cook royl-cell royl-rn))
|
||||
::
|
||||
++ royl-rn
|
||||
=/ moo
|
||||
|= a=tape
|
||||
:- (lent a)
|
||||
(scan a (bass 10 (plus sid:ab)))
|
||||
=+ ^= voy
|
||||
%+ cook royl-cell
|
||||
;~ pose
|
||||
;~ plug
|
||||
(easy %d)
|
||||
;~ pose (cold | hep) (easy &) ==
|
||||
;~ plug dim:ag
|
||||
;~ pose
|
||||
;~(pfix dot (cook moo (plus (shim '0' '9'))))
|
||||
(easy [0 0])
|
||||
==
|
||||
;~ pose
|
||||
;~ pfix
|
||||
(just 'e')
|
||||
;~(plug ;~(pose (cold | hep) (easy &)) dim:ag)
|
||||
==
|
||||
(easy [& 0])
|
||||
==
|
||||
;~ pose
|
||||
;~ plug
|
||||
(easy %d)
|
||||
;~(pose (cold | hep) (easy &))
|
||||
;~ plug dim:ag
|
||||
;~ pose
|
||||
;~(pfix dot (cook moo (plus (shim '0' '9'))))
|
||||
(easy [0 0])
|
||||
==
|
||||
==
|
||||
;~ plug
|
||||
(easy %i)
|
||||
;~ sfix
|
||||
;~ pose (cold | hep) (easy &) ==
|
||||
(jest 'inf')
|
||||
;~ pose
|
||||
;~ pfix
|
||||
(just 'e')
|
||||
;~(plug ;~(pose (cold | hep) (easy &)) dim:ag)
|
||||
==
|
||||
(easy [& 0])
|
||||
==
|
||||
==
|
||||
;~ plug
|
||||
(easy %n)
|
||||
(cold ~ (jest 'nan'))
|
||||
==
|
||||
==
|
||||
;~ pose
|
||||
(stag %rh (cook rylh ;~(pfix ;~(plug sig sig) voy)))
|
||||
(stag %rq (cook rylq ;~(pfix ;~(plug sig sig sig) voy)))
|
||||
(stag %rd (cook ryld ;~(pfix sig voy)))
|
||||
(stag %rs (cook ryls voy))
|
||||
::
|
||||
;~ plug
|
||||
(easy %i)
|
||||
;~ sfix
|
||||
;~(pose (cold | hep) (easy &))
|
||||
(jest 'inf')
|
||||
==
|
||||
==
|
||||
::
|
||||
;~ plug
|
||||
(easy %n)
|
||||
(cold ~ (jest 'nan'))
|
||||
==
|
||||
==
|
||||
::
|
||||
++ royl-cell
|
||||
|
@ -7,15 +7,16 @@
|
||||
:: or classes).
|
||||
::
|
||||
:: each of these stages is split into cores for each of
|
||||
:: arvo's eight major vanes (kernel modules). these are:
|
||||
:: arvo's nine major vanes (kernel modules). these are:
|
||||
::
|
||||
:: - %ames: networking (rhymes with "games")
|
||||
:: - %behn: scheduling ("bane")
|
||||
:: - %clay: revision control ("play")
|
||||
:: - %dill: console ("pill")
|
||||
:: - %eyre: web ("fair")
|
||||
:: - %eyre: http server ("fair")
|
||||
:: - %ford: build ("lord")
|
||||
:: - %gall: application ("ball")
|
||||
:: - %iris: http client ("virus")
|
||||
:: - %jael: security ("jail")
|
||||
::
|
||||
:: with %zuse in your core, the engines of any vane are
|
||||
|
@ -14,6 +14,10 @@ textarea, input, button {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
-webkit-appearance: checkbox;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000 !important;
|
||||
font-weight: 400 !important;
|
||||
|
@ -128,10 +128,11 @@ class UrbitApi {
|
||||
this.action("chat-view", "json", data);
|
||||
}
|
||||
|
||||
chatViewCreate(path, security, read, write) {
|
||||
chatViewCreate(path, security, read, write, allowHistory) {
|
||||
this.chatViewAction({
|
||||
create: {
|
||||
path, security, read, write
|
||||
path, security, read, write,
|
||||
'allow-history': allowHistory
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -140,8 +141,13 @@ class UrbitApi {
|
||||
this.chatViewAction({ delete: { path } });
|
||||
}
|
||||
|
||||
chatViewJoin(ship, path) {
|
||||
this.chatViewAction({ join: { ship, path } });
|
||||
chatViewJoin(ship, path, askHistory) {
|
||||
this.chatViewAction({
|
||||
join: {
|
||||
ship, path,
|
||||
'ask-history': askHistory
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
inviteAction(data) {
|
||||
|
@ -67,7 +67,7 @@ export class ChatScreen extends Component {
|
||||
|
||||
updateReadNumber() {
|
||||
const { props, state } = this;
|
||||
if (props.read < props.envelopes.length) {
|
||||
if (props.read < props.length) {
|
||||
props.api.chat.read(state.station);
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,8 @@ export class JoinScreen extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
props.api.chatView.join(ship, station);
|
||||
// TODO: askHistory setting
|
||||
props.api.chatView.join(ship, station, true);
|
||||
this.props.history.push('/~chat');
|
||||
}
|
||||
|
||||
|
@ -26,19 +26,21 @@ export class ChatInput extends Component {
|
||||
|
||||
// perf testing:
|
||||
/*let closure = () => {
|
||||
let x = 0;
|
||||
for (var i = 0; i < 30; i++) {
|
||||
x++;
|
||||
props.api.chat.message(
|
||||
props.station,
|
||||
`~${window.ship}`,
|
||||
Date.now(),
|
||||
{
|
||||
text: `${Date.now()}`
|
||||
text: `${x}`
|
||||
}
|
||||
);
|
||||
}
|
||||
setTimeout(closure, 1000);
|
||||
};
|
||||
setTimeout(closure, 2000);*/
|
||||
this.closure = closure.bind(this);*/
|
||||
|
||||
moment.updateLocale('en', {
|
||||
relativeTime : {
|
||||
@ -144,6 +146,7 @@ export class ChatInput extends Component {
|
||||
Date.now(),
|
||||
letter
|
||||
);
|
||||
// perf: setTimeout(this.closure, 2000);
|
||||
|
||||
this.setState({
|
||||
message: '',
|
||||
|
@ -14,12 +14,14 @@ export class NewScreen extends Component {
|
||||
invites: '',
|
||||
security: 'village',
|
||||
idError: false,
|
||||
inviteError: false
|
||||
inviteError: false,
|
||||
allowHistory: true
|
||||
};
|
||||
|
||||
this.idChange = this.idChange.bind(this);
|
||||
this.invChange = this.invChange.bind(this);
|
||||
this.securityChange = this.securityChange.bind(this);
|
||||
this.allowHistoryChange = this.allowHistoryChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
@ -47,6 +49,10 @@ export class NewScreen extends Component {
|
||||
this.setState({security: event.target.value});
|
||||
}
|
||||
|
||||
allowHistoryChange(event) {
|
||||
this.setState({allowHistory: !!event.target.checked});
|
||||
}
|
||||
|
||||
onClickCreate() {
|
||||
const { props, state } = this;
|
||||
if (!state.idName) {
|
||||
@ -114,14 +120,15 @@ export class NewScreen extends Component {
|
||||
readAud = aud.slice(); // white list
|
||||
writeAud = []; // black list
|
||||
}
|
||||
|
||||
this.setState({
|
||||
error: false,
|
||||
success: true,
|
||||
invites: ''
|
||||
}, () => {
|
||||
props.setSpinner(true);
|
||||
props.api.chatView.create(station, state.security, readAud, writeAud);
|
||||
props.api.chatView.create(
|
||||
station, state.security, readAud, writeAud, state.allowHistory
|
||||
);
|
||||
aud.forEach((ship) => {
|
||||
if (ship !== `~${window.ship}`) {
|
||||
props.api.invite.invite(station, ship);
|
||||
@ -194,6 +201,18 @@ export class NewScreen extends Component {
|
||||
<option value="journal">Journal</option>
|
||||
<option value="mailbox">Mailbox</option>
|
||||
</select>
|
||||
<p className="body-medium mt3 db">Chat History</p>
|
||||
<div className="db mt2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={this.state.allowHistory}
|
||||
onChange={this.allowHistoryChange.bind(this)}
|
||||
className="dib mr2"
|
||||
/>
|
||||
<p className="body-small db mt2 mb3 dib">
|
||||
Allow participants to download the chat history upon joining.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={this.onClickCreate.bind(this)}
|
||||
className={createClasses}
|
||||
|
@ -44,7 +44,8 @@ export class Root extends Component {
|
||||
messagePreviews[stat] = envelopes[envelopes.length - 1];
|
||||
}
|
||||
|
||||
unreads[stat] = envelopes.length > state.inbox[stat].config.read;
|
||||
unreads[stat] =
|
||||
state.inbox[stat].config.length > state.inbox[stat].config.read;
|
||||
});
|
||||
|
||||
let invites = '/chat' in state.invites ?
|
||||
@ -113,7 +114,7 @@ export class Root extends Component {
|
||||
`/${props.match.params.ship}/${props.match.params.station}`;
|
||||
let mailbox = state.inbox[station] || {
|
||||
config: {
|
||||
read: -1,
|
||||
read: 0,
|
||||
length: 0
|
||||
},
|
||||
envelopes: []
|
||||
@ -127,6 +128,7 @@ export class Root extends Component {
|
||||
api={api}
|
||||
subscription={subscription}
|
||||
read={mailbox.config.read}
|
||||
length={mailbox.config.length}
|
||||
envelopes={mailbox.envelopes}
|
||||
inbox={state.inbox}
|
||||
group={write}
|
||||
|
@ -18,15 +18,18 @@ export class ChatUpdateReducer {
|
||||
let data = _.get(json, 'message', false);
|
||||
if (data) {
|
||||
state.inbox[data.path].envelopes.push(data.envelope);
|
||||
state.inbox[data.path].config.length
|
||||
= state.inbox[data.path].config.length + 1;
|
||||
}
|
||||
}
|
||||
|
||||
messages(json, state) {
|
||||
let data = _.get(json, 'messages', false);
|
||||
if (data) {
|
||||
console.log(data);
|
||||
state.inbox[data.path].envelopes =
|
||||
data.envelopes.concat(state.inbox[data.path].envelopes);
|
||||
state.inbox[data.path].config.length =
|
||||
state.inbox[data.path].config.length + data.envelopes.length;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +37,7 @@ export class ChatUpdateReducer {
|
||||
let data = _.get(json, 'read', false);
|
||||
if (data) {
|
||||
state.inbox[data.path].config.read =
|
||||
state.inbox[data.path].envelopes.length;
|
||||
state.inbox[data.path].config.length;
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,8 +47,8 @@ export class ChatUpdateReducer {
|
||||
state.inbox[`/~${data.ship}${data.path}`] = {
|
||||
envelopes: [],
|
||||
config: {
|
||||
read:0,
|
||||
length: 0,
|
||||
read: 0,
|
||||
length: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
186
pkg/interface/soto/gulpfile.js
Normal file
186
pkg/interface/soto/gulpfile.js
Normal file
@ -0,0 +1,186 @@
|
||||
var gulp = require('gulp');
|
||||
var cssimport = require('gulp-cssimport');
|
||||
var rollup = require('gulp-better-rollup');
|
||||
var cssnano = require('cssnano');
|
||||
var postcss = require('gulp-postcss');
|
||||
var sucrase = require('@sucrase/gulp-plugin');
|
||||
var minify = require('gulp-minify');
|
||||
var rename = require('gulp-rename');
|
||||
var del = require('del');
|
||||
|
||||
var resolve = require('rollup-plugin-node-resolve');
|
||||
var commonjs = require('rollup-plugin-commonjs');
|
||||
var rootImport = require('rollup-plugin-root-import');
|
||||
var globals = require('rollup-plugin-node-globals');
|
||||
|
||||
|
||||
/***
|
||||
Main config options
|
||||
***/
|
||||
|
||||
var urbitrc = require('../urbitrc');
|
||||
|
||||
/***
|
||||
End main config options
|
||||
***/
|
||||
|
||||
gulp.task('css-bundle', function() {
|
||||
let plugins = [
|
||||
cssnano()
|
||||
];
|
||||
return gulp
|
||||
.src('src/index.css')
|
||||
.pipe(cssimport())
|
||||
.pipe(postcss(plugins))
|
||||
.pipe(gulp.dest('../../arvo/app/soto/css'));
|
||||
});
|
||||
|
||||
gulp.task('jsx-transform', function(cb) {
|
||||
return gulp.src('src/**/*.js')
|
||||
.pipe(sucrase({
|
||||
transforms: ['jsx']
|
||||
}))
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('tile-jsx-transform', function(cb) {
|
||||
return gulp.src('tile/**/*.js')
|
||||
.pipe(sucrase({
|
||||
transforms: ['jsx']
|
||||
}))
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('js-imports', function(cb) {
|
||||
return gulp.src('dist/index.js')
|
||||
.pipe(rollup({
|
||||
plugins: [
|
||||
commonjs({
|
||||
namedExports: {
|
||||
'node_modules/react/index.js': [ 'Component' ],
|
||||
'node_modules/react-is/index.js': [ 'isValidElementType' ],
|
||||
}
|
||||
}),
|
||||
rootImport({
|
||||
root: `${__dirname}/dist/js`,
|
||||
useEntry: 'prepend',
|
||||
extensions: '.js'
|
||||
}),
|
||||
globals(),
|
||||
resolve()
|
||||
]
|
||||
}, 'umd'))
|
||||
.on('error', function(e){
|
||||
console.log(e);
|
||||
cb();
|
||||
})
|
||||
.pipe(gulp.dest('../../arvo/app/soto/js/'))
|
||||
.on('end', cb);
|
||||
});
|
||||
|
||||
gulp.task('tile-js-imports', function(cb) {
|
||||
return gulp.src('dist/tile.js')
|
||||
.pipe(rollup({
|
||||
plugins: [
|
||||
commonjs({
|
||||
namedExports: {
|
||||
'node_modules/react/index.js': [ 'Component' ],
|
||||
}
|
||||
}),
|
||||
rootImport({
|
||||
root: `${__dirname}/dist/js`,
|
||||
useEntry: 'prepend',
|
||||
extensions: '.js'
|
||||
}),
|
||||
globals(),
|
||||
resolve()
|
||||
]
|
||||
}, 'umd'))
|
||||
.on('error', function(e){
|
||||
console.log(e);
|
||||
cb();
|
||||
})
|
||||
.pipe(gulp.dest('../../arvo/app/soto/js/'))
|
||||
.on('end', cb);
|
||||
});
|
||||
|
||||
|
||||
gulp.task('js-minify', function () {
|
||||
return gulp.src('../../arvo/app/soto/js/index.js')
|
||||
.pipe(minify())
|
||||
.pipe(gulp.dest('../../arvo/app/soto/js/'));
|
||||
});
|
||||
|
||||
gulp.task('tile-js-minify', function () {
|
||||
return gulp.src('../../arvo/app/soto/js/tile.js')
|
||||
.pipe(minify())
|
||||
.pipe(gulp.dest('../../arvo/app/soto/js/'));
|
||||
});
|
||||
|
||||
gulp.task('rename-index-min', function () {
|
||||
return gulp.src('../../arvo/app/soto/js/index-min.js')
|
||||
.pipe(rename('index.js'))
|
||||
.pipe(gulp.dest('../../arvo/app/soto/js/'))
|
||||
});
|
||||
|
||||
gulp.task('rename-tile-min', function () {
|
||||
return gulp.src('../../arvo/app/soto/js/tile-min.js')
|
||||
.pipe(rename('tile.js'))
|
||||
.pipe(gulp.dest('../../arvo/app/soto/js/'))
|
||||
});
|
||||
|
||||
gulp.task('clean-min', function () {
|
||||
return del(['../../arvo/app/soto/js/index-min.js', '../../arvo/app/soto/js/tile-min.js'], { force: true })
|
||||
});
|
||||
|
||||
gulp.task('urbit-copy', function () {
|
||||
let ret = gulp.src('../../arvo/**/*');
|
||||
|
||||
urbitrc.URBIT_PIERS.forEach(function(pier) {
|
||||
ret = ret.pipe(gulp.dest(pier));
|
||||
});
|
||||
|
||||
return ret;
|
||||
});
|
||||
|
||||
gulp.task('js-bundle-dev', gulp.series('jsx-transform', 'js-imports'));
|
||||
gulp.task('tile-js-bundle-dev', gulp.series('tile-jsx-transform', 'tile-js-imports'));
|
||||
gulp.task('js-bundle-prod', gulp.series('jsx-transform', 'js-imports', 'js-minify'))
|
||||
gulp.task('tile-js-bundle-prod',
|
||||
gulp.series('tile-jsx-transform', 'tile-js-imports', 'tile-js-minify'));
|
||||
|
||||
gulp.task('bundle-dev',
|
||||
gulp.series(
|
||||
gulp.parallel(
|
||||
'css-bundle',
|
||||
'js-bundle-dev',
|
||||
'tile-js-bundle-dev'
|
||||
),
|
||||
'urbit-copy'
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task('bundle-prod',
|
||||
gulp.series(
|
||||
gulp.parallel(
|
||||
'css-bundle',
|
||||
'js-bundle-prod',
|
||||
'tile-js-bundle-prod',
|
||||
),
|
||||
'rename-index-min',
|
||||
'rename-tile-min',
|
||||
'clean-min',
|
||||
'urbit-copy'
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task('default', gulp.series('bundle-dev'));
|
||||
|
||||
gulp.task('watch', gulp.series('default', function() {
|
||||
gulp.watch('tile/**/*.js', gulp.parallel('tile-js-bundle-dev'));
|
||||
|
||||
gulp.watch('src/**/*.js', gulp.parallel('js-bundle-dev'));
|
||||
gulp.watch('src/**/*.css', gulp.parallel('css-bundle'));
|
||||
|
||||
gulp.watch('../../arvo/**/*', gulp.parallel('urbit-copy'));
|
||||
}));
|
5900
pkg/interface/soto/package-lock.json
generated
Normal file
5900
pkg/interface/soto/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
pkg/interface/soto/package.json
Normal file
42
pkg/interface/soto/package.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "soto",
|
||||
"version": "1.0.0",
|
||||
"description": "Dojo relay for Urbit.",
|
||||
"scripts": {
|
||||
"build": "gulp",
|
||||
"serve": "gulp watch"
|
||||
},
|
||||
"author": "Tlon Corp",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/urbit/urbit",
|
||||
"devDependencies": {
|
||||
"@sucrase/gulp-plugin": "^2.0.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-better-rollup": "^4.0.1",
|
||||
"gulp-cssimport": "^7.0.0",
|
||||
"gulp-minify": "^3.1.0",
|
||||
"gulp-postcss": "^8.0.0",
|
||||
"gulp-rename": "^1.4.0",
|
||||
"rollup": "^1.6.0",
|
||||
"rollup-plugin-commonjs": "^9.2.0",
|
||||
"rollup-plugin-node-globals": "^1.4.0",
|
||||
"rollup-plugin-node-resolve": "^4.0.0",
|
||||
"rollup-plugin-root-import": "^0.2.3",
|
||||
"sucrase": "^3.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.6",
|
||||
"del": "^5.1.0",
|
||||
"lodash": "^4.17.11",
|
||||
"moment": "^2.20.1",
|
||||
"mousetrap": "^1.6.3",
|
||||
"react": "^16.5.2",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"urbit-ob": "^4.1.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"natives": "1.1.3"
|
||||
}
|
||||
}
|
45
pkg/interface/soto/src/css/custom.css
Normal file
45
pkg/interface/soto/src/css/custom.css
Normal file
@ -0,0 +1,45 @@
|
||||
p, input {
|
||||
margin-block-end: unset;
|
||||
margin-block-start: unset;
|
||||
-webkit-margin-before: unset;
|
||||
-webkit-margin-after: unset;
|
||||
font-family: "Source Code Pro", monospace;
|
||||
}
|
||||
|
||||
textarea, select, input, button {
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
border: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.body-regular {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.body-large {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.label-regular {
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.label-small-mono {
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
font-family: "Source Code Pro", monospace;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: "Source Code Pro", monospace;
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
}
|
63
pkg/interface/soto/src/css/fonts.css
Normal file
63
pkg/interface/soto/src/css/fonts.css
Normal file
@ -0,0 +1,63 @@
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url("https://media.urbit.org/fonts/Inter-Regular.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: url("https://media.urbit.org/fonts/Inter-Italic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url("https://media.urbit.org/fonts/Inter-Bold.woff2") format("woff2");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: url("https://media.urbit.org/fonts/Inter-BoldItalic.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Code Pro";
|
||||
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-extralight.woff");
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Code Pro";
|
||||
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-light.woff");
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Code Pro";
|
||||
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-regular.woff");
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Code Pro";
|
||||
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-medium.woff");
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Code Pro";
|
||||
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-semibold.woff");
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Code Pro";
|
||||
src: url("https://storage.googleapis.com/media.urbit.org/fonts/scp-bold.woff");
|
||||
font-weight: 700;
|
||||
}
|
||||
|
2843
pkg/interface/soto/src/css/indigo-static.css
Normal file
2843
pkg/interface/soto/src/css/indigo-static.css
Normal file
File diff suppressed because it is too large
Load Diff
38
pkg/interface/soto/src/css/spinner.css
Normal file
38
pkg/interface/soto/src/css/spinner.css
Normal file
@ -0,0 +1,38 @@
|
||||
.spinner-pending {
|
||||
position: relative;
|
||||
content: "";
|
||||
border-radius: 100%;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
|
||||
background-color: rgba(255,255,255,1);
|
||||
}
|
||||
|
||||
.spinner-pending::after {
|
||||
content: "";
|
||||
background-color: rgba(128,128,128,1);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
border-radius: 100%;
|
||||
clip: rect(0, 16px, 16px, 8px);
|
||||
|
||||
animation: spin 1s cubic-bezier(0.745, 0.045, 0.355, 1.000) infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {transform:rotate(0deg)}
|
||||
25% {transform:rotate(90deg)}
|
||||
50% {transform:rotate(180deg)}
|
||||
75% {transform:rotate(270deg)}
|
||||
100% {transform:rotate(360deg)}
|
||||
}
|
||||
|
||||
.spinner-nostart {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 100%;
|
||||
content:'';
|
||||
background-color: black;
|
||||
}
|
||||
|
5
pkg/interface/soto/src/index.css
Normal file
5
pkg/interface/soto/src/index.css
Normal file
@ -0,0 +1,5 @@
|
||||
@import 'css/indigo-static.css';
|
||||
@import 'css/fonts.css';
|
||||
@import 'css/spinner.css';
|
||||
@import 'css/custom.css';
|
||||
|
15
pkg/interface/soto/src/index.js
Normal file
15
pkg/interface/soto/src/index.js
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Root } from '/components/root';
|
||||
import { api } from '/api';
|
||||
import { subscription } from "/subscription";
|
||||
|
||||
api.setAuthTokens({
|
||||
ship: window.ship
|
||||
});
|
||||
|
||||
subscription.start();
|
||||
|
||||
ReactDOM.render((
|
||||
<Root />
|
||||
), document.querySelectorAll("#root")[0]);
|
49
pkg/interface/soto/src/js/api.js
Normal file
49
pkg/interface/soto/src/js/api.js
Normal file
@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import _ from 'lodash';
|
||||
|
||||
class UrbitApi {
|
||||
setAuthTokens(authTokens) {
|
||||
this.authTokens = authTokens;
|
||||
this.bindPaths = [];
|
||||
}
|
||||
|
||||
bind(path, method, ship = this.authTokens.ship, appl = "soto", success, fail) {
|
||||
this.bindPaths = _.uniq([...this.bindPaths, path]);
|
||||
|
||||
window.subscriptionId = window.urb.subscribe(ship, appl, path,
|
||||
(err) => {
|
||||
fail(err);
|
||||
},
|
||||
(event) => {
|
||||
success({
|
||||
data: event,
|
||||
from: {
|
||||
ship,
|
||||
path
|
||||
}
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
fail(err);
|
||||
});
|
||||
}
|
||||
|
||||
soto(data) {
|
||||
this.action("soto", "json", data); //TODO: revert after #1946
|
||||
}
|
||||
|
||||
action(appl, mark, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.urb.poke(ship, appl, mark, data,
|
||||
(json) => {
|
||||
resolve(json);
|
||||
},
|
||||
(err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
export let api = new UrbitApi();
|
||||
window.api = api;
|
22
pkg/interface/soto/src/js/components/history.js
Normal file
22
pkg/interface/soto/src/js/components/history.js
Normal file
@ -0,0 +1,22 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export class History extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="flex flex-column-reverse overflow-container"
|
||||
style={{ height: 'calc(100% - 1rem)', resize: 'vertical' }}>
|
||||
<div style={{ marginTop: 'auto'}}>
|
||||
{this.props.commandLog.map((text, index) => {
|
||||
return <p className="mono" key={index}>{text}</p>
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default History;
|
85
pkg/interface/soto/src/js/components/input.js
Normal file
85
pkg/interface/soto/src/js/components/input.js
Normal file
@ -0,0 +1,85 @@
|
||||
import React, { Component } from 'react';
|
||||
import { store } from '../store';
|
||||
import { api } from '../api';
|
||||
|
||||
export class Input extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.keyPress = this.keyPress.bind(this);
|
||||
this.inputRef = React.createRef();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.inputRef.current.setSelectionRange(this.props.cursor, this.props.cursor);
|
||||
}
|
||||
|
||||
keyPress = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
let ignoredKeys = ["Meta", "Alt", "Control", "Escape", "Shift",
|
||||
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8",
|
||||
"F9", "F10", "F11", "F12", "Backspace"
|
||||
];
|
||||
|
||||
// submit on enter
|
||||
if (e.key === "Enter") {
|
||||
api.soto("ret");
|
||||
}
|
||||
|
||||
else if ((e.key === "Backspace") && (this.props.cursor > 0)) {
|
||||
store.doEdit({ del: this.props.cursor - 1});
|
||||
return store.setState({ cursor: this.props.cursor - 1});
|
||||
}
|
||||
|
||||
else if (e.key.startsWith("Arrow")) {
|
||||
|
||||
if (e.key === "ArrowLeft") {
|
||||
if (this.props.cursor > 0) {
|
||||
store.setState({ cursor: this.props.cursor - 1 });
|
||||
}
|
||||
}
|
||||
|
||||
else if (e.key === "ArrowRight") {
|
||||
if (this.props.cursor < this.props.input.length) {
|
||||
store.setState({ cursor: this.props.cursor + 1});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// tab completion
|
||||
else if (e.key === "Tab") {
|
||||
api.soto({tab: this.props.cursor});
|
||||
}
|
||||
|
||||
// capture and transmit most characters
|
||||
else if (ignoredKeys.indexOf(e.key) === -1) {
|
||||
store.doEdit({ ins: { cha: e.key, at: this.props.cursor } });
|
||||
store.setState({ cursor: this.props.cursor + 1 });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="flex flex-row flex-grow-1">
|
||||
<div className="flex-shrink-0">~{this.props.ship}:dojo
|
||||
</div>
|
||||
<span id="prompt">
|
||||
{this.props.prompt}
|
||||
</span>
|
||||
<input
|
||||
autoCorrect="false"
|
||||
autoFocus={true}
|
||||
className="mono ml1 flex-auto dib w-100"
|
||||
cursor={this.props.cursor}
|
||||
onKeyDown={this.keyPress}
|
||||
onPaste={e => {e.preventDefault()}}
|
||||
ref={this.inputRef}
|
||||
defaultValue={this.props.input}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Input;
|
32
pkg/interface/soto/src/js/components/lib/header-bar.js
Normal file
32
pkg/interface/soto/src/js/components/lib/header-bar.js
Normal file
@ -0,0 +1,32 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { IconHome } from '/components/lib/icons/icon-home';
|
||||
import { IconSpinner } from '/components/lib/icons/icon-spinner';
|
||||
|
||||
export class HeaderBar extends Component {
|
||||
render() {
|
||||
let spin = (this.props.spinner)
|
||||
? <div className="absolute"
|
||||
style={{width: 16, height: 16, top: 16, right: 16}}>
|
||||
<IconSpinner/>
|
||||
</div>
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="bg-black w-100 justify-between b--gray0 bb"
|
||||
style={{ height: 48, padding: 8}}>
|
||||
<a className="db"
|
||||
style={{ background: '#1A1A1A',
|
||||
borderRadius: 16,
|
||||
width: 32,
|
||||
height: 32,
|
||||
top: 8 }}
|
||||
href='/'>
|
||||
<IconHome />
|
||||
</a>
|
||||
{spin}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export class IconHome extends Component {
|
||||
render() {
|
||||
return (
|
||||
<img src="/~launch/img/Home.png" width={32} height={32} />
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export class IconSpinner extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="spinner-pending"></div>
|
||||
);
|
||||
}
|
||||
}
|
136
pkg/interface/soto/src/js/components/lib/sole.js
Normal file
136
pkg/interface/soto/src/js/components/lib/sole.js
Normal file
@ -0,0 +1,136 @@
|
||||
// See /lib/sole/hoon
|
||||
|
||||
const str = JSON.stringify;
|
||||
|
||||
export class Share {
|
||||
constructor(buf, ven, leg) {
|
||||
if (buf == null) { buf = ""; }
|
||||
this.buf = buf;
|
||||
if (ven == null) { ven = [0, 0]; }
|
||||
this.ven = ven;
|
||||
if (leg == null) { leg = []; }
|
||||
this.leg = leg;
|
||||
}
|
||||
|
||||
abet() {
|
||||
return { buf:this.buf,
|
||||
leg:this.leg.slice(),
|
||||
ven:this.ven.slice()
|
||||
};
|
||||
}
|
||||
|
||||
apply(ted){
|
||||
switch (false) {
|
||||
case 'nop' !== ted: return;
|
||||
case !ted.map: return ted.map(this.apply, this);
|
||||
default: switch (Object.keys(ted)[0]) {
|
||||
case 'set': return this.buf = ted.set;
|
||||
case 'del': return this.buf = this.buf.slice(0,ted.del) + this.buf.slice(ted.del + 1);
|
||||
case 'ins':
|
||||
var { at, cha } = ted.ins;
|
||||
return this.buf = this.buf.slice(0,at) + cha + this.buf.slice(at);
|
||||
default: throw `%sole-edit -lost.${str(ted)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transmute(sin,dex){
|
||||
switch (false) {
|
||||
case (sin !== 'nop') && (dex !== 'nop'): return dex;
|
||||
case !sin.reduce:
|
||||
return sin.reduce(((dex,syn) => this.transmute(syn,dex)), dex);
|
||||
case !dex.map: return dex.map(dax => this.transmute(sin,dax));
|
||||
case dex.set === undefined: return dex;
|
||||
default: switch (Object.keys(sin)[0]) {
|
||||
case 'set': return 'nop';
|
||||
case 'del':
|
||||
if (sin.del === dex.del) { return 'nop'; }
|
||||
dex = { ...dex }
|
||||
switch (Object.keys(dex)[0]) {
|
||||
case 'del': if (sin.del < dex.del) { dex.del--; } break;
|
||||
case 'ins': if (sin.del < dex.ins.at) { dex.ins.at--; } break;
|
||||
}
|
||||
return dex;
|
||||
case 'ins':
|
||||
dex = { ...dex };
|
||||
var {at,cha} = sin.ins;
|
||||
switch (Object.keys(dex)[0]) {
|
||||
case 'del': if (at < dex.del) { dex.del++; } break;
|
||||
case 'ins': if ((at < dex.ins.at) ||
|
||||
((at === dex.ins.at) && !(cha <= dex.ins.cha))) {
|
||||
dex.ins.at++;
|
||||
} break;
|
||||
}
|
||||
return dex;
|
||||
default: throw `%sole-edit -lost.${str(sin)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commit(ted){
|
||||
this.ven[0]++;
|
||||
this.leg.push(ted);
|
||||
return this.apply(ted);
|
||||
}
|
||||
|
||||
inverse(ted){
|
||||
switch (false) {
|
||||
case 'nop' !== ted: return ted;
|
||||
case !ted.map:
|
||||
return ted.map( tad => {
|
||||
const res = this.inverse(tad);
|
||||
this.apply(tad);
|
||||
return res;
|
||||
}).reverse();
|
||||
default: switch (Object.keys(ted)[0]) {
|
||||
case 'set': return {set: this.buf};
|
||||
case 'ins': return {del: ted.ins};
|
||||
case 'del': return {ins: {at: ted.del, cha: this.buf[ted.del]}};
|
||||
default: throw `%sole-edit -lost.${str(ted)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
receive({ler,ted}){
|
||||
if (!(ler[1] === this.ven[1])) {
|
||||
throw `-out-of-sync.[${str(ler)} ${str(this.ven)}]`;
|
||||
}
|
||||
this.leg = this.leg.slice((this.leg.length + ler[0]) - this.ven[0]);
|
||||
const dat = this.transmute(this.leg, ted);
|
||||
this.ven[1]++;
|
||||
this.apply(dat);
|
||||
return dat;
|
||||
}
|
||||
|
||||
remit() {
|
||||
throw 'stub';
|
||||
}
|
||||
|
||||
transmit(ted){
|
||||
const act = {ted, ler:[this.ven[1], this.ven[0]]};
|
||||
this.commit(ted);
|
||||
return act;
|
||||
}
|
||||
|
||||
transceive({ler,ted}){
|
||||
const old = new Share(this.buf);
|
||||
const dat = this.receive({ler, ted});
|
||||
return old.inverse(dat);
|
||||
}
|
||||
|
||||
transpose(ted,pos){
|
||||
if (pos === undefined) {
|
||||
return this.transpose(this.leg, ted);
|
||||
}
|
||||
else {
|
||||
let left;
|
||||
return ((left =
|
||||
(this.transmute(
|
||||
ted, {ins: {at: pos}})).ins) != null ?
|
||||
left : { at:0 }
|
||||
).at;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default Share;
|
36
pkg/interface/soto/src/js/components/root.js
Normal file
36
pkg/interface/soto/src/js/components/root.js
Normal file
@ -0,0 +1,36 @@
|
||||
import React, { Component } from 'react';
|
||||
import { BrowserRouter, Route } from "react-router-dom";
|
||||
import classnames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import { HeaderBar } from './lib/header-bar';
|
||||
import { History } from './history';
|
||||
import { Input } from './input';
|
||||
import { api } from '../api';
|
||||
import { store } from '../store';
|
||||
|
||||
export class Root extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = store.state;
|
||||
store.setStateHandler(this.setState.bind(this));
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<div style={{height: "100vh"}}>
|
||||
<HeaderBar/>
|
||||
<Route exact path="/~soto" render={ () => {
|
||||
return (
|
||||
<div className="pa3 bg-black mono gray3 w-100"
|
||||
style={{lineHeight: "1.4", height: "calc(100% - 48px)", cursor: "text"}}>
|
||||
<History commandLog={this.state.txt}/>
|
||||
<Input ship={ship} cursor={this.state.cursor} prompt={this.state.prompt} input={this.state.input}/>
|
||||
</div>
|
||||
)}}
|
||||
/>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
}
|
84
pkg/interface/soto/src/js/store.js
Normal file
84
pkg/interface/soto/src/js/store.js
Normal file
@ -0,0 +1,84 @@
|
||||
import { Share } from './components/lib/sole';
|
||||
import { api } from './api';
|
||||
export const buffer = new Share;
|
||||
|
||||
|
||||
export class Store {
|
||||
constructor() {
|
||||
this.state = {
|
||||
txt: [],
|
||||
prompt: '',
|
||||
cursor: 0,
|
||||
input: ""
|
||||
}
|
||||
this.sync = this.sync.bind(this);
|
||||
this.print = this.print.bind(this);
|
||||
}
|
||||
|
||||
handleEvent(data) {
|
||||
// recursive handler
|
||||
if (data.data) {
|
||||
var dojoReply = data.data;
|
||||
} else {
|
||||
var dojoReply = data;
|
||||
}
|
||||
// %mor sole-effects are nested, so throw back to handler
|
||||
if (dojoReply.map) {
|
||||
return dojoReply.map(reply => this.handleEvent(reply));
|
||||
}
|
||||
switch(Object.keys(dojoReply)[0]) {
|
||||
case 'txt':
|
||||
return this.print(dojoReply.txt);
|
||||
case 'tab':
|
||||
for (let suggestion of dojoReply.tab) {
|
||||
let match = suggestion.match;
|
||||
let info = suggestion.info;
|
||||
this.print(match + " " + info);
|
||||
}
|
||||
return;
|
||||
case 'tan':
|
||||
return dojoReply.tan.split("\n").map(this.print);
|
||||
case 'pro':
|
||||
return this.setState({ prompt: dojoReply.pro.cad });
|
||||
case 'hop':
|
||||
return this.setState({ cursor: dojoReply.hop });
|
||||
case 'det':
|
||||
buffer.receive(dojoReply.det);
|
||||
return this.sync(dojoReply.det.ted);
|
||||
case 'act':
|
||||
switch(dojoReply.act) {
|
||||
case 'clr': return this.setState({txt: []});
|
||||
case 'nex': return this.setState({
|
||||
input: "",
|
||||
cursor: 0
|
||||
});
|
||||
} break;
|
||||
default: console.log(dojoReply);
|
||||
}
|
||||
}
|
||||
|
||||
doEdit(ted) {
|
||||
let detSend = buffer.transmit(ted);
|
||||
this.sync(ted);
|
||||
return api.soto({det: detSend});
|
||||
}
|
||||
|
||||
print(txt) {
|
||||
let textLog = this.state.txt;
|
||||
textLog.push(txt);
|
||||
return this.setState({ txt: textLog });
|
||||
}
|
||||
|
||||
sync(ted) {
|
||||
return this.setState({ input: buffer.buf,
|
||||
cursor: buffer.transpose(ted, this.state.cursor)
|
||||
});
|
||||
}
|
||||
|
||||
setStateHandler(setState) {
|
||||
this.setState = setState;
|
||||
}
|
||||
}
|
||||
|
||||
export let store = new Store();
|
||||
window.store = store;
|
32
pkg/interface/soto/src/js/subscription.js
Normal file
32
pkg/interface/soto/src/js/subscription.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { api } from './api';
|
||||
import { store } from './store';
|
||||
|
||||
|
||||
export class Subscription {
|
||||
start() {
|
||||
if (api.authTokens) {
|
||||
this.initializesoto();
|
||||
} else {
|
||||
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
|
||||
}
|
||||
}
|
||||
|
||||
initializesoto() {
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'soto',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
}
|
||||
|
||||
handleEvent(diff) {
|
||||
store.handleEvent(diff);
|
||||
}
|
||||
|
||||
handleError(err) {
|
||||
console.error(err);
|
||||
api.bind('/primary', 'PUT', api.authTokens.ship, 'soto',
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
export let subscription = new Subscription();
|
27
pkg/interface/soto/tile/tile.js
Normal file
27
pkg/interface/soto/tile/tile.js
Normal file
@ -0,0 +1,27 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
||||
export default class sotoTile extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="w-100 h-100 relative" style={{background: "#1a1a1a"}}>
|
||||
<a className="w-100 h-100 db no-underline" href="/~soto">
|
||||
<p className="gray label-regular b absolute"
|
||||
style={{ left: 8, top: 4 }}>
|
||||
Dojo
|
||||
</p>
|
||||
<img src="~soto/img/Tile.png"
|
||||
className="absolute"
|
||||
style={{ left: 30, top: 30, height: "174px", width: "174px"}}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.sotoTile = sotoTile;
|
Loading…
Reference in New Issue
Block a user