|
|
|
|
@ -1,11 +1,11 @@
|
|
|
|
|
#lang racket/base |
|
|
|
|
|
|
|
|
|
(provide spawn-gatekeeper-pair |
|
|
|
|
gatekeep |
|
|
|
|
^energized) |
|
|
|
|
(provide spawn-warden-pair |
|
|
|
|
ward |
|
|
|
|
^enchanted) |
|
|
|
|
|
|
|
|
|
;; This module provides a "gatekeeping" mechanism... behind the |
|
|
|
|
;; gate is some interesting behavior an actor might not quite |
|
|
|
|
;; This module provides a "warding" mechanism... behind the |
|
|
|
|
;; ward is some interesting behavior an actor might not quite |
|
|
|
|
;; everyone to have access to. See the tests for how to use. |
|
|
|
|
|
|
|
|
|
;; See also http://www.erights.org/history/joule/MANUAL.B17.pdf |
|
|
|
|
@ -16,39 +16,39 @@
|
|
|
|
|
racket/match) |
|
|
|
|
|
|
|
|
|
;; Keyword arguments: |
|
|
|
|
;; - #:async?: If true, the energizer will use <- instead of $ to |
|
|
|
|
;; - #:async?: If true, the incanter will use <- instead of $ to |
|
|
|
|
;; proxy messages sends |
|
|
|
|
;; |
|
|
|
|
;; Returns two values to its continuation: |
|
|
|
|
;; - a gatekeeper, to be used with the gatekeep procedure below |
|
|
|
|
;; - an energizer, to access actors which have gatekept methods |
|
|
|
|
(define (spawn-gatekeeper-pair #:async? [async? #f]) |
|
|
|
|
;; - a warden, to be used with the ward procedure below |
|
|
|
|
;; - an incanter, to access actors which have warded methods |
|
|
|
|
(define (spawn-warden-pair #:async? [async? #f]) |
|
|
|
|
(define-values (seal unseal sealed?) |
|
|
|
|
(make-sealer-triplet 'gatekeep)) |
|
|
|
|
;; When invoked, the gatekeeper returns either: |
|
|
|
|
(make-sealer-triplet 'ward)) |
|
|
|
|
;; When invoked, the warden returns either: |
|
|
|
|
;; - #f: if these are not arguments sealed by the sealer, or |
|
|
|
|
;; - (list kws kw-vals args): the unsealed arguments |
|
|
|
|
(define (^gatekeeper _bcom) |
|
|
|
|
(define (^warden _bcom) |
|
|
|
|
(lambda (maybe-sealed-args) |
|
|
|
|
(and (sealed? maybe-sealed-args) |
|
|
|
|
(unseal maybe-sealed-args)))) |
|
|
|
|
(define (^energizer _bcom) |
|
|
|
|
(define (^incanter _bcom) |
|
|
|
|
(define $/<- |
|
|
|
|
(if async? <- $)) |
|
|
|
|
(make-keyword-procedure |
|
|
|
|
(lambda (kws kw-args target . args) |
|
|
|
|
($/<- target (seal (list kws kw-args args)))))) |
|
|
|
|
|
|
|
|
|
(values (spawn ^gatekeeper) (spawn ^energizer))) |
|
|
|
|
(values (spawn ^warden) (spawn ^incanter))) |
|
|
|
|
|
|
|
|
|
(define (gatekeep gatekeeper behavior |
|
|
|
|
#:extends [extends #f]) |
|
|
|
|
(define (ward warden behavior |
|
|
|
|
#:extends [extends #f]) |
|
|
|
|
(define (error-out) |
|
|
|
|
(error "Not sealed args and no extended behavior")) |
|
|
|
|
(make-keyword-procedure |
|
|
|
|
(match-lambda* |
|
|
|
|
[(list '() '() maybe-sealed-args) |
|
|
|
|
(match ($ gatekeeper maybe-sealed-args) |
|
|
|
|
(match ($ warden maybe-sealed-args) |
|
|
|
|
[(list kws kw-vals args) |
|
|
|
|
(keyword-apply behavior kws kw-vals args)] |
|
|
|
|
;; Hm, didn't match the seal, so let's use the extended |
|
|
|
|
@ -64,22 +64,22 @@
|
|
|
|
|
(keyword-apply extends kws kw-vals args) |
|
|
|
|
(error-out))]))) |
|
|
|
|
|
|
|
|
|
;; Sets up an "energized proxy" that always sends messages through |
|
|
|
|
;; the energizer |
|
|
|
|
(define (^energized _bcom energizer target |
|
|
|
|
;; Sets up an "enchanted proxy" that always sends messages through |
|
|
|
|
;; the incanter |
|
|
|
|
(define (^enchanted _bcom incanter target |
|
|
|
|
#:async? [async? #f]) |
|
|
|
|
(define $/<- |
|
|
|
|
(if async? <- $)) |
|
|
|
|
(make-keyword-procedure |
|
|
|
|
(lambda (kws kw-vals . args) |
|
|
|
|
(keyword-apply $/<- kws kw-vals energizer target args)))) |
|
|
|
|
(keyword-apply $/<- kws kw-vals incanter target args)))) |
|
|
|
|
|
|
|
|
|
(module+ test |
|
|
|
|
(require "methods.rkt" |
|
|
|
|
rackunit |
|
|
|
|
racket/contract) |
|
|
|
|
|
|
|
|
|
(define (^inbox bcom mailbox-name admin-gatekeeper) |
|
|
|
|
(define (^inbox bcom mailbox-name admin-warden) |
|
|
|
|
(define (make-main-beh mailbox-name messages) |
|
|
|
|
(define admin-methods |
|
|
|
|
(methods |
|
|
|
|
@ -98,7 +98,7 @@
|
|
|
|
|
(bcom mailbox-name (make-main-beh msg messages))] |
|
|
|
|
[(mailbox-name) mailbox-name])) |
|
|
|
|
|
|
|
|
|
(gatekeep admin-gatekeeper admin-methods |
|
|
|
|
(ward admin-warden admin-methods |
|
|
|
|
#:extends public-methods)) |
|
|
|
|
|
|
|
|
|
(define revoked-beh |
|
|
|
|
@ -108,61 +108,61 @@
|
|
|
|
|
|
|
|
|
|
(define am (make-actormap)) |
|
|
|
|
|
|
|
|
|
(match-define (list inbox admin-energizer) |
|
|
|
|
(match-define (list inbox admin-incanter) |
|
|
|
|
(actormap-run! am |
|
|
|
|
(lambda () |
|
|
|
|
(define-values (admin-gatekeeper admin-energizer) |
|
|
|
|
(spawn-gatekeeper-pair)) |
|
|
|
|
(list (spawn ^inbox "My First Inbox" admin-gatekeeper) |
|
|
|
|
admin-energizer)))) |
|
|
|
|
(define-values (admin-warden admin-incanter) |
|
|
|
|
(spawn-warden-pair)) |
|
|
|
|
(list (spawn ^inbox "My First Inbox" admin-warden) |
|
|
|
|
admin-incanter)))) |
|
|
|
|
|
|
|
|
|
(check-equal? |
|
|
|
|
(actormap-peek am inbox 'mailbox-name) |
|
|
|
|
"My First Inbox") |
|
|
|
|
|
|
|
|
|
(test-exn |
|
|
|
|
"Can't just set the name without energizer" |
|
|
|
|
"Can't just set the name without incanter" |
|
|
|
|
any/c |
|
|
|
|
(lambda () |
|
|
|
|
(actormap-poke! am inbox 'set-name "A brand new name"))) |
|
|
|
|
|
|
|
|
|
(test-not-exn |
|
|
|
|
"Can set the name through the energizer without erroring out" |
|
|
|
|
"Can set the name through the incanter without erroring out" |
|
|
|
|
(lambda () |
|
|
|
|
(actormap-poke! am admin-energizer |
|
|
|
|
(actormap-poke! am admin-incanter |
|
|
|
|
inbox 'set-name "New name" |
|
|
|
|
#:upcase? #t))) |
|
|
|
|
|
|
|
|
|
(test-equal? |
|
|
|
|
"New name successfully set via energizer" |
|
|
|
|
"New name successfully set via incanter" |
|
|
|
|
(actormap-peek am inbox 'mailbox-name) |
|
|
|
|
"NEW NAME") |
|
|
|
|
|
|
|
|
|
(define some-other-energizer |
|
|
|
|
(define some-other-incanter |
|
|
|
|
(actormap-run! am |
|
|
|
|
(lambda () |
|
|
|
|
(define-values (_some-gatekeeper some-energizer) |
|
|
|
|
(spawn-gatekeeper-pair)) |
|
|
|
|
some-energizer))) |
|
|
|
|
(define-values (_some-warden some-incanter) |
|
|
|
|
(spawn-warden-pair)) |
|
|
|
|
some-incanter))) |
|
|
|
|
|
|
|
|
|
(test-exn |
|
|
|
|
"Can't just set the name without energizer" |
|
|
|
|
"Can't just set the name without incanter" |
|
|
|
|
any/c |
|
|
|
|
(lambda () |
|
|
|
|
(actormap-poke! am some-other-energizer |
|
|
|
|
(actormap-poke! am some-other-incanter |
|
|
|
|
inbox 'set-name "A brand new name"))) |
|
|
|
|
|
|
|
|
|
(define inbox-admin |
|
|
|
|
(actormap-spawn! am ^energized admin-energizer inbox)) |
|
|
|
|
(actormap-spawn! am ^enchanted admin-incanter inbox)) |
|
|
|
|
|
|
|
|
|
(test-not-exn |
|
|
|
|
"Can set the name through the energized proxy without erroring out" |
|
|
|
|
"Can set the name through the enchanted proxy without erroring out" |
|
|
|
|
(lambda () |
|
|
|
|
(actormap-poke! am inbox-admin |
|
|
|
|
'set-name "Another new name" |
|
|
|
|
#:upcase? #t))) |
|
|
|
|
|
|
|
|
|
(test-equal? |
|
|
|
|
"New name successfully set via energized proxy" |
|
|
|
|
"New name successfully set via enchanted proxy" |
|
|
|
|
(actormap-peek am inbox 'mailbox-name) |
|
|
|
|
"ANOTHER NEW NAME")) |
|
|
|
|
|