-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
206 lines (167 loc) · 7.91 KB
/
index.html
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>P2P WikiGame | Nicolas Winsten</title>
<meta name="description" content="Race your friends through wikipedia to discover the degrees of separation between wildly disparate topics">
<style>
body {background-color: #ebece5 !important;}
.hoverUnderline:hover {text-decoration: underline !important}
</style>
</head>
<body>
<div id="app"></div>
<div style="text-align: right; font-style: italic; font-size: smaller;"> -- <a href="http://nicolaswinsten.com">Nicolas Winsten</a></div>
<script src="https://unpkg.com/[email protected]/dist/peerjs.min.js"></script>
<script src="racer.js"></script>
<script>
const peer = constructPeer();
let isHost = null;
let hostConnection = null;
let clientConnections = [];
let app = null
function createApp(seed, peerId) {
app = Elm.Main.init({
node : document.getElementById("app"),
flags : {seed : seed, peerId : peerId}
})
setUpPorts()
}
/* code handling the Peer connections */
function constructPeer() {
console.log("creating P2P agent");
const peerOptions = {debug : 2, port : 443, secure : true };
console.log("peer options:", peerOptions);
const peer = new Peer(null, peerOptions);
peer.on('open', function(id) {
console.log("peer ID is " + id)
createApp(Date.now(), id)
});
peer.on('error', function(err) {
console.log("Your peer has error:", err);
if (app == null) {
createApp(Date.now(), null)
}
app.ports.receiveDataPeerJS.send({error : err.type})
});
peer.on('close', () => console.log("peer agent closed"))
peer.on('disconnected', () => console.log("peer agent disconnected from signalling server"))
return peer
}
// close all connected peers
function clearClientConnections() {
clientConnections.forEach(c => c.close())
clientConnections = []
}
window.addEventListener("beforeunload", function(e){
if (peer != null) peer.destroy()
}, false);
// handle data from a peer
function handleIncomingData(data, senderId) {
// if you're the host, either broadcast the message to everyone (including yourself)
// or pass it along to the correct recipient
// TODO maybe an all-to-all design would work better than host-to-clients
console.log("received data from peer:", data)
if (isHost) {
switch (data.type) {
case "broadcast":
clientConnections
.filter(c => c.peer != senderId)
.forEach(c => c.send(data.message))
app.ports.receiveDataPeerJS.send(data.message)
break
case "directed":
clientConnections
.filter(c => c.peer == data.recipient)
.forEach(c => c.send(data.message))
break
default:
console.log("Error: as host, did not know how to handle incoming data:", data)
}
} else {
app.ports.receiveDataPeerJS.send(data)
}
}
// handle data produced from the app, and send it out to peers
function handleOutgoingData(data) {
console.log("sending out data:", data)
if (isHost) {
switch (data.type) {
case "broadcast":
clientConnections.forEach(c => c.send(data.message))
break
case "directed":
clientConnections
.filter(c => c.peer == data.recipient)
.forEach(c => c.send(data.message))
break
default:
console.log("Error: as host, did not know how to handle outgoing data:", data)
}
} else {
hostConnection.send(data)
}
}
function setUpPorts() {
console.log("setting up ports for Elm app...")
app.ports.copyToClipboard.subscribe(text => {
const type = "text/plain";
const blob = new Blob([text], { type });
const data = [new ClipboardItem({ [type]: blob })];
navigator.clipboard.write(data)
})
app.ports.info.subscribe(console.log)
app.ports.error.subscribe(console.error)
app.ports.sendData.subscribe(handleOutgoingData)
app.ports.connectToHostPort.subscribe(({host, name}) => {
console.log("attempting to connect to host at", host)
isHost = false
clearClientConnections()
hostConnection = peer.connect(host, {metadata : {name : name}, serialization : "json"})
hostConnection.on('open', () => {
console.log("host connection opened")
hostConnection.on('data', data => handleIncomingData(data, host));
peer.disconnect();
hostConnection.on('close', function() {
console.log("connection from host lost");
app.ports.receiveDataPeerJS.send("hostlost");
});
hostConnection.on('error', function(err) {
console.log("connection error with host:", err);
app.ports.receiveDataPeerJS.send({error: err});
});
})
})
app.ports.host.subscribe(() => {
// start listening for peer connections
console.log("Attempting to host game...")
isHost = true
clearClientConnections()
peer.on('connection', function(conn) {
console.log("connection received from " + conn.peer + " : " + conn.metadata.name);
clientConnections.push(conn);
// upon a new connection, signal the other peers about the new peer
conn.on('open', function() {
// broadcast the new peer connection to other peers
const joinMessage = {type : "broadcast", message : {playerconnected : {name : conn.metadata.name, uuid : conn.peer}}}
handleIncomingData(joinMessage, conn.peer)
// when this peer sends data to us, send it through to the app and to the other peers
conn.on('data', data => handleIncomingData(data, conn.peer));
// when this peers connection closes, signal the other peers about it
conn.on('close', function() {
console.log("connection to", conn.metadata.name, ":", conn.peer, "was lost");
clientConnections = clientConnections.filter(c => c.peer != conn.peer)
const leaveMessage = {type : "broadcast", message : {playerlost : {uuid : conn.peer}}}
handleIncomingData(leaveMessage, conn.peer)
});
conn.on('error', function(err) {
console.log("connection error with", conn.metadata.name, conn.peer, ":", err);
app.ports.receiveDataPeerJS.send({error: err});
});
});
});
})
}
</script>
</body>
</html>