implement new split nameplate/mailbox/terminator
fails even worse than before, of course
This commit is contained in:
parent
02bea00366
commit
26adaabe18
|
@ -18,11 +18,11 @@ digraph {
|
||||||
S0 -> P0_build [label="set_code"]
|
S0 -> P0_build [label="set_code"]
|
||||||
|
|
||||||
S0 -> P_close_error [label="rx_error"]
|
S0 -> P_close_error [label="rx_error"]
|
||||||
P_close_error [shape="box" label="M.close(errory)"]
|
P_close_error [shape="box" label="T.close(errory)"]
|
||||||
P_close_error -> S_closing
|
P_close_error -> S_closing
|
||||||
S0 -> P_close_lonely [label="close"]
|
S0 -> P_close_lonely [label="close"]
|
||||||
|
|
||||||
P0_build [shape="box" label="W.got_code\nM.set_nameplate\nK.got_code"]
|
P0_build [shape="box" label="W.got_code\nN.set_nameplate\nK.got_code"]
|
||||||
P0_build -> S1
|
P0_build -> S1
|
||||||
S1 [label="S1: lonely" color="orange"]
|
S1 [label="S1: lonely" color="orange"]
|
||||||
|
|
||||||
|
@ -31,15 +31,15 @@ digraph {
|
||||||
S1 -> P_close_error [label="rx_error"]
|
S1 -> P_close_error [label="rx_error"]
|
||||||
S1 -> P_close_scary [label="scared" color="red"]
|
S1 -> P_close_scary [label="scared" color="red"]
|
||||||
S1 -> P_close_lonely [label="close"]
|
S1 -> P_close_lonely [label="close"]
|
||||||
P_close_lonely [shape="box" label="M.close(lonely)"]
|
P_close_lonely [shape="box" label="T.close(lonely)"]
|
||||||
P_close_lonely -> S_closing
|
P_close_lonely -> S_closing
|
||||||
|
|
||||||
P_close_scary [shape="box" label="M.close(scary)" color="red"]
|
P_close_scary [shape="box" label="T.close(scary)" color="red"]
|
||||||
P_close_scary -> S_closing [color="red"]
|
P_close_scary -> S_closing [color="red"]
|
||||||
|
|
||||||
S2 [label="S2: happy" color="green"]
|
S2 [label="S2: happy" color="green"]
|
||||||
S2 -> P2_close [label="close"]
|
S2 -> P2_close [label="close"]
|
||||||
P2_close [shape="box" label="M.close(happy)"]
|
P2_close [shape="box" label="T.close(happy)"]
|
||||||
P2_close -> S_closing
|
P2_close -> S_closing
|
||||||
|
|
||||||
S2 -> P2_got_message [label="got_message"]
|
S2 -> P2_got_message [label="got_message"]
|
||||||
|
|
|
@ -3,37 +3,37 @@ digraph {
|
||||||
title [label="Terminator\nMachine" style="dotted"]
|
title [label="Terminator\nMachine" style="dotted"]
|
||||||
|
|
||||||
initial [style="invis"]
|
initial [style="invis"]
|
||||||
initial -> Snm [style="dashed"]
|
initial -> Snmo [style="dashed"]
|
||||||
|
|
||||||
Snm [label="Snm:\nnameplate active\nmailbox active" color="orange"]
|
Snmo [label="Snmo:\nnameplate active\nmailbox active\nopen" color="orange"]
|
||||||
Sn [label="Sn:\nnameplate active\nmailbox done"]
|
Sno [label="Sno:\nnameplate active\nmailbox done\nopen"]
|
||||||
Sm [label="Sm:\nnameplate done\nmailbox active" color="green"]
|
Smo [label="Smo:\nnameplate done\nmailbox active\nopen" color="green"]
|
||||||
S0 [label="S0:\nnameplate done\nmailbox done"]
|
S0o [label="S0o:\nnameplate done\nmailbox done\nopen"]
|
||||||
|
|
||||||
Snm -> Sn [label="mailbox_done"]
|
Snmo -> Sno [label="mailbox_done"]
|
||||||
Snm -> Sm [label="nameplate_done" color="orange"]
|
Snmo -> Smo [label="nameplate_done" color="orange"]
|
||||||
Sn -> S0 [label="nameplate_done"]
|
Sno -> S0o [label="nameplate_done"]
|
||||||
Sm -> S0 [label="mailbox_done"]
|
Smo -> S0o [label="mailbox_done"]
|
||||||
|
|
||||||
Snm -> Snm_closing [label="close"]
|
Snmo -> Snm [label="close"]
|
||||||
Sn -> Sn_closing [label="close"]
|
Sno -> Sn [label="close"]
|
||||||
Sm -> Sm_closing [label="close" color="red"]
|
Smo -> Sm [label="close" color="red"]
|
||||||
S0 -> P_stop [label="close"]
|
S0o -> P_stop [label="close"]
|
||||||
|
|
||||||
Snm_closing [label="Snm_closing:\nnameplate active\nmailbox active"
|
Snm [label="Snm:\nnameplate active\nmailbox active\nclosing"
|
||||||
style="dashed"]
|
style="dashed"]
|
||||||
Sn_closing [label="Sn_closing:\nnameplate active\nmailbox done"
|
Sn [label="Sn:\nnameplate active\nmailbox done\nclosing"
|
||||||
style="dashed"]
|
style="dashed"]
|
||||||
Sm_closing [label="Sm_closing:\nnameplate done\nmailbox active"
|
Sm [label="Sm:\nnameplate done\nmailbox active\nclosing"
|
||||||
style="dashed" color="red"]
|
style="dashed" color="red"]
|
||||||
|
|
||||||
Snm_closing -> Sn_closing [label="mailbox_done"]
|
Snm -> Sn [label="mailbox_done"]
|
||||||
Snm_closing -> Sm_closing [label="nameplate_done"]
|
Snm -> Sm [label="nameplate_done"]
|
||||||
Sn_closing -> P_stop [label="nameplate_done"]
|
Sn -> P_stop [label="nameplate_done"]
|
||||||
Sm_closing -> P_stop [label="mailbox_done" color="red"]
|
Sm -> P_stop [label="mailbox_done" color="red"]
|
||||||
|
|
||||||
{rank=same; S_stopping Pss S_stopped}
|
{rank=same; S_stopping Pss S_stopped}
|
||||||
P_stop [shape="box" label="C.stop" color="red"]
|
P_stop [shape="box" label="RC.stop" color="red"]
|
||||||
P_stop -> S_stopping [color="red"]
|
P_stop -> S_stopping [color="red"]
|
||||||
|
|
||||||
S_stopping [label="S_stopping" color="red"]
|
S_stopping [label="S_stopping" color="red"]
|
||||||
|
|
|
@ -7,14 +7,16 @@ from attr.validators import provides, instance_of
|
||||||
from twisted.python import log
|
from twisted.python import log
|
||||||
from automat import MethodicalMachine
|
from automat import MethodicalMachine
|
||||||
from . import _interfaces
|
from . import _interfaces
|
||||||
|
from ._nameplate import Nameplate
|
||||||
from ._mailbox import Mailbox
|
from ._mailbox import Mailbox
|
||||||
from ._send import Send
|
from ._send import Send
|
||||||
from ._order import Order
|
from ._order import Order
|
||||||
from ._key import Key
|
from ._key import Key
|
||||||
from ._receive import Receive
|
from ._receive import Receive
|
||||||
from ._rendezvous import RendezvousConnector
|
from ._rendezvous import RendezvousConnector
|
||||||
from ._nameplate import NameplateListing
|
from ._nameplate_lister import NameplateListing
|
||||||
from ._code import Code
|
from ._code import Code
|
||||||
|
from ._terminator import Terminator
|
||||||
from .errors import WrongPasswordError
|
from .errors import WrongPasswordError
|
||||||
from .util import bytes_to_dict
|
from .util import bytes_to_dict
|
||||||
|
|
||||||
|
@ -34,6 +36,7 @@ class Boss(object):
|
||||||
m = MethodicalMachine()
|
m = MethodicalMachine()
|
||||||
|
|
||||||
def __attrs_post_init__(self):
|
def __attrs_post_init__(self):
|
||||||
|
self._N = Nameplate()
|
||||||
self._M = Mailbox(self._side)
|
self._M = Mailbox(self._side)
|
||||||
self._S = Send(self._side, self._timing)
|
self._S = Send(self._side, self._timing)
|
||||||
self._O = Order(self._side, self._timing)
|
self._O = Order(self._side, self._timing)
|
||||||
|
@ -44,8 +47,10 @@ class Boss(object):
|
||||||
self._timing)
|
self._timing)
|
||||||
self._NL = NameplateListing()
|
self._NL = NameplateListing()
|
||||||
self._C = Code(self._timing)
|
self._C = Code(self._timing)
|
||||||
|
self._T = Terminator()
|
||||||
|
|
||||||
self._M.wire(self, self._RC, self._O)
|
self._N.wire(self._M, self._RC, self._T)
|
||||||
|
self._M.wire(self._N, self._RC, self._O, self._T)
|
||||||
self._S.wire(self._M)
|
self._S.wire(self._M)
|
||||||
self._O.wire(self._K, self._R)
|
self._O.wire(self._K, self._R)
|
||||||
self._K.wire(self, self._M, self._R)
|
self._K.wire(self, self._M, self._R)
|
||||||
|
@ -53,6 +58,7 @@ class Boss(object):
|
||||||
self._RC.wire(self, self._M, self._C, self._NL)
|
self._RC.wire(self, self._M, self._C, self._NL)
|
||||||
self._NL.wire(self._RC, self._C)
|
self._NL.wire(self._RC, self._C)
|
||||||
self._C.wire(self, self._RC, self._NL)
|
self._C.wire(self, self._RC, self._NL)
|
||||||
|
self._T.wire(self, self._RC, self._N, self._M)
|
||||||
|
|
||||||
self._next_tx_phase = 0
|
self._next_tx_phase = 0
|
||||||
self._next_rx_phase = 0
|
self._next_rx_phase = 0
|
||||||
|
@ -137,7 +143,7 @@ class Boss(object):
|
||||||
@m.input()
|
@m.input()
|
||||||
def got_verifier(self, verifier): pass
|
def got_verifier(self, verifier): pass
|
||||||
|
|
||||||
# Mailbox sends closed
|
# Terminator sends closed
|
||||||
@m.input()
|
@m.input()
|
||||||
def closed(self): pass
|
def closed(self): pass
|
||||||
|
|
||||||
|
@ -149,7 +155,7 @@ class Boss(object):
|
||||||
@m.output()
|
@m.output()
|
||||||
def do_got_code(self, code):
|
def do_got_code(self, code):
|
||||||
nameplate = code.split("-")[0]
|
nameplate = code.split("-")[0]
|
||||||
self._M.set_nameplate(nameplate)
|
self._N.set_nameplate(nameplate)
|
||||||
self._K.got_code(code)
|
self._K.got_code(code)
|
||||||
self._W.got_code(code)
|
self._W.got_code(code)
|
||||||
@m.output()
|
@m.output()
|
||||||
|
@ -167,19 +173,19 @@ class Boss(object):
|
||||||
@m.output()
|
@m.output()
|
||||||
def close_error(self, err, orig):
|
def close_error(self, err, orig):
|
||||||
self._result = WormholeError(err)
|
self._result = WormholeError(err)
|
||||||
self._M.close("errory")
|
self._T.close("errory")
|
||||||
@m.output()
|
@m.output()
|
||||||
def close_scared(self):
|
def close_scared(self):
|
||||||
self._result = WrongPasswordError()
|
self._result = WrongPasswordError()
|
||||||
self._M.close("scary")
|
self._T.close("scary")
|
||||||
@m.output()
|
@m.output()
|
||||||
def close_lonely(self):
|
def close_lonely(self):
|
||||||
self._result = WormholeError("lonely")
|
self._result = WormholeError("lonely")
|
||||||
self._M.close("lonely")
|
self._T.close("lonely")
|
||||||
@m.output()
|
@m.output()
|
||||||
def close_happy(self):
|
def close_happy(self):
|
||||||
self._result = "happy"
|
self._result = "happy"
|
||||||
self._M.close("happy")
|
self._T.close("happy")
|
||||||
|
|
||||||
@m.output()
|
@m.output()
|
||||||
def W_got_verifier(self, verifier):
|
def W_got_verifier(self, verifier):
|
||||||
|
|
|
@ -4,6 +4,8 @@ class IWormhole(Interface):
|
||||||
pass
|
pass
|
||||||
class IBoss(Interface):
|
class IBoss(Interface):
|
||||||
pass
|
pass
|
||||||
|
class INameplate(Interface):
|
||||||
|
pass
|
||||||
class IMailbox(Interface):
|
class IMailbox(Interface):
|
||||||
pass
|
pass
|
||||||
class ISend(Interface):
|
class ISend(Interface):
|
||||||
|
@ -20,6 +22,8 @@ class INameplateLister(Interface):
|
||||||
pass
|
pass
|
||||||
class ICode(Interface):
|
class ICode(Interface):
|
||||||
pass
|
pass
|
||||||
|
class ITerminator(Interface):
|
||||||
|
pass
|
||||||
|
|
||||||
class ITiming(Interface):
|
class ITiming(Interface):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -14,16 +14,15 @@ class Mailbox(object):
|
||||||
def setTrace(): pass
|
def setTrace(): pass
|
||||||
|
|
||||||
def __attrs_post_init__(self):
|
def __attrs_post_init__(self):
|
||||||
self._mood = None
|
|
||||||
self._nameplate = None
|
|
||||||
self._mailbox = None
|
self._mailbox = None
|
||||||
self._pending_outbound = {}
|
self._pending_outbound = {}
|
||||||
self._processed = set()
|
self._processed = set()
|
||||||
|
|
||||||
def wire(self, boss, rendezvous_connector, ordering):
|
def wire(self, nameplate, rendezvous_connector, ordering, terminator):
|
||||||
self._B = _interfaces.IBoss(boss)
|
self._N = _interfaces.INameplate(nameplate)
|
||||||
self._RC = _interfaces.IRendezvousConnector(rendezvous_connector)
|
self._RC = _interfaces.IRendezvousConnector(rendezvous_connector)
|
||||||
self._O = _interfaces.IOrder(ordering)
|
self._O = _interfaces.IOrder(ordering)
|
||||||
|
self._T = _interfaces.ITerminator(terminator)
|
||||||
|
|
||||||
# all -A states: not connected
|
# all -A states: not connected
|
||||||
# all -B states: yes connected
|
# all -B states: yes connected
|
||||||
|
@ -35,73 +34,49 @@ class Mailbox(object):
|
||||||
@m.state()
|
@m.state()
|
||||||
def S0B(self): pass
|
def S0B(self): pass
|
||||||
|
|
||||||
# S1: nameplate known, not claimed
|
# S1: mailbox known, not opened
|
||||||
@m.state()
|
@m.state()
|
||||||
def S1A(self): pass
|
def S1A(self): pass
|
||||||
|
|
||||||
# S2: nameplate known, maybe claimed
|
# S2: mailbox known, opened
|
||||||
|
# We've definitely tried to open the mailbox at least once, but it must
|
||||||
|
# be re-opened with each connection, because open() is also subscribe()
|
||||||
@m.state()
|
@m.state()
|
||||||
def S2A(self): pass
|
def S2A(self): pass
|
||||||
@m.state()
|
@m.state()
|
||||||
def S2B(self): pass
|
def S2B(self): pass
|
||||||
|
|
||||||
# S3: nameplate claimed, mailbox known, maybe open
|
# S3: closing
|
||||||
@m.state()
|
@m.state()
|
||||||
def S3A(self): pass
|
def S3A(self): pass
|
||||||
@m.state()
|
@m.state()
|
||||||
def S3B(self): pass
|
def S3B(self): pass
|
||||||
|
|
||||||
# S4: mailbox maybe open, nameplate maybe released
|
# S4: closed. We no longer care whether we're connected or not
|
||||||
# We've definitely opened the mailbox at least once, but it must be
|
#@m.state()
|
||||||
# re-opened with each connection, because open() is also subscribe()
|
#def S4A(self): pass
|
||||||
@m.state()
|
#@m.state()
|
||||||
def S4A(self): pass
|
#def S4B(self): pass
|
||||||
@m.state()
|
|
||||||
def S4B(self): pass
|
|
||||||
|
|
||||||
# S5: mailbox maybe open, nameplate released
|
|
||||||
@m.state()
|
|
||||||
def S5A(self): pass
|
|
||||||
@m.state()
|
|
||||||
def S5B(self): pass
|
|
||||||
|
|
||||||
# Src: waiting for release+close
|
|
||||||
@m.state()
|
|
||||||
def SrcA(self): pass
|
|
||||||
@m.state()
|
|
||||||
def SrcB(self): pass
|
|
||||||
# Sr: closed (or never opened), waiting for release
|
|
||||||
@m.state()
|
|
||||||
def SrA(self): pass
|
|
||||||
@m.state()
|
|
||||||
def SrB(self): pass
|
|
||||||
# Sc: released (or never claimed), waiting for close
|
|
||||||
@m.state()
|
|
||||||
def ScA(self): pass
|
|
||||||
@m.state()
|
|
||||||
def ScB(self): pass
|
|
||||||
# Ss: closed and released, waiting for stop
|
|
||||||
@m.state()
|
|
||||||
def SsB(self): pass
|
|
||||||
@m.state(terminal=True)
|
@m.state(terminal=True)
|
||||||
def Ss(self): pass
|
def S4(self): pass
|
||||||
|
S4A = S4
|
||||||
|
S4B = S4
|
||||||
|
|
||||||
|
|
||||||
# from Boss
|
# from Terminator
|
||||||
@m.input()
|
|
||||||
def set_nameplate(self, nameplate): pass
|
|
||||||
@m.input()
|
@m.input()
|
||||||
def close(self, mood): pass
|
def close(self, mood): pass
|
||||||
|
|
||||||
|
# from Nameplate
|
||||||
|
@m.input()
|
||||||
|
def got_mailbox(self, mailbox): pass
|
||||||
|
|
||||||
# from RendezvousConnector
|
# from RendezvousConnector
|
||||||
@m.input()
|
@m.input()
|
||||||
def connected(self): pass
|
def connected(self): pass
|
||||||
@m.input()
|
@m.input()
|
||||||
def lost(self): pass
|
def lost(self): pass
|
||||||
|
|
||||||
@m.input()
|
|
||||||
def rx_claimed(self, mailbox): pass
|
|
||||||
|
|
||||||
def rx_message(self, side, phase, body):
|
def rx_message(self, side, phase, body):
|
||||||
assert isinstance(side, type("")), type(side)
|
assert isinstance(side, type("")), type(side)
|
||||||
assert isinstance(phase, type("")), type(phase)
|
assert isinstance(phase, type("")), type(phase)
|
||||||
|
@ -115,11 +90,7 @@ class Mailbox(object):
|
||||||
@m.input()
|
@m.input()
|
||||||
def rx_message_theirs(self, phase, body): pass
|
def rx_message_theirs(self, phase, body): pass
|
||||||
@m.input()
|
@m.input()
|
||||||
def rx_released(self): pass
|
|
||||||
@m.input()
|
|
||||||
def rx_closed(self): pass
|
def rx_closed(self): pass
|
||||||
@m.input()
|
|
||||||
def stopped(self): pass
|
|
||||||
|
|
||||||
# from Send or Key
|
# from Send or Key
|
||||||
@m.input()
|
@m.input()
|
||||||
|
@ -130,16 +101,8 @@ class Mailbox(object):
|
||||||
|
|
||||||
|
|
||||||
@m.output()
|
@m.output()
|
||||||
def record_nameplate(self, nameplate):
|
def record_mailbox(self, mailbox):
|
||||||
self._nameplate = nameplate
|
self._mailbox = mailbox
|
||||||
@m.output()
|
|
||||||
def record_nameplate_and_RC_tx_claim(self, nameplate):
|
|
||||||
self._nameplate = nameplate
|
|
||||||
self._RC.tx_claim(self._nameplate)
|
|
||||||
@m.output()
|
|
||||||
def RC_tx_claim(self):
|
|
||||||
# when invoked via M.connected(), we must use the stored nameplate
|
|
||||||
self._RC.tx_claim(self._nameplate)
|
|
||||||
@m.output()
|
@m.output()
|
||||||
def RC_tx_open(self):
|
def RC_tx_open(self):
|
||||||
assert self._mailbox
|
assert self._mailbox
|
||||||
|
@ -150,7 +113,7 @@ class Mailbox(object):
|
||||||
assert isinstance(body, type(b"")), (type(body), phase, body)
|
assert isinstance(body, type(b"")), (type(body), phase, body)
|
||||||
self._pending_outbound[phase] = body
|
self._pending_outbound[phase] = body
|
||||||
@m.output()
|
@m.output()
|
||||||
def store_mailbox_and_RC_tx_open_and_drain(self, mailbox):
|
def record_mailbox_and_RC_tx_open_and_drain(self, mailbox):
|
||||||
self._mailbox = mailbox
|
self._mailbox = mailbox
|
||||||
self._RC.tx_open(mailbox)
|
self._RC.tx_open(mailbox)
|
||||||
self._drain()
|
self._drain()
|
||||||
|
@ -166,29 +129,15 @@ class Mailbox(object):
|
||||||
assert isinstance(body, type(b"")), type(body)
|
assert isinstance(body, type(b"")), type(body)
|
||||||
self._RC.tx_add(phase, body)
|
self._RC.tx_add(phase, body)
|
||||||
@m.output()
|
@m.output()
|
||||||
def RC_tx_release(self):
|
def N_release_and_accept(self, phase, body):
|
||||||
self._RC.tx_release()
|
self._N.release()
|
||||||
@m.output()
|
|
||||||
def RC_tx_release_and_accept(self, phase, body):
|
|
||||||
self._RC.tx_release()
|
|
||||||
self._accept(phase, body)
|
self._accept(phase, body)
|
||||||
@m.output()
|
@m.output()
|
||||||
def record_mood_and_RC_tx_release(self, mood):
|
|
||||||
self._mood = mood
|
|
||||||
self._RC.tx_release()
|
|
||||||
@m.output()
|
|
||||||
def record_mood_and_RC_tx_release_and_RC_tx_close(self, mood):
|
|
||||||
self._mood = mood
|
|
||||||
self._RC.tx_release()
|
|
||||||
self._RC.tx_close(self._mood)
|
|
||||||
@m.output()
|
|
||||||
def RC_tx_close(self):
|
def RC_tx_close(self):
|
||||||
assert self._mood
|
assert self._mood
|
||||||
self._RC.tx_close(self._mood)
|
self._RC_tx_close()
|
||||||
@m.output()
|
def _RC_tx_close(self):
|
||||||
def record_mood_and_RC_tx_close(self, mood):
|
self._RC.tx_close(self._mailbox, self._mood)
|
||||||
self._mood = mood
|
|
||||||
self._RC.tx_close(self._mood)
|
|
||||||
@m.output()
|
@m.output()
|
||||||
def accept(self, phase, body):
|
def accept(self, phase, body):
|
||||||
self._accept(phase, body)
|
self._accept(phase, body)
|
||||||
|
@ -203,98 +152,49 @@ class Mailbox(object):
|
||||||
def record_mood(self, mood):
|
def record_mood(self, mood):
|
||||||
self._mood = mood
|
self._mood = mood
|
||||||
@m.output()
|
@m.output()
|
||||||
def record_mood_and_RC_stop(self, mood):
|
def record_mood_and_RC_tx_close(self, mood):
|
||||||
self._mood = mood
|
self._mood = mood
|
||||||
self._RC_stop()
|
self._RC_rx_close()
|
||||||
@m.output()
|
@m.output()
|
||||||
def RC_stop(self):
|
def ignore_mood_and_T_mailbox_done(self, mood):
|
||||||
self._RC_stop()
|
self._T.mailbox_done()
|
||||||
def _RC_stop(self):
|
|
||||||
self._RC.stop()
|
|
||||||
@m.output()
|
@m.output()
|
||||||
def W_closed(self):
|
def T_mailbox_done(self):
|
||||||
self._B.closed()
|
self._T.mailbox_done()
|
||||||
|
|
||||||
S0A.upon(connected, enter=S0B, outputs=[])
|
S0A.upon(connected, enter=S0B, outputs=[])
|
||||||
S0A.upon(set_nameplate, enter=S1A, outputs=[record_nameplate])
|
S0A.upon(got_mailbox, enter=S1A, outputs=[record_mailbox])
|
||||||
S0A.upon(add_message, enter=S0A, outputs=[queue])
|
S0A.upon(add_message, enter=S0A, outputs=[queue])
|
||||||
|
S0A.upon(close, enter=S4A, outputs=[ignore_mood_and_T_mailbox_done])
|
||||||
S0B.upon(lost, enter=S0A, outputs=[])
|
S0B.upon(lost, enter=S0A, outputs=[])
|
||||||
S0B.upon(set_nameplate, enter=S2B, outputs=[record_nameplate_and_RC_tx_claim])
|
|
||||||
S0B.upon(add_message, enter=S0B, outputs=[queue])
|
S0B.upon(add_message, enter=S0B, outputs=[queue])
|
||||||
|
S0B.upon(close, enter=S4B, outputs=[ignore_mood_and_T_mailbox_done])
|
||||||
|
S0B.upon(got_mailbox, enter=S2B,
|
||||||
|
outputs=[record_mailbox_and_RC_tx_open_and_drain])
|
||||||
|
|
||||||
S1A.upon(connected, enter=S2B, outputs=[RC_tx_claim])
|
S1A.upon(connected, enter=S2B, outputs=[RC_tx_open, drain])
|
||||||
S1A.upon(add_message, enter=S1A, outputs=[queue])
|
S1A.upon(add_message, enter=S1A, outputs=[queue])
|
||||||
|
S1A.upon(close, enter=S4A, outputs=[ignore_mood_and_T_mailbox_done])
|
||||||
|
|
||||||
S2A.upon(connected, enter=S2B, outputs=[RC_tx_claim])
|
S2A.upon(connected, enter=S2B, outputs=[RC_tx_open, drain])
|
||||||
S2A.upon(add_message, enter=S2A, outputs=[queue])
|
S2A.upon(add_message, enter=S2A, outputs=[queue])
|
||||||
|
S2A.upon(close, enter=S3A, outputs=[record_mood])
|
||||||
S2B.upon(lost, enter=S2A, outputs=[])
|
S2B.upon(lost, enter=S2A, outputs=[])
|
||||||
S2B.upon(add_message, enter=S2B, outputs=[queue])
|
S2B.upon(add_message, enter=S2B, outputs=[queue, RC_tx_add])
|
||||||
S2B.upon(rx_claimed, enter=S3B,
|
S2B.upon(rx_message_theirs, enter=S2B, outputs=[N_release_and_accept])
|
||||||
outputs=[store_mailbox_and_RC_tx_open_and_drain])
|
S2B.upon(rx_message_ours, enter=S2B, outputs=[dequeue])
|
||||||
|
S2B.upon(close, enter=S3B, outputs=[record_mood_and_RC_tx_close])
|
||||||
|
|
||||||
S3A.upon(connected, enter=S3B, outputs=[RC_tx_open, drain])
|
S3A.upon(connected, enter=S3B, outputs=[RC_tx_close])
|
||||||
S3A.upon(add_message, enter=S3A, outputs=[queue])
|
|
||||||
S3B.upon(lost, enter=S3A, outputs=[])
|
S3B.upon(lost, enter=S3A, outputs=[])
|
||||||
S3B.upon(rx_message_theirs, enter=S4B, outputs=[RC_tx_release_and_accept])
|
S3B.upon(rx_closed, enter=S4B, outputs=[T_mailbox_done])
|
||||||
S3B.upon(rx_message_ours, enter=S3B, outputs=[dequeue])
|
S3B.upon(add_message, enter=S3B, outputs=[])
|
||||||
S3B.upon(rx_claimed, enter=S3B, outputs=[])
|
S3B.upon(rx_message_theirs, enter=S3B, outputs=[])
|
||||||
S3B.upon(add_message, enter=S3B, outputs=[queue, RC_tx_add])
|
S3B.upon(rx_message_ours, enter=S3B, outputs=[])
|
||||||
|
|
||||||
S4A.upon(connected, enter=S4B, outputs=[RC_tx_open, drain, RC_tx_release])
|
S4A.upon(connected, enter=S4B, outputs=[])
|
||||||
S4A.upon(add_message, enter=S4A, outputs=[queue])
|
|
||||||
S4B.upon(lost, enter=S4A, outputs=[])
|
S4B.upon(lost, enter=S4A, outputs=[])
|
||||||
S4B.upon(add_message, enter=S4B, outputs=[queue, RC_tx_add])
|
S4.upon(add_message, enter=S4, outputs=[])
|
||||||
S4B.upon(rx_message_theirs, enter=S4B, outputs=[accept])
|
S4.upon(rx_message_theirs, enter=S4, outputs=[])
|
||||||
S4B.upon(rx_message_ours, enter=S4B, outputs=[dequeue])
|
S4.upon(rx_message_ours, enter=S4, outputs=[])
|
||||||
S4B.upon(rx_released, enter=S5B, outputs=[])
|
|
||||||
|
|
||||||
S5A.upon(connected, enter=S5B, outputs=[RC_tx_open, drain])
|
|
||||||
S5A.upon(add_message, enter=S5A, outputs=[queue])
|
|
||||||
S5B.upon(lost, enter=S5A, outputs=[])
|
|
||||||
S5B.upon(add_message, enter=S5B, outputs=[queue, RC_tx_add])
|
|
||||||
S5B.upon(rx_message_theirs, enter=S5B, outputs=[accept])
|
|
||||||
S5B.upon(rx_message_ours, enter=S5B, outputs=[dequeue])
|
|
||||||
|
|
||||||
if True:
|
|
||||||
S0A.upon(close, enter=SsB, outputs=[record_mood_and_RC_stop])
|
|
||||||
S0B.upon(close, enter=SsB, outputs=[record_mood_and_RC_stop])
|
|
||||||
S1A.upon(close, enter=SsB, outputs=[record_mood_and_RC_stop])
|
|
||||||
S2A.upon(close, enter=SrA, outputs=[record_mood])
|
|
||||||
S2B.upon(close, enter=SrB, outputs=[record_mood_and_RC_tx_release])
|
|
||||||
S3A.upon(close, enter=SrcA, outputs=[record_mood])
|
|
||||||
S3B.upon(close, enter=SrcB,
|
|
||||||
outputs=[record_mood_and_RC_tx_release_and_RC_tx_close])
|
|
||||||
S4A.upon(close, enter=SrcA, outputs=[record_mood])
|
|
||||||
S4B.upon(close, enter=SrcB, outputs=[record_mood_and_RC_tx_close])
|
|
||||||
S5A.upon(close, enter=ScA, outputs=[record_mood])
|
|
||||||
S5B.upon(close, enter=ScB, outputs=[record_mood_and_RC_tx_close])
|
|
||||||
|
|
||||||
SrcA.upon(connected, enter=SrcB, outputs=[RC_tx_release, RC_tx_close])
|
|
||||||
SrcB.upon(lost, enter=SrcA, outputs=[])
|
|
||||||
SrcB.upon(rx_closed, enter=SrB, outputs=[])
|
|
||||||
SrcB.upon(rx_released, enter=ScB, outputs=[])
|
|
||||||
|
|
||||||
SrB.upon(lost, enter=SrA, outputs=[])
|
|
||||||
SrA.upon(connected, enter=SrB, outputs=[RC_tx_release])
|
|
||||||
SrB.upon(rx_released, enter=SsB, outputs=[RC_stop])
|
|
||||||
|
|
||||||
ScB.upon(lost, enter=ScA, outputs=[])
|
|
||||||
ScB.upon(rx_closed, enter=SsB, outputs=[RC_stop])
|
|
||||||
ScA.upon(connected, enter=ScB, outputs=[RC_tx_close])
|
|
||||||
|
|
||||||
SsB.upon(lost, enter=SsB, outputs=[])
|
|
||||||
SsB.upon(stopped, enter=Ss, outputs=[W_closed])
|
|
||||||
|
|
||||||
SrcB.upon(rx_claimed, enter=SrcB, outputs=[])
|
|
||||||
SrcB.upon(rx_message_theirs, enter=SrcB, outputs=[])
|
|
||||||
SrcB.upon(rx_message_ours, enter=SrcB, outputs=[])
|
|
||||||
SrB.upon(rx_claimed, enter=SrB, outputs=[])
|
|
||||||
SrB.upon(rx_message_theirs, enter=SrB, outputs=[])
|
|
||||||
SrB.upon(rx_message_ours, enter=SrB, outputs=[])
|
|
||||||
ScB.upon(rx_claimed, enter=ScB, outputs=[])
|
|
||||||
ScB.upon(rx_message_theirs, enter=ScB, outputs=[])
|
|
||||||
ScB.upon(rx_message_ours, enter=ScB, outputs=[])
|
|
||||||
SsB.upon(rx_claimed, enter=SsB, outputs=[])
|
|
||||||
SsB.upon(rx_message_theirs, enter=SsB, outputs=[])
|
|
||||||
SsB.upon(rx_message_ours, enter=SsB, outputs=[])
|
|
||||||
|
|
||||||
|
|
|
@ -3,63 +3,142 @@ from zope.interface import implementer
|
||||||
from automat import MethodicalMachine
|
from automat import MethodicalMachine
|
||||||
from . import _interfaces
|
from . import _interfaces
|
||||||
|
|
||||||
@implementer(_interfaces.INameplateLister)
|
@implementer(_interfaces.INameplate)
|
||||||
class NameplateListing(object):
|
class Nameplate(object):
|
||||||
m = MethodicalMachine()
|
m = MethodicalMachine()
|
||||||
|
@m.setTrace()
|
||||||
|
def setTrace(): pass
|
||||||
|
|
||||||
def wire(self, rendezvous_connector, code):
|
def __init__(self):
|
||||||
|
self._nameplate = None
|
||||||
|
|
||||||
|
def wire(self, mailbox, rendezvous_connector, terminator):
|
||||||
|
self._M = _interfaces.IMailbox(mailbox)
|
||||||
self._RC = _interfaces.IRendezvousConnector(rendezvous_connector)
|
self._RC = _interfaces.IRendezvousConnector(rendezvous_connector)
|
||||||
self._C = _interfaces.ICode(code)
|
self._T = _interfaces.ITerminator(terminator)
|
||||||
|
|
||||||
# Ideally, each API request would spawn a new "list_nameplates" message
|
# all -A states: not connected
|
||||||
# to the server, so the response would be maximally fresh, but that would
|
# all -B states: yes connected
|
||||||
# require correlating server request+response messages, and the protocol
|
# B states serialize as A, so they deserialize as unconnected
|
||||||
# is intended to be less stateful than that. So we offer a weaker
|
|
||||||
# freshness property: if no server requests are in flight, then a new API
|
|
||||||
# request will provoke a new server request, and the result will be
|
|
||||||
# fresh. But if a server request is already in flight when a second API
|
|
||||||
# request arrives, both requests will be satisfied by the same response.
|
|
||||||
|
|
||||||
|
# S0: know nothing
|
||||||
@m.state(initial=True)
|
@m.state(initial=True)
|
||||||
def S0A_idle_disconnected(self): pass
|
def S0A(self): pass
|
||||||
@m.state()
|
@m.state()
|
||||||
def S1A_wanting_disconnected(self): pass
|
def S0B(self): pass
|
||||||
@m.state()
|
|
||||||
def S0B_idle_connected(self): pass
|
|
||||||
@m.state()
|
|
||||||
def S1B_wanting_connected(self): pass
|
|
||||||
|
|
||||||
|
# S1: nameplate known, never claimed
|
||||||
|
@m.state()
|
||||||
|
def S1A(self): pass
|
||||||
|
|
||||||
|
# S2: nameplate known, maybe claimed
|
||||||
|
@m.state()
|
||||||
|
def S2A(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S2B(self): pass
|
||||||
|
|
||||||
|
# S3: nameplate claimed
|
||||||
|
@m.state()
|
||||||
|
def S3A(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S3B(self): pass
|
||||||
|
|
||||||
|
# S4: maybe released
|
||||||
|
@m.state()
|
||||||
|
def S4A(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S4B(self): pass
|
||||||
|
|
||||||
|
# S5: released
|
||||||
|
# we no longer care whether we're connected or not
|
||||||
|
#@m.state()
|
||||||
|
#def S5A(self): pass
|
||||||
|
#@m.state()
|
||||||
|
#def S5B(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S5(self): pass
|
||||||
|
S5A = S5
|
||||||
|
S5B = S5
|
||||||
|
|
||||||
|
# from Boss
|
||||||
|
@m.input()
|
||||||
|
def set_nameplate(self, nameplate): pass
|
||||||
|
|
||||||
|
# from Mailbox
|
||||||
|
@m.input()
|
||||||
|
def release(self): pass
|
||||||
|
|
||||||
|
# from Terminator
|
||||||
|
@m.input()
|
||||||
|
def close(self): pass
|
||||||
|
|
||||||
|
# from RendezvousConnector
|
||||||
@m.input()
|
@m.input()
|
||||||
def connected(self): pass
|
def connected(self): pass
|
||||||
@m.input()
|
@m.input()
|
||||||
def lost(self): pass
|
def lost(self): pass
|
||||||
|
|
||||||
@m.input()
|
@m.input()
|
||||||
def refresh_nameplates(self): pass
|
def rx_claimed(self, mailbox): pass
|
||||||
@m.input()
|
@m.input()
|
||||||
def rx_nameplates(self, message): pass
|
def rx_released(self): pass
|
||||||
|
|
||||||
|
|
||||||
@m.output()
|
@m.output()
|
||||||
def RC_tx_list(self):
|
def record_nameplate(self, nameplate):
|
||||||
self._RC.tx_list()
|
self._nameplate = nameplate
|
||||||
@m.output()
|
@m.output()
|
||||||
def C_got_nameplates(self, message):
|
def record_nameplate_and_RC_tx_claim(self, nameplate):
|
||||||
self._C.got_nameplates(message["nameplates"])
|
self._nameplate = nameplate
|
||||||
|
self._RC.tx_claim(self._nameplate)
|
||||||
|
@m.output()
|
||||||
|
def RC_tx_claim(self):
|
||||||
|
# when invoked via M.connected(), we must use the stored nameplate
|
||||||
|
self._RC.tx_claim(self._nameplate)
|
||||||
|
@m.output()
|
||||||
|
def M_got_mailbox(self, mailbox):
|
||||||
|
self._M.got_mailbox(mailbox)
|
||||||
|
@m.output()
|
||||||
|
def RC_tx_release(self):
|
||||||
|
assert self._nameplate
|
||||||
|
self._RC.tx_release(self._nameplate)
|
||||||
|
@m.output()
|
||||||
|
def T_nameplate_done(self):
|
||||||
|
self._T.nameplate_done()
|
||||||
|
|
||||||
S0A_idle_disconnected.upon(connected, enter=S0B_idle_connected, outputs=[])
|
S0A.upon(set_nameplate, enter=S1A, outputs=[record_nameplate])
|
||||||
S0B_idle_connected.upon(lost, enter=S0A_idle_disconnected, outputs=[])
|
S0A.upon(connected, enter=S0B, outputs=[])
|
||||||
|
S0A.upon(close, enter=S5A, outputs=[T_nameplate_done])
|
||||||
|
S0B.upon(set_nameplate, enter=S2B,
|
||||||
|
outputs=[record_nameplate_and_RC_tx_claim])
|
||||||
|
S0B.upon(lost, enter=S0A, outputs=[])
|
||||||
|
S0B.upon(close, enter=S5A, outputs=[T_nameplate_done])
|
||||||
|
|
||||||
S0A_idle_disconnected.upon(refresh_nameplates,
|
S1A.upon(connected, enter=S2B, outputs=[RC_tx_claim])
|
||||||
enter=S1A_wanting_disconnected, outputs=[])
|
S1A.upon(close, enter=S5A, outputs=[T_nameplate_done])
|
||||||
S1A_wanting_disconnected.upon(refresh_nameplates,
|
|
||||||
enter=S1A_wanting_disconnected, outputs=[])
|
S2A.upon(connected, enter=S2B, outputs=[RC_tx_claim])
|
||||||
S1A_wanting_disconnected.upon(connected, enter=S1B_wanting_connected,
|
S2A.upon(close, enter=S4A, outputs=[])
|
||||||
outputs=[RC_tx_list])
|
S2B.upon(lost, enter=S2A, outputs=[])
|
||||||
S0B_idle_connected.upon(refresh_nameplates, enter=S1B_wanting_connected,
|
S2B.upon(rx_claimed, enter=S3B, outputs=[M_got_mailbox])
|
||||||
outputs=[RC_tx_list])
|
S2B.upon(close, enter=S4B, outputs=[RC_tx_release])
|
||||||
S0B_idle_connected.upon(rx_nameplates, enter=S0B_idle_connected,
|
|
||||||
outputs=[C_got_nameplates])
|
S3A.upon(connected, enter=S3B, outputs=[])
|
||||||
S1B_wanting_connected.upon(lost, enter=S1A_wanting_disconnected, outputs=[])
|
S3A.upon(close, enter=S4A, outputs=[])
|
||||||
S1B_wanting_connected.upon(refresh_nameplates, enter=S1B_wanting_connected,
|
S3B.upon(lost, enter=S3A, outputs=[])
|
||||||
outputs=[RC_tx_list])
|
#S3B.upon(rx_claimed, enter=S3B, outputs=[]) # shouldn't happen
|
||||||
S1B_wanting_connected.upon(rx_nameplates, enter=S0B_idle_connected,
|
S3B.upon(release, enter=S4B, outputs=[RC_tx_release])
|
||||||
outputs=[C_got_nameplates])
|
S3B.upon(close, enter=S4B, outputs=[RC_tx_release])
|
||||||
|
|
||||||
|
S4A.upon(connected, enter=S4B, outputs=[RC_tx_release])
|
||||||
|
S4A.upon(close, enter=S4A, outputs=[])
|
||||||
|
S4B.upon(lost, enter=S4A, outputs=[])
|
||||||
|
S4B.upon(rx_released, enter=S5B, outputs=[T_nameplate_done])
|
||||||
|
S4B.upon(release, enter=S4B, outputs=[]) # mailbox is lazy
|
||||||
|
# Mailbox doesn't remember how many times it's sent a release, and will
|
||||||
|
# re-send a new one for each peer message it receives. Ignoring it here
|
||||||
|
# is easier than adding a new pair of states to Mailbox.
|
||||||
|
S4B.upon(close, enter=S4B, outputs=[])
|
||||||
|
|
||||||
|
S5A.upon(connected, enter=S5B, outputs=[])
|
||||||
|
S5B.upon(lost, enter=S5A, outputs=[])
|
||||||
|
|
65
src/wormhole/_nameplate_lister.py
Normal file
65
src/wormhole/_nameplate_lister.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
from __future__ import print_function, absolute_import, unicode_literals
|
||||||
|
from zope.interface import implementer
|
||||||
|
from automat import MethodicalMachine
|
||||||
|
from . import _interfaces
|
||||||
|
|
||||||
|
@implementer(_interfaces.INameplateLister)
|
||||||
|
class NameplateListing(object):
|
||||||
|
m = MethodicalMachine()
|
||||||
|
|
||||||
|
def wire(self, rendezvous_connector, code):
|
||||||
|
self._RC = _interfaces.IRendezvousConnector(rendezvous_connector)
|
||||||
|
self._C = _interfaces.ICode(code)
|
||||||
|
|
||||||
|
# Ideally, each API request would spawn a new "list_nameplates" message
|
||||||
|
# to the server, so the response would be maximally fresh, but that would
|
||||||
|
# require correlating server request+response messages, and the protocol
|
||||||
|
# is intended to be less stateful than that. So we offer a weaker
|
||||||
|
# freshness property: if no server requests are in flight, then a new API
|
||||||
|
# request will provoke a new server request, and the result will be
|
||||||
|
# fresh. But if a server request is already in flight when a second API
|
||||||
|
# request arrives, both requests will be satisfied by the same response.
|
||||||
|
|
||||||
|
@m.state(initial=True)
|
||||||
|
def S0A_idle_disconnected(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S1A_wanting_disconnected(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S0B_idle_connected(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S1B_wanting_connected(self): pass
|
||||||
|
|
||||||
|
@m.input()
|
||||||
|
def connected(self): pass
|
||||||
|
@m.input()
|
||||||
|
def lost(self): pass
|
||||||
|
@m.input()
|
||||||
|
def refresh_nameplates(self): pass
|
||||||
|
@m.input()
|
||||||
|
def rx_nameplates(self, message): pass
|
||||||
|
|
||||||
|
@m.output()
|
||||||
|
def RC_tx_list(self):
|
||||||
|
self._RC.tx_list()
|
||||||
|
@m.output()
|
||||||
|
def C_got_nameplates(self, message):
|
||||||
|
self._C.got_nameplates(message["nameplates"])
|
||||||
|
|
||||||
|
S0A_idle_disconnected.upon(connected, enter=S0B_idle_connected, outputs=[])
|
||||||
|
S0B_idle_connected.upon(lost, enter=S0A_idle_disconnected, outputs=[])
|
||||||
|
|
||||||
|
S0A_idle_disconnected.upon(refresh_nameplates,
|
||||||
|
enter=S1A_wanting_disconnected, outputs=[])
|
||||||
|
S1A_wanting_disconnected.upon(refresh_nameplates,
|
||||||
|
enter=S1A_wanting_disconnected, outputs=[])
|
||||||
|
S1A_wanting_disconnected.upon(connected, enter=S1B_wanting_connected,
|
||||||
|
outputs=[RC_tx_list])
|
||||||
|
S0B_idle_connected.upon(refresh_nameplates, enter=S1B_wanting_connected,
|
||||||
|
outputs=[RC_tx_list])
|
||||||
|
S0B_idle_connected.upon(rx_nameplates, enter=S0B_idle_connected,
|
||||||
|
outputs=[C_got_nameplates])
|
||||||
|
S1B_wanting_connected.upon(lost, enter=S1A_wanting_disconnected, outputs=[])
|
||||||
|
S1B_wanting_connected.upon(refresh_nameplates, enter=S1B_wanting_connected,
|
||||||
|
outputs=[RC_tx_list])
|
||||||
|
S1B_wanting_connected.upon(rx_nameplates, enter=S0B_idle_connected,
|
||||||
|
outputs=[C_got_nameplates])
|
|
@ -106,11 +106,11 @@ class RendezvousConnector(object):
|
||||||
assert isinstance(body, type(b"")), type(body)
|
assert isinstance(body, type(b"")), type(body)
|
||||||
self._tx("add", phase=phase, body=bytes_to_hexstr(body))
|
self._tx("add", phase=phase, body=bytes_to_hexstr(body))
|
||||||
|
|
||||||
def tx_release(self):
|
def tx_release(self, nameplate):
|
||||||
self._tx("release")
|
self._tx("release", nameplate=nameplate)
|
||||||
|
|
||||||
def tx_close(self, mood):
|
def tx_close(self, mailbox, mood):
|
||||||
self._tx("close", mood=mood)
|
self._tx("close", mailbox=mailbox, mood=mood)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
d = defer.maybeDeferred(self._connector.stopService)
|
d = defer.maybeDeferred(self._connector.stopService)
|
||||||
|
|
104
src/wormhole/_terminator.py
Normal file
104
src/wormhole/_terminator.py
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
from __future__ import print_function, absolute_import, unicode_literals
|
||||||
|
from zope.interface import implementer
|
||||||
|
from automat import MethodicalMachine
|
||||||
|
from . import _interfaces
|
||||||
|
|
||||||
|
@implementer(_interfaces.ITerminator)
|
||||||
|
class Terminator(object):
|
||||||
|
m = MethodicalMachine()
|
||||||
|
@m.setTrace()
|
||||||
|
def setTrace(): pass
|
||||||
|
|
||||||
|
def __attrs_post_init__(self):
|
||||||
|
self._mood = None
|
||||||
|
|
||||||
|
def wire(self, boss, rendezvous_connector, nameplate, mailbox):
|
||||||
|
self._B = _interfaces.IBoss(boss)
|
||||||
|
self._RC = _interfaces.IRendezvousConnector(rendezvous_connector)
|
||||||
|
self._N = _interfaces.INameplate(nameplate)
|
||||||
|
self._M = _interfaces.IMailbox(mailbox)
|
||||||
|
|
||||||
|
# 4*2-1 main states:
|
||||||
|
# (nm, m, n, 0): nameplate and/or mailbox is active
|
||||||
|
# (o, ""): open (not-yet-closing), or trying to close
|
||||||
|
# S0 is special: we don't hang out in it
|
||||||
|
|
||||||
|
# We start in Snmo (non-closing). When both nameplate and mailboxes are
|
||||||
|
# done, and we're closing, then we stop the RendezvousConnector
|
||||||
|
|
||||||
|
@m.state(initial=True)
|
||||||
|
def Snmo(self): pass
|
||||||
|
@m.state()
|
||||||
|
def Smo(self): pass
|
||||||
|
@m.state()
|
||||||
|
def Sno(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S0o(self): pass
|
||||||
|
|
||||||
|
@m.state()
|
||||||
|
def Snm(self): pass
|
||||||
|
@m.state()
|
||||||
|
def Sm(self): pass
|
||||||
|
@m.state()
|
||||||
|
def Sn(self): pass
|
||||||
|
#@m.state()
|
||||||
|
#def S0(self): pass # unused
|
||||||
|
|
||||||
|
@m.state()
|
||||||
|
def S_stopping(self): pass
|
||||||
|
@m.state()
|
||||||
|
def S_stopped(self, terminal=True): pass
|
||||||
|
|
||||||
|
# from Boss
|
||||||
|
@m.input()
|
||||||
|
def close(self, mood): pass
|
||||||
|
|
||||||
|
# from Nameplate
|
||||||
|
@m.input()
|
||||||
|
def nameplate_done(self): pass
|
||||||
|
|
||||||
|
# from Mailbox
|
||||||
|
@m.input()
|
||||||
|
def mailbox_done(self): pass
|
||||||
|
|
||||||
|
# from RendezvousConnector
|
||||||
|
@m.input()
|
||||||
|
def stopped(self): pass
|
||||||
|
|
||||||
|
|
||||||
|
@m.output()
|
||||||
|
def close_nameplate(self, mood):
|
||||||
|
self._N.close() # ignores mood
|
||||||
|
@m.output()
|
||||||
|
def close_mailbox(self, mood):
|
||||||
|
self._M.close(mood)
|
||||||
|
|
||||||
|
@m.output()
|
||||||
|
def ignore_mood_and_RC_stop(self, mood):
|
||||||
|
self._RC.stop()
|
||||||
|
@m.output()
|
||||||
|
def RC_stop(self):
|
||||||
|
self._RC.stop()
|
||||||
|
@m.output()
|
||||||
|
def B_closed(self):
|
||||||
|
self._B.closed()
|
||||||
|
|
||||||
|
Snmo.upon(mailbox_done, enter=Sno, outputs=[])
|
||||||
|
Snmo.upon(close, enter=Snm, outputs=[close_nameplate, close_mailbox])
|
||||||
|
Snmo.upon(nameplate_done, enter=Smo, outputs=[])
|
||||||
|
|
||||||
|
Sno.upon(close, enter=Sn, outputs=[close_nameplate, close_mailbox])
|
||||||
|
Sno.upon(nameplate_done, enter=S0o, outputs=[])
|
||||||
|
|
||||||
|
Smo.upon(close, enter=Sm, outputs=[close_nameplate, close_mailbox])
|
||||||
|
Smo.upon(mailbox_done, enter=S0o, outputs=[])
|
||||||
|
|
||||||
|
Snm.upon(mailbox_done, enter=Sn, outputs=[])
|
||||||
|
Snm.upon(nameplate_done, enter=Sm, outputs=[])
|
||||||
|
|
||||||
|
Sn.upon(nameplate_done, enter=S_stopping, outputs=[RC_stop])
|
||||||
|
S0o.upon(close, enter=S_stopping,
|
||||||
|
outputs=[close_nameplate, close_mailbox, ignore_mood_and_RC_stop])
|
||||||
|
Sm.upon(mailbox_done, enter=S_stopping, outputs=[RC_stop])
|
||||||
|
|
||||||
|
S_stopping.upon(stopped, enter=S_stopped, outputs=[B_closed])
|
Loading…
Reference in New Issue
Block a user