-
Notifications
You must be signed in to change notification settings - Fork 0
/
channel.py
117 lines (97 loc) · 2.83 KB
/
channel.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def ignore():
"""Useful placeholder for e.g. close_receiver"""
pass
def fail():
"""Useful token for e.g. close_receiver (if that's unexpected)"""
pass
class Channel(object):
"""
>>> from channel import Channel
>>> c = Channel()
>>> def r0(data):
... print("R0 RECEIVED", data)
...
>>> def r1(data):
... print("R1 RECEIVED", data)
...
>>> s0 = c.connect(r0)
>>> s1 = c.connect(r1)
>>> s0("hallo")
R1 RECEIVED hallo
>>> s1("hallo")
R0 RECEIVED hallo
>>> def r2(data):
... print("R2 RECEIVED", data)
...
>>> s2 = c.connect(r2)
>>> s2("hallo")
R0 RECEIVED hallo
R1 RECEIVED hallo
>>> s0("hallo")
R1 RECEIVED hallo
R2 RECEIVED hallo
"""
def __init__(self):
self.receivers = []
def connect(self, receiver):
# receiver :: function that takes data
sender_index = len(self.receivers)
self.receivers.append(receiver)
def send(data):
for index, r in enumerate(self.receivers):
if index != sender_index:
r(data)
return send
def broadcast(self, data):
for r in self.receivers:
r(data)
class ClosableChannel(object):
"""
Channel w/ an explicit close() call; alternatively this could be modelled by sending either Open(data) or Close()
over a regular Channel, or by opening a second channel that will be used for communicating open/closed info.
>>> from channel import ClosableChannel
>>> c = ClosableChannel()
>>>
>>> def r0(data):
... print("R0 RECEIVED", data)
...
>>> def c0():
... print("C0 RECEIVED")
...
>>> def r1(data):
... print("R1 RECEIVED", data)
...
>>> def c1():
... print("C1 RECEIVED")
...
>>> s0, close0 = c.connect(r0, c0)
>>> s1, close1 = c.connect(r1, c1)
>>>
>>> close0()
C1 RECEIVED
"""
def __init__(self):
self.receivers = []
self.close_receivers = []
self.closed = False
def connect(self, receiver, close_receiver=fail):
# receiver :: function that takes data;
# close_receiver :: argless function
sender_index = len(self.receivers)
self.receivers.append(receiver)
self.close_receivers.append(close_receiver)
def send(data):
if self.closed:
raise Exception("Channel closed")
for index, r in enumerate(self.receivers):
if index != sender_index:
r(data)
def close():
self.closed = True
for index, c in enumerate(self.close_receivers):
if index != sender_index:
c()
return send, close
def broadcast(self, data):
for r in self.receivers:
r(data)