From cbdc19fc8eafb62132736ec7901583d552dd78d0 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Tue, 6 Dec 2016 15:04:41 +1300 Subject: [PATCH] Hacking --- examples/webchat/htdocs/style.css | 65 ++++-- .../htdocs/templates/contact-entry.html | 24 +++ .../webchat/htdocs/templates/mainpage.html | 100 +++++---- .../templates/my-permission-request.html | 2 - .../webchat/htdocs/templates/nav-account.html | 20 ++ .../htdocs/templates/option-question.html | 11 + .../templates/others-permission-request.html | 3 - .../permission-request-in-GENERIC.html | 3 + .../permission-request-in-p:follow.html | 3 + .../permission-request-out-GENERIC.html | 1 + .../permission-request-out-p:follow.html | 1 + .../htdocs/templates/present-entry.html | 1 - examples/webchat/htdocs/webchat.syndicate.js | 204 ++++++++++++++---- examples/webchat/server/account.rkt | 4 +- examples/webchat/server/api.rkt | 29 +-- examples/webchat/server/contacts.rkt | 83 +++++++ examples/webchat/server/conversation.rkt | 6 +- examples/webchat/server/duplicate.rkt | 17 ++ examples/webchat/server/main.rkt | 3 + examples/webchat/server/pages.rkt | 13 +- examples/webchat/server/protocol.rkt | 42 ++-- examples/webchat/server/qa.rkt | 43 ++++ examples/webchat/server/static-content.rkt | 3 +- examples/webchat/server/trust.rkt | 30 +-- 24 files changed, 538 insertions(+), 173 deletions(-) create mode 100644 examples/webchat/htdocs/templates/contact-entry.html delete mode 100644 examples/webchat/htdocs/templates/my-permission-request.html create mode 100644 examples/webchat/htdocs/templates/nav-account.html create mode 100644 examples/webchat/htdocs/templates/option-question.html delete mode 100644 examples/webchat/htdocs/templates/others-permission-request.html create mode 100644 examples/webchat/htdocs/templates/permission-request-in-GENERIC.html create mode 100644 examples/webchat/htdocs/templates/permission-request-in-p:follow.html create mode 100644 examples/webchat/htdocs/templates/permission-request-out-GENERIC.html create mode 100644 examples/webchat/htdocs/templates/permission-request-out-p:follow.html delete mode 100644 examples/webchat/htdocs/templates/present-entry.html create mode 100644 examples/webchat/server/contacts.rkt create mode 100644 examples/webchat/server/duplicate.rkt create mode 100644 examples/webchat/server/qa.rkt diff --git a/examples/webchat/htdocs/style.css b/examples/webchat/htdocs/style.css index 1986f8d..37c4bfc 100644 --- a/examples/webchat/htdocs/style.css +++ b/examples/webchat/htdocs/style.css @@ -2,20 +2,57 @@ template { display: none !important; } -span#request-count { - background: red; - color: white; - padding: 0em 0.25em; - border-radius: 4px; -} -span#request-count.count0 { - display: none; -} - -span#request-count-plural.count1 { - display: none; -} - img.avatar { border-radius: 24px; } + +/* --------------------------------------------------------------------------- */ + +.alert-count { + background: red; + color: white; + padding: 0em 0.25em; + border-radius: 4px; +} + +.hide-zero-count.count0 { + display: none; +} + +.show-only-zero-count { + display: none; +} +.show-only-zero-count.count0 { + display: inherit; +} + +.plural.count1 { + display: none; +} + +.contact-list-present-false { + opacity: 0.3; +} + +.align-right { text-align: right; } +.align-center { text-align: center; } + +.cursor-interactive { + cursor: pointer; +} + +.dropdown-marginal { + left: -1.1em; + display: inline-block; + width: 0px; + position: relative; +} + +.forcewrap { + word-wrap: break-word !important; + xhyphens: auto; +} + +.big-icon { + font-size: 1.75rem; +} diff --git a/examples/webchat/htdocs/templates/contact-entry.html b/examples/webchat/htdocs/templates/contact-entry.html new file mode 100644 index 0000000..d910656 --- /dev/null +++ b/examples/webchat/htdocs/templates/contact-entry.html @@ -0,0 +1,24 @@ + diff --git a/examples/webchat/htdocs/templates/mainpage.html b/examples/webchat/htdocs/templates/mainpage.html index 67ab707..6401e22 100644 --- a/examples/webchat/htdocs/templates/mainpage.html +++ b/examples/webchat/htdocs/templates/mainpage.html @@ -1,55 +1,79 @@ - -
-

