Fixed accidental submodule
This commit is contained in:
Родитель
7e22558b8a
Коммит
c3a8ac0a5f
|
@ -1 +0,0 @@
|
|||
Subproject commit f750484c56c49fb0383d488a9751c466590004b3
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
ssl
|
|
@ -0,0 +1,98 @@
|
|||
# WebRTC peer-to-peer
|
||||
|
||||
This is a browser JS library that makes it easy to manage RTC peer connections, streams and data channels.
|
||||
It's currently used in [emscripten](http://github.com/kripken/emscripten) to provide data transport for the posix sockets implementation.
|
||||
|
||||
## Requirements
|
||||
|
||||
You will need either Firefox [Nightly](http://nightly.mozilla.org/), or Chrome [Canary](https://www.google.com/intl/en/chrome/browser/canary.html).
|
||||
You can also use Chrome [Dev Channel](http://www.chromium.org/getting-involved/dev-channel).
|
||||
|
||||
## What it does
|
||||
|
||||
* Firefox (nightly) and Chrome (dev/canary) supported
|
||||
* Binary transport using arraybuffers (Firefox only!)
|
||||
* Multiple connections
|
||||
* Broker service (on nodejitsu), or run your own
|
||||
* Connection timeouts
|
||||
|
||||
## What it doesn't do (yet!)
|
||||
|
||||
* Interoperability between Firefox and Chrome
|
||||
* Peer brokering for establishing new connections through existing peer-to-peer
|
||||
|
||||
## Quick start
|
||||
|
||||
Setting up a peer is easy. The code below will create a new peer and listen for incoming connections.
|
||||
The `onconnection` handler is called each time a new connection is ready.
|
||||
|
||||
````javascript
|
||||
// Create a new Peer
|
||||
var peer = new Peer(
|
||||
'http://webrtcb.jit.su:80', // You can use this broker if you don't want to set one up
|
||||
{
|
||||
binaryType: 'arraybuffer',
|
||||
video: false,
|
||||
audio: false
|
||||
}
|
||||
);
|
||||
|
||||
// Listen for incoming connections
|
||||
peer.listen();
|
||||
|
||||
var connections = {};
|
||||
|
||||
// Handle new connections
|
||||
peer.onconnection = function(connection) {
|
||||
// Store connections here so we can use them later
|
||||
connections[connection.id] = connection; // Each connection has a unique ID
|
||||
|
||||
connection.ondisconnect = function(reason) {
|
||||
delete connections[connection.id];
|
||||
};
|
||||
|
||||
connection.onerror = function(error) {
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
// Handle messages from this channel
|
||||
// The label will be 'reliable' or 'unreliable', depending on how it was received
|
||||
connection.onmessage = function(label, message) {
|
||||
console.log(label, message);
|
||||
};
|
||||
|
||||
// Sends a message to the other peer using the reliable data channel
|
||||
connection.send('reliable', 'hi!');
|
||||
|
||||
// The connection exposes the underlying media streams
|
||||
// You can attach them to DOM elements to get video/audio, if available
|
||||
console.log(connection.streams.local, connection.streams.remote);
|
||||
|
||||
// Closes the connection
|
||||
// This will cause `ondisconnect` to fire
|
||||
connection.close();
|
||||
};
|
||||
|
||||
// Print our route when it's available
|
||||
peer.onroute = function(route) {
|
||||
// This is our routing address from the broker
|
||||
// It's used by peers who wish to connect with us
|
||||
console.log('route:', route);
|
||||
};
|
||||
|
||||
peer.onerror = function(error) {
|
||||
console.log(error);
|
||||
};
|
||||
````
|
||||
|
||||
Another peer can connect easily to the one we made above by calling `connect()` on its routing address.
|
||||
|
||||
````javascript
|
||||
peer.connect(route);
|
||||
````
|
||||
|
||||
## Demo
|
||||
|
||||
There are some files in the `demo` directory that offer an example.
|
||||
You can load it [here](http://js-platform.github.com/p2p/examples/data-demo.html) and open the `connect` URL in another window.
|
||||
For this example, the `route` is added to the URL query string so that the other peer can parse it and connect when the page loads, so all you need to share is the URL.
|
|
@ -0,0 +1 @@
|
|||
../node_modules/.bin/uglifyjs
|
|
@ -0,0 +1,231 @@
|
|||
var crypto = require('crypto');
|
||||
var fs = require('fs');
|
||||
var https = require('https');
|
||||
|
||||
var SSL_KEY = 'ssl/ssl.key';
|
||||
var SSL_CERT = 'ssl/ssl-unified.crt';
|
||||
var PORT = 8080;
|
||||
|
||||
var sslSupported = false;
|
||||
if(fs.existsSync(SSL_KEY) && fs.existsSync(SSL_CERT) && fs.statSync(SSL_KEY).isFile() && fs.statSync(SSL_CERT).isFile()) {
|
||||
sslSupported = true;
|
||||
}
|
||||
|
||||
function handler(req, res) {
|
||||
res.writeHead(200);
|
||||
res.end("p2p");
|
||||
};
|
||||
|
||||
var app, port;
|
||||
if(sslSupported) {
|
||||
var sslopts = {
|
||||
key: fs.readFileSync(SSL_KEY),
|
||||
cert: fs.readFileSync(SSL_CERT)
|
||||
};
|
||||
sslopts.agent = new https.Agent(sslopts);
|
||||
app = require('https').createServer(sslopts, handler);
|
||||
port = 8081;
|
||||
console.info('ssl mode enabled');
|
||||
} else {
|
||||
app = require('http').createServer(handler);
|
||||
port = 8080;
|
||||
console.info('ssl mode disabled');
|
||||
}
|
||||
console.info('listening on port', port);
|
||||
|
||||
var io = require('socket.io').listen(app, {
|
||||
'log level': 2
|
||||
});
|
||||
|
||||
app.listen(port);
|
||||
|
||||
var jsMime = {
|
||||
type: 'application/javascript',
|
||||
encoding: 'utf8',
|
||||
gzip: true
|
||||
};
|
||||
|
||||
io.static.add('/p2p-client.js', {
|
||||
mime: jsMime,
|
||||
file: 'client/p2p-client.js'
|
||||
});
|
||||
|
||||
/*
|
||||
io.static.add('/p2p-client.min.js', {
|
||||
mime: jsMime,
|
||||
file: 'client/p2p-client.min.js'
|
||||
});
|
||||
*/
|
||||
|
||||
function mkguid() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
|
||||
return v.toString(16);
|
||||
}).toUpperCase();
|
||||
};
|
||||
|
||||
var peers = {};
|
||||
var hosts = {};
|
||||
|
||||
var E = {
|
||||
OK: 'ok'
|
||||
, NOROUTE: 'no such route'
|
||||
, ISNOTHOST: 'peer is not a host'
|
||||
};
|
||||
|
||||
function Peer(socket) {
|
||||
this.socket = socket;
|
||||
this.host = null;
|
||||
};
|
||||
|
||||
function Host(options) {
|
||||
this.route = options['route'];
|
||||
this.url = options['url'];
|
||||
this.listed = (undefined !== options['listed']) ? options['listed'] : false;
|
||||
this.metadata = options['metadata'] || {};
|
||||
this.ctime = Date.now();
|
||||
this.mtime = Date.now();
|
||||
};
|
||||
Host.prototype.update = function update(options) {
|
||||
this.url = options['url'];
|
||||
this.listed = (undefined !== options['listed']) ? options['listed'] : false;
|
||||
this.metadata = options['metadata'] || {};
|
||||
this.mtime = Date.now();
|
||||
};
|
||||
|
||||
io.of('/peer').on('connection', function(socket) {
|
||||
var route = crypto.createHash('md5').update(socket['id']).digest('hex');
|
||||
socket.emit('route', route);
|
||||
|
||||
socket.on('disconnect', function() {
|
||||
if(hosts[route]) {
|
||||
var host = hosts[route];
|
||||
changeList('remove', host);
|
||||
}
|
||||
delete hosts[route];
|
||||
delete peers[route];
|
||||
});
|
||||
|
||||
socket.on('send', function(message, callback) {
|
||||
var to = message['to'];
|
||||
|
||||
if(!peers.hasOwnProperty(to)) {
|
||||
callback({'error': E.NOROUTE});
|
||||
return;
|
||||
}
|
||||
|
||||
var from = route;
|
||||
var data = message['data'];
|
||||
peers[to].emit('receive', {
|
||||
'from': from,
|
||||
'data': data
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('listen', function(options, callback) {
|
||||
options['route'] = route;
|
||||
if(hosts.hasOwnProperty(route)) {
|
||||
hosts[route].update(options);
|
||||
changeList('update', hosts[route]);
|
||||
} else {
|
||||
hosts[route] = new Host(options);
|
||||
changeList('append', hosts[route]);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
|
||||
socket.on('ignore', function(message, callback) {
|
||||
if(!hosts.hasOwnProperty(route)) {
|
||||
callback({'error': E.ISNOTHOST});
|
||||
return;
|
||||
}
|
||||
|
||||
var host = hosts[route];
|
||||
delete hosts[route];
|
||||
|
||||
changeList('remove', host);
|
||||
|
||||
callback();
|
||||
});
|
||||
|
||||
peers[route] = socket;
|
||||
});
|
||||
|
||||
function Filter(socket, options) {
|
||||
this.options = options || {};
|
||||
this.socket = socket;
|
||||
};
|
||||
Filter.prototype.test = function test(host) {
|
||||
var filter = this.options;
|
||||
var result;
|
||||
|
||||
if(filter['url'] && typeof host['url'] === 'string') {
|
||||
try {
|
||||
result = host['url'].match(filter['url']);
|
||||
if(!result)
|
||||
return true;
|
||||
} catch(e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(filter['metadata'] && host['metadata']) {
|
||||
var metadataFilter = filter['metadata'];
|
||||
var metadataHost = host['metadata'];
|
||||
|
||||
if(metadataFilter['name'] && typeof metadataHost['name'] === 'string') {
|
||||
try {
|
||||
result = metadataHost['name'].match(metadataFilter['name']);
|
||||
if(!result)
|
||||
return true;
|
||||
} catch(e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
var lists = {};
|
||||
|
||||
function changeList(operation, host) {
|
||||
var clients = Object.keys(lists);
|
||||
clients.forEach(function(client) {
|
||||
var filter = lists[client];
|
||||
if(!host['listed'])
|
||||
return;
|
||||
if(!filter.test(host)) {
|
||||
var data = operation === 'remove' ? host['route'] : host;
|
||||
filter.socket.emit(operation, data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
io.of('/list').on('connection', function(socket) {
|
||||
var id = socket['id'];
|
||||
|
||||
socket.on('disconnect', function() {
|
||||
delete lists[id];
|
||||
});
|
||||
|
||||
socket.on('list', function(options) {
|
||||
var filter = new Filter(socket, options);
|
||||
|
||||
var result = [];
|
||||
|
||||
var hostIds = Object.keys(hosts);
|
||||
hostIds.forEach(function(hostId) {
|
||||
var host = hosts[hostId];
|
||||
if(!host['listed'])
|
||||
return;
|
||||
if(!filter.test(host))
|
||||
result.push(host);
|
||||
});
|
||||
|
||||
lists[id] = filter;
|
||||
|
||||
socket.emit('truncate', result);
|
||||
});
|
||||
});
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div>instructions: open the connect link in a new window or tab; after a few seconds you should see a message in both instances indicating that they are connected</div>
|
||||
<video id="local" autoplay></video>
|
||||
<video id="remote" autoplay></video>
|
||||
<div id="host"></div>
|
||||
<pre id="chat"></pre>
|
||||
<input type="text" id="chatinput">
|
||||
</body>
|
||||
<script src="../client/p2p-client.js"></script>
|
||||
<script src="data-demo.js"></script>
|
||||
</html>
|
|
@ -0,0 +1,103 @@
|
|||
function log(msg) {
|
||||
console.log(msg);
|
||||
document.getElementById("chat").appendChild(document.createTextNode(msg + "\n"));
|
||||
}
|
||||
|
||||
/*
|
||||
var localvideo = document.getElementById("local");
|
||||
var remotevideo = document.getElementById("remote");
|
||||
*/
|
||||
|
||||
function bindStream(stream, element) {
|
||||
if ("mozSrcObject" in element) {
|
||||
element.mozSrcObject = stream;
|
||||
} else {
|
||||
element.src = webkitURL.createObjectURL(stream);
|
||||
}
|
||||
element.play();
|
||||
};
|
||||
|
||||
var brokerSession = null;
|
||||
var brokerUrl = 'https://mdsw.ch:8080';
|
||||
var hosting = true;
|
||||
var options;
|
||||
|
||||
if(window.location.search) {
|
||||
var params = window.location.search.substring(1).split('&');
|
||||
for(var i = 0; i < params.length; ++ i) {
|
||||
if(params[i].match('^webrtc-session')) {
|
||||
brokerSession = params[i].split('=')[1];
|
||||
hosting = false;
|
||||
} else if(params[i].match('^webrtc-broker')) {
|
||||
brokerUrl = params[i].split('=')[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('broker', brokerUrl);
|
||||
var peer = new Peer(brokerUrl, {video: false, audio: false});
|
||||
window.connections = {};
|
||||
peer.onconnection = function(connection) {
|
||||
log('connected: ' + connection.id);
|
||||
connections[connection.id] = connection;
|
||||
connection.ondisconnect = function() {
|
||||
log('disconnected: ' + connection.id);
|
||||
delete connections[connection.id];
|
||||
};
|
||||
connection.onerror = function(error) {
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
//bindStream(connection.streams['local'], localvideo);
|
||||
//bindStream(connection.streams['remote'], remotevideo);
|
||||
|
||||
connection.onmessage = function(label, msg) {
|
||||
log('<other:' + connection.id + '> ' + msg.data);
|
||||
};
|
||||
/*
|
||||
var buff = new Uint8Array([1, 2, 3, 4]);
|
||||
connection.send('reliable', buff.buffer);
|
||||
*/
|
||||
};
|
||||
peer.onerror = function(error) {
|
||||
console.error(error);
|
||||
};
|
||||
|
||||
if(hosting) {
|
||||
console.log('hosting');
|
||||
peer.listen({metadata:{name:'data-demo'}});
|
||||
peer.onroute = function(route) {
|
||||
var url = window.location.toString().split('?');
|
||||
url[1] = url[1] || '';
|
||||
var params = url[1].split('&');
|
||||
params.push('webrtc-session=' + route);
|
||||
url[1] = params.join('&');
|
||||
|
||||
var div = document.getElementById('host');
|
||||
div.innerHTML = '<a href="' + url.join('?') + '">connect</a>';
|
||||
}
|
||||
} else {
|
||||
peer.connect(brokerSession);
|
||||
}
|
||||
|
||||
window.onbeforeunload = function() {
|
||||
var ids = Object.keys(connections);
|
||||
ids.forEach(function(id) {
|
||||
connections[id].close();
|
||||
});
|
||||
peer.close();
|
||||
};
|
||||
|
||||
document.getElementById("chatinput").addEventListener("keyup", function(e) {
|
||||
if (e.keyCode == 13) {
|
||||
var ci = document.getElementById("chatinput");
|
||||
log("<self> " + ci.value);
|
||||
|
||||
var ids = Object.keys(connections);
|
||||
ids.forEach(function(id) {
|
||||
connections[id].send('reliable', ci.value);
|
||||
});
|
||||
|
||||
ci.value = "";
|
||||
}
|
||||
});
|
|
@ -0,0 +1,112 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="list">
|
||||
</div>
|
||||
</body>
|
||||
<script src="http://wrtcb.jit.su/socket.io/socket.io.js"></script>
|
||||
<script>
|
||||
var brokerUrl = 'https://mdsw.ch:8080';
|
||||
if(window.location.search) {
|
||||
var params = window.location.search.substring(1).split('&');
|
||||
for(var i = 0; i < params.length; ++ i) {
|
||||
if(params[i].match('^webrtc-broker')) {
|
||||
brokerUrl = params[i].split('=')[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(brokerUrl);
|
||||
|
||||
var hosts = {};
|
||||
var filter = {
|
||||
'metadata': {
|
||||
'name': '.*'
|
||||
}
|
||||
};
|
||||
|
||||
var socket = io.connect(brokerUrl + '/list');
|
||||
socket.on('connect', function() {
|
||||
socket.emit('list', filter);
|
||||
});
|
||||
socket.on('error', function(error) {
|
||||
console.error(error);
|
||||
});
|
||||
socket.on('truncate', function(list) {
|
||||
clear();
|
||||
append(list);
|
||||
});
|
||||
socket.on('append', function(host) {
|
||||
append([host]);
|
||||
});
|
||||
socket.on('update', function(host) {
|
||||
update([host]);
|
||||
});
|
||||
socket.on('remove', function(route) {
|
||||
remove([route]);
|
||||
});
|
||||
|
||||
function setQuery(url, item) {
|
||||
var urlParts = url.split('?');
|
||||
if(urlParts.length < 2) {
|
||||
urlParts[1] = item;
|
||||
} else {
|
||||
var query = urlParts[1].split('&');
|
||||
query.push(item);
|
||||
urlParts[1] = query.join('&');
|
||||
}
|
||||
return urlParts.join('?');
|
||||
};
|
||||
|
||||
function clear() {
|
||||
hosts = {};
|
||||
var div = document.getElementById('list');
|
||||
var parent = div.parentNode;
|
||||
parent.removeChild(div);
|
||||
div = document.createElement('div');
|
||||
div.id = 'list';
|
||||
parent.appendChild(div);
|
||||
};
|
||||
|
||||
function append(list) {
|
||||
list = list || [];
|
||||
list.forEach(function(host) {
|
||||
hosts[host['route']] = host;
|
||||
var div = document.getElementById('list');
|
||||
var element = document.createElement('div');
|
||||
host.element = element;
|
||||
var name = host['metadata']['name'] || '';
|
||||
var url = setQuery(host['url'], 'webrtc-session=' + host['route']);
|
||||
element.innerHTML = new Date(host['ctime']).toString() + ' | ' + name + ' | ' + '<a href="' + url + '">join</a>';
|
||||
div.appendChild(element);
|
||||
});
|
||||
};
|
||||
|
||||
function update(list) {
|
||||
list = list || [];
|
||||
list.forEach(function(host) {
|
||||
if(hosts[host['route']]) {
|
||||
var element = hosts[host['route']].element;
|
||||
var name = host['metadata']['name'] || '';
|
||||
var url = setQuery(host['url'], 'webrtc-session=' + host['route']);
|
||||
element.innerHTML = new Date(host['ctime']).toString() + ' | ' + name + ' | ' + '<a href="' + url + '">join</a>';
|
||||
host.element = element;
|
||||
hosts[host['route']] = host;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function remove(list) {
|
||||
list = list || [];
|
||||
list.forEach(function(route) {
|
||||
var host = hosts[route];
|
||||
var element = host.element;
|
||||
element.parentNode.removeChild(element);
|
||||
delete hosts[route];
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
node_modules/.bin/forever
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "p2p",
|
||||
"version": "0.0.1-21",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "node broker/p2p-broker.js",
|
||||
"install-windows-service": "winser -i",
|
||||
"uninstall-windows-service": "winser -r"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "~1.0.1",
|
||||
"forever": "~0.10.0",
|
||||
"socket.io": "~0.9.13",
|
||||
"uglify-js": "~2.2.5",
|
||||
"winser": "~0.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "0.8.x",
|
||||
"npm": "1.1.x"
|
||||
},
|
||||
"subdomain": "wrtcb"
|
||||
}
|
Загрузка…
Ссылка в новой задаче