-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpeer.dart
208 lines (164 loc) · 5.58 KB
/
peer.dart
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
part of messenger;
/**
* @todo:
* * ready Status enum instead of string
*/
abstract class Peer{
///root logging object
static final Logger parent_log = new Logger("Peer");
Logger log;
StreamController<NewConnectionEvent> newConnectionController;
///number of all local peer instances
static int num = 0;
///name of this peer instance
String name;
///new message event stream
StreamController<NewMessageEvent> newMessageController;
Map<int, Connection> _connections;
static List<Peer> peers = new List<Peer>();
//object is identified by hash of name. name has to be unique
int get hashCode => this.name.hashCode;
Completer<String> connection_completer;
Completer<String> listen_completer;
/**
* constuctor
*
*/
Peer([String name="", Level logLevel=Level.FINE]){
//set name of this peer instance
this.name = (name.length < 1)?"peer" + (++num).toString():name;
//is name is unique?
if(peers.contains(this))
throw new StateError("peer with name ${this.name} already exists!");
//setup logger
hierarchicalLoggingEnabled = true;
log = new Logger("Peer.${this.runtimeType}.${this.name}");
log.level = logLevel;
log.onRecord.listen((LogRecord rec) {
print('${rec.loggerName} (${rec.level.name}): ${rec.message}');
});
//init
newMessageController = new StreamController<NewMessageEvent>.broadcast();
newConnectionController = new StreamController<NewConnectionEvent>.broadcast();
_connections = new Map<int, Connection>();
listen_completer = new Completer<String>();
connection_completer = new Completer<String>();
log.info("new peer: #${num.toString()} ${this.name} ");
peers.add(this);
}
/**
* connections getter
*/
Map<int, Connection> get connections => _connections;
/**
* get identifer of this object
*/
String get id => this.hashCode.toString();
/**
* number of connections
*
* @param ReadyState filter. count only connections with this readyState
* @returns number of connections
*/
int countConnections([ReadyState filter=null]){
int i=0;
_connections.forEach((k,v){
if(filter==null) return i++;
else if(v.readyState == filter) i++;
});
return i;
}
/**
* listen for incoming connections
*
* @param Peer other
*/
Stream<NewConnectionEvent> listen(SignalingChannel other);
/**
* connect to another peer
*
* @param Peer other
*/
Stream<NewConnectionEvent> connect(SignalingChannel other);
/**
* send Message to other peer
*
* @param String receiverId receiver of message
* @param Message msg is content of message
*/
send(int receiverId, Message msg);
/**
* send string to other peer
*/
sendString(int receiverId, String msg) => send(receiverId, new Message(msg));
/**
* send message to multiple peers
*/
broadcast(Iterable<int> receiverIds, Message msg){
receiverIds.forEach((int id){
this.send(id, msg);
});
}
/**
* send message to all known peers
*/
multicast(Message msg) => broadcast(_connections.keys, msg);
/**
* getter: onstream event channel (stream)
*/
Stream get onReceive => newMessageController.stream;
/**
* getter: name
*/
String get getName => this.name;
/**
* close connection
*/
close();
}
class ReadyState{
final String name;
final int value;
//init value
static const ReadyState NEW = const ReadyState._create('NEW', 0);
//RTC
static const ReadyState RTC_NEW = const ReadyState._create('RTC_NEW', 1);
static const ReadyState RTC_CONNECTING = const ReadyState._create('RTC_CONNECTING', 2);
static const ReadyState RTC_CONNECTED = const ReadyState._create('RTC_CONNECTED', 3);
static const ReadyState RTC_COMPLETED = const ReadyState._create('RTC_COMPLETED', 4);
static const ReadyState RTC_FAILED = const ReadyState._create('RTC_FAILED', 5);
static const ReadyState RTC_DISCONNECTED = const ReadyState._create('RTC_DISCONNECTED', 6);
static const ReadyState RTC_CLOSED = const ReadyState._create('RTC_CLOSED', 7);
//DC
static const ReadyState DC_CONNECTING = const ReadyState._create('DC_CONNECTING', 8);
static const ReadyState DC_OPEN = const ReadyState._create('DC_OPEN', 9);
static const ReadyState DC_CLOSING = const ReadyState._create('DC_CLOSING', 10);
static const ReadyState DC_CLOSED = const ReadyState._create('DC_CLOSED', 11);
static const ReadyState CONNECTED = const ReadyState._create('CONNECTED', 50);
//Undefined status
static const ReadyState UNDEFINED = const ReadyState._create('UNDEFINED', 100);
const ReadyState._create(this.name, this.value);
factory ReadyState.fromDataChannel(String name){
switch(name){
case "connecting":
return const ReadyState._create('DC_CONNECTING', 11);
case "open":
return const ReadyState._create('DC_OPEN', 9);
case "closing":
return const ReadyState._create('DC_CLOSING', 10);
case "closed":
return const ReadyState._create('DC_CLOSED', 11);
default:
return const ReadyState._create('UNDEFINED', 100);
}
}
}
/*
//Signaling
*
static const ReadyState STABLE = const ReadyState('STABLE', 1);
static const ReadyState HAVE_LOCAL_OFFER = const ReadyState('HAVE_LOCAL_OFFER', 2);
static const ReadyState HAVE_REMOTE_OFFER = const ReadyState('HAVE_REMOTE_OFFER', 3);
static const ReadyState HAVE_LOCAL_PRANSWER = const ReadyState('HAVE_LOCAL_PRANSWER', 4);
static const ReadyState HAVE_REMOTE_PRANSWER = const ReadyState('HAVE_REMOTE_PRANSWER', 5);
*/