mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
Merge branch 'amark:master' into azure-blob-adapter
This commit is contained in:
commit
d3a8f0147e
38
examples/basic/meet.html
Normal file
38
examples/basic/meet.html
Normal file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<center>must press play or unmute on new videos to accept meeting</center>
|
||||
<center id="videos">
|
||||
<video id="me" width="100%" controls autoplay playsinline muted></video>
|
||||
</center>
|
||||
<center>Stream <select id="select"><option id="from">from</option></select></center>
|
||||
|
||||
<script src="../jquery.js"></script>
|
||||
<script src="../../../gun/gun.js"></script>
|
||||
<script src="../../../gun/sea.js"></script>
|
||||
<script src="../../../gun/lib/webrtc.js"></script>
|
||||
|
||||
<script>;(async function(){
|
||||
streams = {}, gun = Gun(location.origin + '/gun'); //gun = GUN();
|
||||
mesh = gun.back('opt.mesh');
|
||||
|
||||
(await (me.stream = navigator.mediaDevices).enumerateDevices()).forEach((device,i) => {
|
||||
if('videoinput' !== device.kind){ return }
|
||||
var opt = $(from).clone().prependTo('select').get(0);
|
||||
$(opt).text(opt.id = device.label || 'Camera '+i);
|
||||
opt.value = device.deviceId;
|
||||
});
|
||||
|
||||
$('select').on('change', async eve => { $(from).text('Off'); // update label
|
||||
if('Off' == select.value){ return me.srcObject.getTracks()[0].stop() }
|
||||
mesh.hi(me.srcObject = await me.stream.getUserMedia({ audio: true,
|
||||
video: (select.value && {deviceId: {exact: select.value}}) || {facingMode: "environment"}
|
||||
}));
|
||||
});
|
||||
|
||||
gun.on('rtc', async function(eve){ var ui, src;
|
||||
console.log("?RTC?", eve.peer && eve.peer.connectionState, eve);
|
||||
if(!(src = eve.streams)){ return }
|
||||
ui = $('#v'+(src=src[0]).id).get(0) || $(me).clone().attr('id', 'v'+src.id).prependTo('#videos').get(0); // reuse or create video element
|
||||
ui.srcObject = src;
|
||||
});
|
||||
}());</script>
|
12
gun.js
12
gun.js
@ -220,6 +220,7 @@
|
||||
}
|
||||
|
||||
function set(word, is){
|
||||
// TODO: Perf on random write is decent, but short keys or seq seems significantly slower.
|
||||
var b = this, has = b.all[word];
|
||||
if(has){ return b(word, is) } // updates to in-memory items will always match exactly.
|
||||
var page = b.page(word=''+word), tmp; // before we assume this is an insert tho, we need to check
|
||||
@ -240,21 +241,22 @@
|
||||
|
||||
function split(p, b){ // TODO: use closest hash instead of half.
|
||||
//console.time();
|
||||
//var S = performance.now();
|
||||
var L = sort(p), l = L.length, i = l/2 >> 0, j = i, half = L[j], tmp;
|
||||
//console.timeEnd();
|
||||
var next = {first: half.substring(), size: 0, substring: sub, toString: to, book: b, get: b, read: list}, f = next.from = [];
|
||||
//console.time();
|
||||
while(tmp = L[i++]){
|
||||
f.push(tmp);
|
||||
next.size += (tmp.is||'').length||1;
|
||||
tmp.page = next;
|
||||
}
|
||||
//console.timeEnd(); console.time();
|
||||
p.from = p.from.slice(0, j);
|
||||
p.size -= next.size;
|
||||
b.list.splice(spot(next.first, b.list)+1, 0, next); // TODO: BUG! Make sure next.first is decoded text. // TODO: BUG! spot may need parse too?
|
||||
//console.timeEnd();
|
||||
if(b.split){ b.split(next, p) }
|
||||
//console.log(S = (performance.now() - S), 'split');
|
||||
//console.BIG = console.BIG > S? console.BIG : S;
|
||||
}
|
||||
|
||||
function slot(t){ return heal((t=t||'').substring(1, t.length-1).split(t[0]), t[0]) } B.slot = slot; // TODO: check first=last & pass `s`.
|
||||
@ -1684,10 +1686,10 @@
|
||||
if((tmp = msg['><']) && 'string' == typeof tmp){ tmp.slice(0,99).split(',').forEach(function(k){ this[k] = 1 }, (msg._).yo = {}) } // Peers already sent to, do not resend.
|
||||
// DAM ^
|
||||
if(tmp = msg.dam){
|
||||
(dup_track(id)||{}).via = peer;
|
||||
if(tmp = mesh.hear[tmp]){
|
||||
tmp(msg, peer, root);
|
||||
}
|
||||
dup_track(id);
|
||||
return;
|
||||
}
|
||||
if(tmp = msg.ok){ msg._.near = tmp['/'] }
|
||||
@ -1980,10 +1982,10 @@
|
||||
|
||||
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root);
|
||||
|
||||
var wire = mesh.wire || opt.wire;
|
||||
var wired = mesh.wire || opt.wire;
|
||||
mesh.wire = opt.wire = open;
|
||||
function open(peer){ try{
|
||||
if(!peer || !peer.url){ return wire && wire(peer) }
|
||||
if(!peer || !peer.url){ return wired && wired(peer) }
|
||||
var url = peer.url.replace(/^http/, 'ws');
|
||||
var wire = peer.wire = new opt.WebSocket(url);
|
||||
wire.onclose = function(){
|
||||
|
@ -83,7 +83,7 @@ Gun.on('create', function(root){
|
||||
this.to.next(root);
|
||||
var opt = root.opt;
|
||||
if(opt.rfs === false){ return }
|
||||
opt.store = opt.store || (!Gun.window || opt.rfs === true && Store(opt));
|
||||
opt.store = opt.store || ((!Gun.window || opt.rfs === true) && Store(opt));
|
||||
});
|
||||
|
||||
module.exports = Store;
|
@ -66,7 +66,7 @@ Gun.on('create', function(root){
|
||||
if((tmp = (root.next||'')[soul]) && tmp.put){
|
||||
if(o.atom){
|
||||
tmp = (tmp.next||'')[o.atom] ;
|
||||
if(tmp && tmp.rad){ return }
|
||||
if(tmp && tmp.root && tmp.root.graph && tmp.root.graph[soul] && tmp.root.graph[soul][o.atom]){ return }
|
||||
} else
|
||||
if(tmp && tmp.rad){ return }
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
;(function(){
|
||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
Gun.on('opt', function(root){
|
||||
var GUN = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
GUN.on('opt', function(root){
|
||||
this.to.next(root);
|
||||
var opt = root.opt;
|
||||
if(root.once){ return }
|
||||
if(!Gun.Mesh){ return }
|
||||
if(!GUN.Mesh){ return }
|
||||
if(false === opt.RTCPeerConnection){ return }
|
||||
|
||||
var env;
|
||||
@ -33,44 +33,69 @@
|
||||
opt.rtc.dataChannel = opt.rtc.dataChannel || {ordered: false, maxRetransmits: 2};
|
||||
opt.rtc.sdp = opt.rtc.sdp || {mandatory: {OfferToReceiveAudio: false, OfferToReceiveVideo: false}};
|
||||
opt.rtc.max = opt.rtc.max || 55; // is this a magic number? // For Future WebRTC notes: Chrome 500 max limit, however 256 likely - FF "none", webtorrent does 55 per torrent.
|
||||
opt.rtc.room = opt.rtc.room || Gun.window && (location.hash.slice(1) || location.pathname.slice(1));
|
||||
opt.rtc.room = opt.rtc.room || GUN.window && (location.hash.slice(1) || location.pathname.slice(1));
|
||||
opt.announce = function(to){
|
||||
opt.rtc.start = +new Date; // handle room logic:
|
||||
root.$.get('/RTC/'+opt.rtc.room+'<?99').get('+').put(opt.pid, function(ack){
|
||||
if(!ack.ok || !ack.ok.rtc){ return }
|
||||
open(ack);
|
||||
plan(ack);
|
||||
}, {acks: opt.rtc.max}).on(function(last,key, msg){
|
||||
if(last === opt.pid || opt.rtc.start > msg.put['>']){ return }
|
||||
open({'#': ''+msg['#'], ok: {rtc: {id: last}}});
|
||||
plan({'#': ''+msg['#'], ok: {rtc: {id: last}}});
|
||||
});
|
||||
};
|
||||
|
||||
var mesh = opt.mesh = opt.mesh || Gun.Mesh(root);
|
||||
var mesh = opt.mesh = opt.mesh || GUN.Mesh(root), wired = mesh.wire;
|
||||
mesh.hear['rtc'] = plan;
|
||||
mesh.wire = function(media){ try{ wired && wired(media);
|
||||
if(!(media instanceof MediaStream)){ return }
|
||||
(open.media = open.media||{})[media.id] = media;
|
||||
for(var p in opt.peers){ p = opt.peers[p]||'';
|
||||
p.addTrack && media.getTracks().forEach(track => {
|
||||
p.addTrack(track, media);
|
||||
});
|
||||
p.createOffer && p.createOffer(function(offer){
|
||||
p.setLocalDescription(offer);
|
||||
mesh.say({'#': root.ask(plan), dam: 'rtc', ok: {rtc: {offer: offer, id: opt.pid}}}, p);
|
||||
}, function(){}, opt.rtc.sdp);
|
||||
}
|
||||
} catch(e){console.log(e)} }
|
||||
root.on('create', function(at){
|
||||
this.to.next(at);
|
||||
setTimeout(opt.announce, 1);
|
||||
});
|
||||
|
||||
function open(msg){
|
||||
if(this && this.off){ this.off() } // Ignore this, because of ask / ack.
|
||||
function plan(msg){
|
||||
if(!msg.ok){ return }
|
||||
var rtc = msg.ok.rtc, peer, tmp;
|
||||
if(!rtc || !rtc.id || rtc.id === opt.pid){ return }
|
||||
//console.log("webrtc:", JSON.stringify(msg));
|
||||
peer = open(msg, rtc);
|
||||
if(tmp = rtc.candidate){
|
||||
return peer.addIceCandidate(new opt.RTCIceCandidate(tmp));
|
||||
}
|
||||
if(tmp = rtc.answer){
|
||||
if(!(peer = opt.peers[rtc.id] || open[rtc.id]) || peer.remoteSet){ return }
|
||||
tmp.sdp = tmp.sdp.replace(/\\r\\n/g, '\r\n');
|
||||
return peer.setRemoteDescription(peer.remoteSet = new opt.RTCSessionDescription(tmp));
|
||||
}
|
||||
if(tmp = rtc.candidate){
|
||||
peer = opt.peers[rtc.id] || open[rtc.id] || open({ok: {rtc: {id: rtc.id}}});
|
||||
return peer.addIceCandidate(new opt.RTCIceCandidate(tmp));
|
||||
if(tmp = rtc.offer){
|
||||
rtc.offer.sdp = rtc.offer.sdp.replace(/\\r\\n/g, '\r\n');
|
||||
peer.setRemoteDescription(new opt.RTCSessionDescription(tmp));
|
||||
return peer.createAnswer(function(answer){
|
||||
peer.setLocalDescription(answer);
|
||||
root.on('out', {'@': msg['#'], ok: {rtc: {answer: answer, id: opt.pid}}});
|
||||
}, function(){}, opt.rtc.sdp);
|
||||
}
|
||||
//if(opt.peers[rtc.id]){ return }
|
||||
if(open[rtc.id]){ return }
|
||||
}
|
||||
function open(msg, rtc, peer){
|
||||
if(peer = opt.peers[rtc.id] || open[rtc.id]){ return peer }
|
||||
(peer = new opt.RTCPeerConnection(opt.rtc)).id = rtc.id;
|
||||
var wire = peer.wire = peer.createDataChannel('dc', opt.rtc.dataChannel);
|
||||
function rtceve(eve){ eve.peer = peer; gun.on('rtc', eve) }
|
||||
peer.$ = gun;
|
||||
open[rtc.id] = peer;
|
||||
peer.ontrack = rtceve;
|
||||
peer.onremovetrack = rtceve;
|
||||
peer.onconnectionstatechange = rtceve;
|
||||
wire.to = setTimeout(function(){delete open[rtc.id]},1000*60);
|
||||
wire.onclose = function(){ mesh.bye(peer) };
|
||||
wire.onerror = function(err){ };
|
||||
@ -80,31 +105,27 @@
|
||||
}
|
||||
wire.onmessage = function(msg){
|
||||
if(!msg){ return }
|
||||
//console.log('via rtc');
|
||||
mesh.hear(msg.data || msg, peer);
|
||||
};
|
||||
peer.onicecandidate = function(e){ // source: EasyRTC!
|
||||
peer.onicecandidate = function(e){ rtceve(e);
|
||||
if(!e.candidate){ return }
|
||||
root.on('out', {'@': msg['#'], ok: {rtc: {candidate: e.candidate, id: opt.pid}}});
|
||||
root.on('out', {'@': (msg||'')['#'], '#': root.ask(plan), ok: {rtc: {candidate: e.candidate, id: opt.pid}}});
|
||||
}
|
||||
peer.ondatachannel = function(e){
|
||||
peer.ondatachannel = function(e){ rtceve(e);
|
||||
var rc = e.channel;
|
||||
rc.onmessage = wire.onmessage;
|
||||
rc.onopen = wire.onopen;
|
||||
rc.onclose = wire.onclose;
|
||||
}
|
||||
if(tmp = rtc.offer){
|
||||
rtc.offer.sdp = rtc.offer.sdp.replace(/\\r\\n/g, '\r\n')
|
||||
peer.setRemoteDescription(new opt.RTCSessionDescription(tmp));
|
||||
peer.createAnswer(function(answer){
|
||||
peer.setLocalDescription(answer);
|
||||
root.on('out', {'@': msg['#'], ok: {rtc: {answer: answer, id: opt.pid}}});
|
||||
}, function(){}, opt.rtc.sdp);
|
||||
return;
|
||||
if(rtc.offer){ return peer }
|
||||
for(var m in open.media){ m = open.media[m];
|
||||
m.getTracks().forEach(track => {
|
||||
peer.addTrack(track, m);
|
||||
});
|
||||
}
|
||||
peer.createOffer(function(offer){
|
||||
peer.setLocalDescription(offer);
|
||||
root.on('out', {'@': msg['#'], '#': root.ask(open), ok: {rtc: {offer: offer, id: opt.pid}}});
|
||||
root.on('out', {'@': (msg||'')['#'], '#': root.ask(plan), ok: {rtc: {offer: offer, id: opt.pid}}});
|
||||
}, function(){}, opt.rtc.sdp);
|
||||
return peer;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user