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 -> 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
|
||||
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
|
||||
S1 [label="S1: lonely" color="orange"]
|
||||
|
||||
|
@ -31,15 +31,15 @@ digraph {
|
|||
S1 -> P_close_error [label="rx_error"]
|
||||
S1 -> P_close_scary [label="scared" color="red"]
|
||||
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_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"]
|
||||
|
||||
S2 [label="S2: happy" color="green"]
|
||||
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
|
||||
|
||||
S2 -> P2_got_message [label="got_message"]
|
||||
|
|
|
@ -3,37 +3,37 @@ digraph {
|
|||
title [label="Terminator\nMachine" style="dotted"]
|
||||
|
||||
initial [style="invis"]
|
||||
initial -> Snm [style="dashed"]
|
||||
initial -> Snmo [style="dashed"]
|
||||
|
||||
Snm [label="Snm:\nnameplate active\nmailbox active" color="orange"]
|
||||
Sn [label="Sn:\nnameplate active\nmailbox done"]
|
||||
Sm [label="Sm:\nnameplate done\nmailbox active" color="green"]
|
||||
S0 [label="S0:\nnameplate done\nmailbox done"]
|
||||
Snmo [label="Snmo:\nnameplate active\nmailbox active\nopen" color="orange"]
|
||||
Sno [label="Sno:\nnameplate active\nmailbox done\nopen"]
|
||||
Smo [label="Smo:\nnameplate done\nmailbox active\nopen" color="green"]
|
||||
S0o [label="S0o:\nnameplate done\nmailbox done\nopen"]
|
||||
|
||||
Snm -> Sn [label="mailbox_done"]
|
||||
Snm -> Sm [label="nameplate_done" color="orange"]
|
||||
Sn -> S0 [label="nameplate_done"]
|
||||
Sm -> S0 [label="mailbox_done"]
|
||||
Snmo -> Sno [label="mailbox_done"]
|
||||
Snmo -> Smo [label="nameplate_done" color="orange"]
|
||||
Sno -> S0o [label="nameplate_done"]
|
||||
Smo -> S0o [label="mailbox_done"]
|
||||
|
||||
Snm -> Snm_closing [label="close"]
|
||||
Sn -> Sn_closing [label="close"]
|
||||
Sm -> Sm_closing [label="close" color="red"]
|
||||
S0 -> P_stop [label="close"]
|
||||
Snmo -> Snm [label="close"]
|
||||
Sno -> Sn [label="close"]
|
||||
Smo -> Sm [label="close" color="red"]
|
||||
S0o -> P_stop [label="close"]
|
||||
|
||||
Snm_closing [label="Snm_closing:\nnameplate active\nmailbox active"
|
||||
Snm [label="Snm:\nnameplate active\nmailbox active\nclosing"
|
||||
style="dashed"]
|
||||
Sn_closing [label="Sn_closing:\nnameplate active\nmailbox done"
|
||||
Sn [label="Sn:\nnameplate active\nmailbox done\nclosing"
|
||||
style="dashed"]
|
||||
Sm_closing [label="Sm_closing:\nnameplate done\nmailbox active"
|
||||
Sm [label="Sm:\nnameplate done\nmailbox active\nclosing"
|
||||
style="dashed" color="red"]
|
||||
|
||||
Snm_closing -> Sn_closing [label="mailbox_done"]
|
||||
Snm_closing -> Sm_closing [label="nameplate_done"]
|
||||
Sn_closing -> P_stop [label="nameplate_done"]
|
||||
Sm_closing -> P_stop [label="mailbox_done" color="red"]
|
||||
Snm -> Sn [label="mailbox_done"]
|
||||
Snm -> Sm [label="nameplate_done"]
|
||||
Sn -> P_stop [label="nameplate_done"]
|
||||
Sm -> P_stop [label="mailbox_done" color="red"]
|
||||
|
||||
{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"]
|
||||
|
||||
S_stopping [label="S_stopping" color="red"]
|
||||
|
|
|
@ -7,14 +7,16 @@ from attr.validators import provides, instance_of
|
|||
from twisted.python import log
|
||||
from automat import MethodicalMachine
|
||||
from . import _interfaces
|
||||
from ._nameplate import Nameplate
|
||||
from ._mailbox import Mailbox
|
||||
from ._send import Send
|
||||
from ._order import Order
|
||||
from ._key import Key
|
||||
from ._receive import Receive
|
||||
from ._rendezvous import RendezvousConnector
|
||||
from ._nameplate import NameplateListing
|
||||
from ._nameplate_lister import NameplateListing
|
||||
from ._code import Code
|
||||
from ._terminator import Terminator
|
||||
from .errors import WrongPasswordError
|
||||
from .util import bytes_to_dict
|
||||
|
||||
|
@ -34,6 +36,7 @@ class Boss(object):
|
|||
m = MethodicalMachine()
|
||||
|
||||
def __attrs_post_init__(self):
|
||||
self._N = Nameplate()
|
||||
self._M = Mailbox(self._side)
|
||||
self._S = Send(self._side, self._timing)
|
||||
self._O = Order(self._side, self._timing)
|
||||
|
@ -44,8 +47,10 @@ class Boss(object):
|
|||
self._timing)
|
||||
self._NL = NameplateListing()
|
||||
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._O.wire(self._K, 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._NL.wire(self._RC, self._C)
|
||||
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_rx_phase = 0
|
||||
|
@ -137,7 +143,7 @@ class Boss(object):
|
|||
@m.input()
|
||||
def got_verifier(self, verifier): pass
|
||||
|
||||
# Mailbox sends closed
|
||||
# Terminator sends closed
|
||||
@m.input()
|
||||
def closed(self): pass
|
||||
|
||||
|
@ -149,7 +155,7 @@ class Boss(object):
|
|||
@m.output()
|
||||
def do_got_code(self, code):
|
||||
nameplate = code.split("-")[0]
|
||||
self._M.set_nameplate(nameplate)
|
||||
self._N.set_nameplate(nameplate)
|
||||
self._K.got_code(code)
|
||||
self._W.got_code(code)
|
||||
@m.output()
|
||||
|
@ -167,19 +173,19 @@ class Boss(object):
|
|||
@m.output()
|
||||
def close_error(self, err, orig):
|
||||
self._result = WormholeError(err)
|
||||
self._M.close("errory")
|
||||
self._T.close("errory")
|
||||
@m.output()
|
||||
def close_scared(self):
|
||||
self._result = WrongPasswordError()
|
||||
self._M.close("scary")
|
||||
self._T.close("scary")
|
||||
@m.output()
|
||||
def close_lonely(self):
|
||||
self._result = WormholeError("lonely")
|
||||
self._M.close("lonely")
|
||||
self._T.close("lonely")
|
||||
@m.output()
|
||||
def close_happy(self):
|
||||
self._result = "happy"
|
||||
self._M.close("happy")
|
||||
self._T.close("happy")
|
||||
|
||||
@m.output()
|
||||
def W_got_verifier(self, verifier):
|
||||
|
|
|
@ -4,6 +4,8 @@ class IWormhole(Interface):
|
|||
pass
|
||||
class IBoss(Interface):
|
||||
pass
|
||||
class INameplate(Interface):
|
||||
pass
|
||||
class IMailbox(Interface):
|
||||
pass
|
||||
class ISend(Interface):
|
||||
|
@ -20,6 +22,8 @@ class INameplateLister(Interface):
|
|||
pass
|
||||
class ICode(Interface):
|
||||
pass
|
||||
class ITerminator(Interface):
|
||||
pass
|
||||
|
||||
class ITiming(Interface):
|
||||
pass
|
||||
|
|
|
@ -14,16 +14,15 @@ class Mailbox(object):
|
|||
def setTrace(): pass
|
||||
|
||||
def __attrs_post_init__(self):
|
||||
self._mood = None
|
||||
self._nameplate = None
|
||||
self._mailbox = None
|
||||
self._pending_outbound = {}
|
||||
self._processed = set()
|
||||
|
||||
def wire(self, boss, rendezvous_connector, ordering):
|
||||
self._B = _interfaces.IBoss(boss)
|
||||
def wire(self, nameplate, rendezvous_connector, ordering, terminator):
|
||||
self._N = _interfaces.INameplate(nameplate)
|
||||
self._RC = _interfaces.IRendezvousConnector(rendezvous_connector)
|
||||
self._O = _interfaces.IOrder(ordering)
|
||||
self._T = _interfaces.ITerminator(terminator)
|
||||
|
||||
# all -A states: not connected
|
||||
# all -B states: yes connected
|
||||
|
@ -35,73 +34,49 @@ class Mailbox(object):
|
|||
@m.state()
|
||||
def S0B(self): pass
|
||||
|
||||
# S1: nameplate known, not claimed
|
||||
# S1: mailbox known, not opened
|
||||
@m.state()
|
||||
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()
|
||||
def S2A(self): pass
|
||||
@m.state()
|
||||
def S2B(self): pass
|
||||
|
||||
# S3: nameplate claimed, mailbox known, maybe open
|
||||
# S3: closing
|
||||
@m.state()
|
||||
def S3A(self): pass
|
||||
@m.state()
|
||||
def S3B(self): pass
|
||||
|
||||
# S4: mailbox maybe open, nameplate maybe released
|
||||
# We've definitely opened the mailbox at least once, but it must be
|
||||
# re-opened with each connection, because open() is also subscribe()
|
||||
@m.state()
|
||||
def S4A(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
|
||||
# S4: closed. We no longer care whether we're connected or not
|
||||
#@m.state()
|
||||
#def S4A(self): pass
|
||||
#@m.state()
|
||||
#def S4B(self): pass
|
||||
@m.state(terminal=True)
|
||||
def Ss(self): pass
|
||||
def S4(self): pass
|
||||
S4A = S4
|
||||
S4B = S4
|
||||
|
||||
|
||||
# from Boss
|
||||
@m.input()
|
||||
def set_nameplate(self, nameplate): pass
|
||||
# from Terminator
|
||||
@m.input()
|
||||
def close(self, mood): pass
|
||||
|
||||
# from Nameplate
|
||||
@m.input()
|
||||
def got_mailbox(self, mailbox): pass
|
||||
|
||||
# from RendezvousConnector
|
||||
@m.input()
|
||||
def connected(self): pass
|
||||
@m.input()
|
||||
def lost(self): pass
|
||||
|
||||
@m.input()
|
||||
def rx_claimed(self, mailbox): pass
|
||||
|
||||
def rx_message(self, side, phase, body):
|
||||
assert isinstance(side, type("")), type(side)
|
||||
assert isinstance(phase, type("")), type(phase)
|
||||
|
@ -115,11 +90,7 @@ class Mailbox(object):
|
|||
@m.input()
|
||||
def rx_message_theirs(self, phase, body): pass
|
||||
@m.input()
|
||||
def rx_released(self): pass
|
||||
@m.input()
|
||||
def rx_closed(self): pass
|
||||
@m.input()
|
||||
def stopped(self): pass
|
||||
|
||||
# from Send or Key
|
||||
@m.input()
|
||||
|
@ -130,16 +101,8 @@ class Mailbox(object):
|
|||
|
||||
|
||||
@m.output()
|
||||
def record_nameplate(self, nameplate):
|
||||
self._nameplate = nameplate
|
||||
@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)
|
||||
def record_mailbox(self, mailbox):
|
||||
self._mailbox = mailbox
|
||||
@m.output()
|
||||
def RC_tx_open(self):
|
||||
assert self._mailbox
|
||||
|
@ -150,7 +113,7 @@ class Mailbox(object):
|
|||
assert isinstance(body, type(b"")), (type(body), phase, body)
|
||||
self._pending_outbound[phase] = body
|
||||
@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._RC.tx_open(mailbox)
|
||||
self._drain()
|
||||
|
@ -166,29 +129,15 @@ class Mailbox(object):
|
|||
assert isinstance(body, type(b"")), type(body)
|
||||
self._RC.tx_add(phase, body)
|
||||
@m.output()
|
||||
def RC_tx_release(self):
|
||||
self._RC.tx_release()
|
||||
@m.output()
|
||||
def RC_tx_release_and_accept(self, phase, body):
|
||||
self._RC.tx_release()
|
||||
def N_release_and_accept(self, phase, body):
|
||||
self._N.release()
|
||||
self._accept(phase, body)
|
||||
@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):
|
||||
assert self._mood
|
||||
self._RC.tx_close(self._mood)
|
||||
@m.output()
|
||||
def record_mood_and_RC_tx_close(self, mood):
|
||||
self._mood = mood
|
||||
self._RC.tx_close(self._mood)
|
||||
self._RC_tx_close()
|
||||
def _RC_tx_close(self):
|
||||
self._RC.tx_close(self._mailbox, self._mood)
|
||||
@m.output()
|
||||
def accept(self, phase, body):
|
||||
self._accept(phase, body)
|
||||
|
@ -203,98 +152,49 @@ class Mailbox(object):
|
|||
def record_mood(self, mood):
|
||||
self._mood = mood
|
||||
@m.output()
|
||||
def record_mood_and_RC_stop(self, mood):
|
||||
def record_mood_and_RC_tx_close(self, mood):
|
||||
self._mood = mood
|
||||
self._RC_stop()
|
||||
self._RC_rx_close()
|
||||
@m.output()
|
||||
def RC_stop(self):
|
||||
self._RC_stop()
|
||||
def _RC_stop(self):
|
||||
self._RC.stop()
|
||||
def ignore_mood_and_T_mailbox_done(self, mood):
|
||||
self._T.mailbox_done()
|
||||
@m.output()
|
||||
def W_closed(self):
|
||||
self._B.closed()
|
||||
def T_mailbox_done(self):
|
||||
self._T.mailbox_done()
|
||||
|
||||
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(close, enter=S4A, outputs=[ignore_mood_and_T_mailbox_done])
|
||||
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(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(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(close, enter=S3A, outputs=[record_mood])
|
||||
S2B.upon(lost, enter=S2A, outputs=[])
|
||||
S2B.upon(add_message, enter=S2B, outputs=[queue])
|
||||
S2B.upon(rx_claimed, enter=S3B,
|
||||
outputs=[store_mailbox_and_RC_tx_open_and_drain])
|
||||
S2B.upon(add_message, enter=S2B, outputs=[queue, RC_tx_add])
|
||||
S2B.upon(rx_message_theirs, enter=S2B, outputs=[N_release_and_accept])
|
||||
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(add_message, enter=S3A, outputs=[queue])
|
||||
S3A.upon(connected, enter=S3B, outputs=[RC_tx_close])
|
||||
S3B.upon(lost, enter=S3A, outputs=[])
|
||||
S3B.upon(rx_message_theirs, enter=S4B, outputs=[RC_tx_release_and_accept])
|
||||
S3B.upon(rx_message_ours, enter=S3B, outputs=[dequeue])
|
||||
S3B.upon(rx_claimed, enter=S3B, outputs=[])
|
||||
S3B.upon(add_message, enter=S3B, outputs=[queue, RC_tx_add])
|
||||
S3B.upon(rx_closed, enter=S4B, outputs=[T_mailbox_done])
|
||||
S3B.upon(add_message, enter=S3B, outputs=[])
|
||||
S3B.upon(rx_message_theirs, enter=S3B, outputs=[])
|
||||
S3B.upon(rx_message_ours, enter=S3B, outputs=[])
|
||||
|
||||
S4A.upon(connected, enter=S4B, outputs=[RC_tx_open, drain, RC_tx_release])
|
||||
S4A.upon(add_message, enter=S4A, outputs=[queue])
|
||||
S4A.upon(connected, enter=S4B, outputs=[])
|
||||
S4B.upon(lost, enter=S4A, outputs=[])
|
||||
S4B.upon(add_message, enter=S4B, outputs=[queue, RC_tx_add])
|
||||
S4B.upon(rx_message_theirs, enter=S4B, outputs=[accept])
|
||||
S4B.upon(rx_message_ours, enter=S4B, outputs=[dequeue])
|
||||
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=[])
|
||||
S4.upon(add_message, enter=S4, outputs=[])
|
||||
S4.upon(rx_message_theirs, enter=S4, outputs=[])
|
||||
S4.upon(rx_message_ours, enter=S4, outputs=[])
|
||||
|
||||
|
|
|
@ -3,63 +3,142 @@ from zope.interface import implementer
|
|||
from automat import MethodicalMachine
|
||||
from . import _interfaces
|
||||
|
||||
@implementer(_interfaces.INameplateLister)
|
||||
class NameplateListing(object):
|
||||
@implementer(_interfaces.INameplate)
|
||||
class Nameplate(object):
|
||||
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._C = _interfaces.ICode(code)
|
||||
self._T = _interfaces.ITerminator(terminator)
|
||||
|
||||
# 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.
|
||||
# all -A states: not connected
|
||||
# all -B states: yes connected
|
||||
# B states serialize as A, so they deserialize as unconnected
|
||||
|
||||
# S0: know nothing
|
||||
@m.state(initial=True)
|
||||
def S0A_idle_disconnected(self): pass
|
||||
def S0A(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
|
||||
def S0B(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()
|
||||
def connected(self): pass
|
||||
@m.input()
|
||||
def lost(self): pass
|
||||
|
||||
@m.input()
|
||||
def refresh_nameplates(self): pass
|
||||
def rx_claimed(self, mailbox): pass
|
||||
@m.input()
|
||||
def rx_nameplates(self, message): pass
|
||||
def rx_released(self): pass
|
||||
|
||||
|
||||
@m.output()
|
||||
def RC_tx_list(self):
|
||||
self._RC.tx_list()
|
||||
def record_nameplate(self, nameplate):
|
||||
self._nameplate = nameplate
|
||||
@m.output()
|
||||
def C_got_nameplates(self, message):
|
||||
self._C.got_nameplates(message["nameplates"])
|
||||
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()
|
||||
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=[])
|
||||
S0B_idle_connected.upon(lost, enter=S0A_idle_disconnected, outputs=[])
|
||||
S0A.upon(set_nameplate, enter=S1A, outputs=[record_nameplate])
|
||||
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,
|
||||
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])
|
||||
S1A.upon(connected, enter=S2B, outputs=[RC_tx_claim])
|
||||
S1A.upon(close, enter=S5A, outputs=[T_nameplate_done])
|
||||
|
||||
S2A.upon(connected, enter=S2B, outputs=[RC_tx_claim])
|
||||
S2A.upon(close, enter=S4A, outputs=[])
|
||||
S2B.upon(lost, enter=S2A, outputs=[])
|
||||
S2B.upon(rx_claimed, enter=S3B, outputs=[M_got_mailbox])
|
||||
S2B.upon(close, enter=S4B, outputs=[RC_tx_release])
|
||||
|
||||
S3A.upon(connected, enter=S3B, outputs=[])
|
||||
S3A.upon(close, enter=S4A, outputs=[])
|
||||
S3B.upon(lost, enter=S3A, outputs=[])
|
||||
#S3B.upon(rx_claimed, enter=S3B, outputs=[]) # shouldn't happen
|
||||
S3B.upon(release, enter=S4B, outputs=[RC_tx_release])
|
||||
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)
|
||||
self._tx("add", phase=phase, body=bytes_to_hexstr(body))
|
||||
|
||||
def tx_release(self):
|
||||
self._tx("release")
|
||||
def tx_release(self, nameplate):
|
||||
self._tx("release", nameplate=nameplate)
|
||||
|
||||
def tx_close(self, mood):
|
||||
self._tx("close", mood=mood)
|
||||
def tx_close(self, mailbox, mood):
|
||||
self._tx("close", mailbox=mailbox, mood=mood)
|
||||
|
||||
def stop(self):
|
||||
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