My status

-

- - -

+

Add a new contact

+
+ + + + + +
-

Add a new contact

- - - - - +

Contact List

+
+
+
+
-

Who is online?

- +
+

New Conversation

+
+
+
+
+
+
+
+
+
+ +
+
+
+

+ Select a conversation from the column to the left, + or create a new conversation. +

+
+
+
-

Permissions I enjoy

+

Permissions I enjoy

    -

    Permissions I have granted to others

    +

    Permissions I have granted to others

      -
      -

      Requests I have made

      -
        - -

        Requests from others

        -
          +
          +

          Questions

          +

          There are no questions waiting for you to answer.

          +
          +
          +
          +
          +

          + + +

          +
          +

          All requests from others

          +
            +
            +
            + +
            +

            Requests I have made

            +

            You have no outstanding requests waiting for responses from others.

            +
              +
              + +
              +
              diff --git a/examples/webchat/htdocs/templates/my-permission-request.html b/examples/webchat/htdocs/templates/my-permission-request.html deleted file mode 100644 index 42d52c3..0000000 --- a/examples/webchat/htdocs/templates/my-permission-request.html +++ /dev/null @@ -1,2 +0,0 @@ -
            • {{issuer}} {{permission}} -
            • diff --git a/examples/webchat/htdocs/templates/nav-account.html b/examples/webchat/htdocs/templates/nav-account.html new file mode 100644 index 0000000..15e672e --- /dev/null +++ b/examples/webchat/htdocs/templates/nav-account.html @@ -0,0 +1,20 @@ + diff --git a/examples/webchat/htdocs/templates/option-question.html b/examples/webchat/htdocs/templates/option-question.html new file mode 100644 index 0000000..fa2dea4 --- /dev/null +++ b/examples/webchat/htdocs/templates/option-question.html @@ -0,0 +1,11 @@ +
              +
              +

              {{title}}

              + {{&blurb}} +
              + {{#options}} + + {{/options}} +
              +
              +
              diff --git a/examples/webchat/htdocs/templates/others-permission-request.html b/examples/webchat/htdocs/templates/others-permission-request.html deleted file mode 100644 index ff7d871..0000000 --- a/examples/webchat/htdocs/templates/others-permission-request.html +++ /dev/null @@ -1,3 +0,0 @@ -
            • {{issuer}} {{grantee}} {{permission}} - -
            • diff --git a/examples/webchat/htdocs/templates/permission-request-in-GENERIC.html b/examples/webchat/htdocs/templates/permission-request-in-GENERIC.html new file mode 100644 index 0000000..d6f50ce --- /dev/null +++ b/examples/webchat/htdocs/templates/permission-request-in-GENERIC.html @@ -0,0 +1,3 @@ +
            • {{issuer}} {{grantee}} {{permissionJSON}} + Grant + Deny
            • diff --git a/examples/webchat/htdocs/templates/permission-request-in-p:follow.html b/examples/webchat/htdocs/templates/permission-request-in-p:follow.html new file mode 100644 index 0000000..af3fc8b --- /dev/null +++ b/examples/webchat/htdocs/templates/permission-request-in-p:follow.html @@ -0,0 +1,3 @@ +
            • Request from {{grantee}} to follow {{permission.fields.0}} + Grant + Deny
            • diff --git a/examples/webchat/htdocs/templates/permission-request-out-GENERIC.html b/examples/webchat/htdocs/templates/permission-request-out-GENERIC.html new file mode 100644 index 0000000..861f07b --- /dev/null +++ b/examples/webchat/htdocs/templates/permission-request-out-GENERIC.html @@ -0,0 +1 @@ +
            • q {{issuer}} {{permissionJSON}} Cancel
            • diff --git a/examples/webchat/htdocs/templates/permission-request-out-p:follow.html b/examples/webchat/htdocs/templates/permission-request-out-p:follow.html new file mode 100644 index 0000000..b0d3c23 --- /dev/null +++ b/examples/webchat/htdocs/templates/permission-request-out-p:follow.html @@ -0,0 +1 @@ +
            • Request to follow {{issuer}} Cancel
            • diff --git a/examples/webchat/htdocs/templates/present-entry.html b/examples/webchat/htdocs/templates/present-entry.html deleted file mode 100644 index 9b73586..0000000 --- a/examples/webchat/htdocs/templates/present-entry.html +++ /dev/null @@ -1 +0,0 @@ -
            • {{email}}
            • diff --git a/examples/webchat/htdocs/webchat.syndicate.js b/examples/webchat/htdocs/webchat.syndicate.js index ad4b371..c6d5b96 100644 --- a/examples/webchat/htdocs/webchat.syndicate.js +++ b/examples/webchat/htdocs/webchat.syndicate.js @@ -4,7 +4,9 @@ // the desired effect! assertion type online(); assertion type present(email); + assertion type uiTemplate(name, data) = "ui-template"; + assertion type permitted(issuer, email, permission, isDelegable); assertion type grant(issuer, grantor, grantee, permission, isDelegable); assertion type permissionRequest(issuer, grantee, permission) = "permission-request"; @@ -17,6 +19,16 @@ // assertion type pInvite(email) = "p:invite"; // assertion type pSeePresence(email) = "p:see-presence"; + assertion type contactListEntry(owner, member) = "contact-list-entry"; + + assertion type question(id, timestamp, klass, target, title, blurb, type); + assertion type answer(id, value); + assertion type yesNoQuestion(falseValue, trueValue) = "yes/no-question"; + assertion type optionQuestion(options) = "option-question"; + // ^ options = [[Any, Markdown]] + assertion type textQuestion(isMultiline) = "text-question"; + assertion type acknowledgeQuestion() = "acknowledge-question"; + var brokerConnected = Syndicate.Broker.brokerConnected; var brokerConnection = Syndicate.Broker.brokerConnection; var toBroker = Syndicate.Broker.toBroker; @@ -44,6 +56,10 @@ return fromBroker(brokerUrl, x); } + function avatar(email) { + return 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=48&d=retro'; + } + /////////////////////////////////////////////////////////////////////////// window.addEventListener('load', function () { @@ -73,6 +89,11 @@ actor { this.ui = new Syndicate.UI.Anchor(); field this.connectedTo = null; + field this.myRequestCount = 0; // requests *I* have made of others + field this.otherRequestCount = 0; // requests *others* have made of me + field this.questionCount = 0; // questions from the system + field this.globallyVisible = false; // mirrors *other people's experience of us* + field this.locallyVisible = true; assert brokerConnection(brokerUrl); @@ -81,7 +102,19 @@ var mainpage_c = this.ui.context('mainpage'); during inbound(uiTemplate("mainpage.html", $mainpage)) { - assert mainpage_c.html('div#main-div', mainpage); + assert mainpage_c.html('div#main-div', Mustache.render( + mainpage, + { + questionCount: this.questionCount, + myRequestCount: this.myRequestCount, + otherRequestCount: this.otherRequestCount, + globallyVisible: this.globallyVisible + })); + } + + during inbound(online()) { + on start { this.globallyVisible = true; } + on stop { this.globallyVisible = false; } } during mainpage_c.fragmentVersion($mainpageVersion) { @@ -89,12 +122,6 @@ // of nested widgetry. If we didn't include mainpageVersion in each subwidget's // context, then so long as the subwidget's content itself remained unchanged, // the user would see the subwidget disappear when mainpage.html changed. - on start { console.log('mainpage up', mainpageVersion); } - on stop { console.log('mainpage down', mainpageVersion); } - - during inputValue('#invisible', false) { - assert outbound(online()); - } on asserted Syndicate.UI.locationHash($hash) { var tab = hash.substr(1); @@ -105,30 +132,69 @@ $('#main-tab-tab-' + tab).addClass('active'); } - during inbound(uiTemplate("present-entry.html", $presentEntry)) { - during inbound(present($who)) { - var c = this.ui.context(mainpageVersion, 'present', who); - assert c.html('#present-entries', Mustache.render( - presentEntry, - { - email: who, - avatar: 'https://www.gravatar.com/avatar/' + md5(who.trim().toLowerCase()) + '?s=48&d=retro' - })); + during inbound(uiTemplate("nav-account.html", $entry)) { + var c = this.ui.context(mainpageVersion, 'nav', 0, 'account'); + assert outbound(online()) when (this.locallyVisible); + assert c.html('#nav-ul', Mustache.render( + entry, + { + email: sessionInfo.email, + avatar: avatar(sessionInfo.email), + questionCount: this.questionCount, + myRequestCount: this.myRequestCount, + otherRequestCount: this.otherRequestCount, + globallyVisible: this.globallyVisible, + locallyVisible: this.locallyVisible + })); + on message c.event('.toggleInvisible', 'click', _) { + this.locallyVisible = !this.locallyVisible; + } + } + + during inbound(uiTemplate("contact-entry.html", $entry)) { + during Syndicate.UI.locationHash('/contacts') { + during inbound(contactListEntry(sessionInfo.email, $contact)) { + field this.isPresent = false; + on asserted inbound(present(contact)) { this.isPresent = true; } + on retracted inbound(present(contact)) { this.isPresent = false; } + var c = this.ui.context(mainpageVersion, 'all-contacts', contact); + assert c.html('#main-tab-body-contacts .contact-list', + Mustache.render(entry, { + email: contact, + avatar: avatar(contact), + isPresent: this.isPresent + })); + on message c.event('.do-hi', 'click', $e) { + alert(contact); + } + } } } during inputValue('#add-contact-email', $contact) { - on message mainpage_c.event('#add-contact', 'click', _) { - :: outbound(createResource(permissionRequest(contact, - sessionInfo.email, - pFollow(contact)))); - // :: outbound(createResource(permissionRequest(contact, - // sessionInfo.email, - // pInvite(contact)))); - // :: outbound(createResource(permissionRequest(contact, - // sessionInfo.email, - // pSeePresence(contact)))); - $('#add-contact-email').val(''); + during inputValue('#reciprocate', $reciprocate) { + on message mainpage_c.event('#add-contact', 'click', _) { + if (reciprocate) { + :: outbound(createResource(grant(sessionInfo.email, + sessionInfo.email, + contact, + pFollow(sessionInfo.email), + false))); + } + + :: outbound(createResource(contactListEntry(sessionInfo.email, contact))); + :: outbound(createResource(permissionRequest(contact, + sessionInfo.email, + pFollow(contact)))); + + // :: outbound(createResource(permissionRequest(contact, + // sessionInfo.email, + // pInvite(contact)))); + // :: outbound(createResource(permissionRequest(contact, + // sessionInfo.email, + // pSeePresence(contact)))); + $('#add-contact-email').val(''); + } } } @@ -162,37 +228,57 @@ } } - during inbound(uiTemplate("my-permission-request.html", $entry)) { + during inbound(uiTemplate("permission-request-out-GENERIC.html", $genericEntry)) { during inbound(permissionRequest($issuer, sessionInfo.email, $permission)) { + on start { this.myRequestCount++; } + on stop { this.myRequestCount--; } + var c = this.ui.context(mainpageVersion, 'my-permission-request', issuer, permission); + field this.entry = genericEntry; assert c.html('#my-permission-requests', - Mustache.render(entry, {issuer: issuer, - permission: JSON.stringify(permission)})); + Mustache.render(this.entry, + {issuer: issuer, + permission: permission, + permissionJSON: JSON.stringify(permission)})) + when (this.entry); + var specificTemplate = "permission-request-out-" + + encodeURIComponent(permission.meta.label) + ".html"; + on asserted inbound(uiTemplate(specificTemplate, $specificEntry)) { + this.entry = specificEntry || genericEntry; + } on message c.event('.cancel', 'click', _) { :: outbound(deleteResource(permissionRequest(issuer, sessionInfo.email, permission))); } } } - during inbound(uiTemplate("others-permission-request.html", $entry)) { - field this.requestCount = 0; - - assert mainpage_c.context(mainpageVersion, 'requestCount') - .html('#request-count', this.requestCount); - assert Syndicate.UI.uiAttribute('.request-count-sensitive', - 'class', - 'count' + this.requestCount); + during inputValue('#show-all-requests-from-others', $showRequestsFromOthers) { + on start { + var d = $('#all-requests-from-others-div'); + if (showRequestsFromOthers) { d.show(); } else { d.hide(); } + } + } + during inbound(uiTemplate("permission-request-in-GENERIC.html", $genericEntry)) { during inbound(permissionRequest($issuer, $grantee, $permission)) { if (grantee !== sessionInfo.email) { - on start { this.requestCount++; } - on stop { this.requestCount--; } + on start { this.otherRequestCount++; } + on stop { this.otherRequestCount--; } var c = this.ui.context(mainpageVersion, 'others-permission-request', issuer, grantee, permission); + field this.entry = genericEntry; assert c.html('#others-permission-requests', - Mustache.render(entry, {issuer: issuer, - grantee: grantee, - permission: JSON.stringify(permission)})); + Mustache.render(this.entry, + {issuer: issuer, + grantee: grantee, + permission: permission, + permissionJSON: JSON.stringify(permission)})) + when (this.entry); + var specificTemplate = "permission-request-in-" + + encodeURIComponent(permission.meta.label) + ".html"; + on asserted inbound(uiTemplate(specificTemplate, $specificEntry)) { + this.entry = specificEntry || genericEntry; + } on message c.event('.grant', 'click', _) { :: outbound(createResource(grant(issuer, sessionInfo.email, @@ -206,9 +292,41 @@ } } } + + during inbound(question($qid, $timestamp, $klass, sessionInfo.email, $title, $blurb, $qt)) + { + on start { this.questionCount++; } + on stop { this.questionCount--; } + + var c = this.ui.context(mainpageVersion, 'question', timestamp, qid); + + switch (qt.meta.label) { + case "option-question": { + var options = qt.fields[0]; + during inbound(uiTemplate("option-question.html", $entry)) { + assert c.html('#question-container', + Mustache.render(entry, {questionClass: klass, + title: title, + blurb: blurb, + options: options})); + on message c.event('.response', 'click', $e) { + react { assert outbound(answer(qid, e.target.dataset.value)); } + } + } + break; + } + default: { + break; + } + } + } } } } + + G.dataspace.setOnStateChange(function (mux, patch) { + $("#debug-space").text(Syndicate.prettyTrie(mux.routingTable)); + }); } })(); diff --git a/examples/webchat/server/account.rkt b/examples/webchat/server/account.rkt index 261c617..b65ff3d 100644 --- a/examples/webchat/server/account.rkt +++ b/examples/webchat/server/account.rkt @@ -19,7 +19,5 @@ (on-start (log-info "Account ~s created." email)) (on-stop (log-info "Account ~s deleted." email)) (assert (account email)) - (assert (issuer email (p:follow email))) - ;; (assert (issuer email (p:invite email))) - ;; (assert (issuer email (p:see-presence email))) + (assert (grant email email email (p:follow email) #t)) (stop-when (message (delete-account email))))) diff --git a/examples/webchat/server/api.rkt b/examples/webchat/server/api.rkt index 5084c09..c95cee1 100644 --- a/examples/webchat/server/api.rkt +++ b/examples/webchat/server/api.rkt @@ -22,17 +22,13 @@ #:scope scope #:hook (lambda () (stop-when (message (end-session sid))) - (stop-when (message (delete-account email)))))])))) - -(struct online () #:prefab) -(struct present (email) #:prefab) - -(supervise - (actor #:name 'reflect-presence - (stop-when-reloaded) - (during (api (session $who _) (online)) - (during (permitted who $grantee (p:follow #;p:see-presence who) _) - (assert (api (session grantee _) (present who))))))) + (stop-when (message (delete-account email)))))] + [else + (web-respond/xexpr! id + #:header (web-response-header #:code 401 + #:message #"Unauthorized") + `(html (body (h1 "Unauthorized") + (a ((href "/")) "Login"))))])))) (supervise (actor #:name 'reflect-trust @@ -43,7 +39,9 @@ (during ($ r (permission-request _ who _)) (assert (api (session who _) r))) (during ($ g (grant _ who _ _ _)) - (assert (api (session who _) g)))))) + (assert (api (session who _) g))) + (during ($ c (contact-list-entry who _)) + (assert (api (session who _) c)))))) (supervise (actor #:name 'reflect-grant-requests @@ -59,6 +57,13 @@ (actor #:name 'take-trust-instructions (stop-when-reloaded) + (on (message (api (session $owner _) (create-resource (? contact-list-entry? $e)))) + (when (equal? owner (contact-list-entry-owner e)) + (send! (create-resource e)))) + (on (message (api (session $owner _) (delete-resource (? contact-list-entry? $e)))) + (when (equal? owner (contact-list-entry-owner e)) + (send! (delete-resource e)))) + (on (message (api (session $grantor _) (create-resource (? grant? $g)))) (when (equal? grantor (grant-grantor g)) (send! (create-resource g)))) diff --git a/examples/webchat/server/contacts.rkt b/examples/webchat/server/contacts.rkt new file mode 100644 index 0000000..99328f1 --- /dev/null +++ b/examples/webchat/server/contacts.rkt @@ -0,0 +1,83 @@ +#lang syndicate/actor + +(require/activate syndicate/reload) +(require/activate syndicate/supervise) +(require/activate "trust.rkt") +(require/activate "qa.rkt") + +(require "protocol.rkt") +(require "duplicate.rkt") + +(struct online () #:prefab) +(struct present (email) #:prefab) + +(supervise + (actor #:name 'reflect-contacts + (stop-when-reloaded) + (during (api (session $who _) (online)) + (during (permitted who $grantee (p:follow #;p:see-presence who) _) + ;; `who` allows `grantee` to follow them + (assert (api (session grantee _) (present who))))))) + +(actor #:name 'contact-list-factory + (stop-when-reloaded) + (on (message (create-resource ($ e (contact-list-entry $owner $member)))) + (actor #:name e + (on-start (log-info "~s adds ~s to their contact list" owner member)) + (on-stop (log-info "~s removes ~s from their contact list" owner member)) + (assert e) + (stop-when-duplicate e) + (stop-when (message (delete-resource e))) + (stop-when (asserted (delete-account owner))) + (stop-when (asserted (delete-account member)))))) + +(supervise + (actor #:name 'contacts:questions + (stop-when-reloaded) + ;; TODO: NOTE: When the `permission-request` vanishes (due to + ;; satisfaction or rejection), this should remove the question + ;; from all eligible answerers at once + (during (permission-request $who $grantee ($ p (p:follow _))) + (when (equal? who (p:follow-email p)) + ;; `grantee` wants to follow `who` + (during (permitted who $grantor p #t) + ;; `grantor` can make that decision + (on-start + (define-values (title blurb) + (if (equal? who grantor) + (values (format "Follow request from ~a" grantee) + `(p "User " (b ,grantee) " wants to be able to invite you " + "to conversations and see when you are online.")) + (values (format "Request from ~a to follow ~a" grantee who) + `(p "User " (b ,grantee) " wants to be able to invite " + (b ,who) " to conversations and see when they are online.")))) + (define base-options + (list (list "deny" "Reject") + (list "ignore" "Ignore"))) + (match (ask-question #:title title #:blurb blurb #:target grantor #:class "q-follow" + (option-question + ;; If who == grantor, then the grantor is directly + ;; the person being followed, and should be offered + ;; the option to follow back, unless they've already + ;; taken that option, which can be deduced if BOTH + ;; the grantee has declared that the grantor may + ;; follow the grantee AND the grantor has declared + ;; that the grantee is a member of their contact + ;; list. + (if (and (equal? who grantor) + (not (and + (immediate-query [query-value #f (permitted grantee grantor (p:follow grantee) _) #t]) + (immediate-query [query-value #f (contact-list-entry grantor grantee) #t])))) + (list* (list "allow-and-return" "Accept and follow back") + (list "allow" "Accept, but do not follow back") + base-options) + (cons (list "allow" "Accept") + base-options)))) + ["allow-and-return" + (send! (create-resource (grant who grantor grantee p #f))) + (send! (create-resource (contact-list-entry grantor grantee))) + (send! (create-resource (permission-request grantee grantor (p:follow grantee))))] + ["allow" (send! (create-resource (grant who grantor grantee p #f)))] + ["deny" (send! (delete-resource (permission-request who grantee p)))] + ["ignore" (void)]))))))) + diff --git a/examples/webchat/server/conversation.rkt b/examples/webchat/server/conversation.rkt index c93db19..fdc600a 100644 --- a/examples/webchat/server/conversation.rkt +++ b/examples/webchat/server/conversation.rkt @@ -1,7 +1,7 @@ #lang syndicate/actor -(provide ) +(require/activate syndicate/reload) +(require/activate syndicate/supervise) +(require/activate "trust.rkt") (require "protocol.rkt") - -(actor #:name diff --git a/examples/webchat/server/duplicate.rkt b/examples/webchat/server/duplicate.rkt new file mode 100644 index 0000000..28b6a4c --- /dev/null +++ b/examples/webchat/server/duplicate.rkt @@ -0,0 +1,17 @@ +#lang syndicate/actor + +(provide stop-when-duplicate) + +(require syndicate/protocol/instance) +(require "util.rkt") + +(define (stop-when-duplicate spec) + (define id (random-hex-string 16)) + (field [duplicate? #f]) + (stop-when (rising-edge (duplicate?))) + (assert (instance id spec)) + (on (asserted (instance $id2 spec)) + (when (stringpath (make-url->path templates-path)) (during (api _ (observe (ui-template $name _))) (define-values (path path-pieces) (url->path (string->url name))) - (log-info "Observation of ~v" path) + (on-start (log-info "Start observation of ~v" path)) + (on-stop (log-info "Stop observation of ~v" path)) (during (file-content path file->string $data) (assert (api _ (ui-template name data)))))) diff --git a/examples/webchat/server/trust.rkt b/examples/webchat/server/trust.rkt index 138e71e..2e8fd34 100644 --- a/examples/webchat/server/trust.rkt +++ b/examples/webchat/server/trust.rkt @@ -1,33 +1,20 @@ #lang syndicate/actor (require racket/set) -(require syndicate/protocol/instance) (require/activate syndicate/reload) (require "protocol.rkt") -(require "util.rkt") +(require "duplicate.rkt") (actor #:name 'trust-inference (stop-when-reloaded) - (during (issuer $who $permission) - (assert (permitted who who permission #t))) - (during (grant $issuer $grantor $grantee $permission $delegable?) + (when (equal? issuer grantor) + (assert (permitted issuer grantee permission delegable?))) (during (permitted issuer grantor permission #t) (assert (permitted issuer grantee permission delegable?))))) -(define (stop-when-duplicate spec) - (define id (random-hex-string 16)) - (field [duplicate? #f]) - (stop-when (rising-edge (duplicate?))) - (assert (instance id spec)) - (on (asserted (instance $id2 spec)) - (when (string