commit
3e8b1e33b9
8 changed files with 335 additions and 191 deletions
15
css/main.css
15
css/main.css
|
|
@ -277,3 +277,18 @@ button.secondary:hover { background-color: #FFDF00 !important;}
|
||||||
border: 2px red solid;
|
border: 2px red solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-small {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
margin: 20px;
|
||||||
|
display: inline;
|
||||||
|
float:left;
|
||||||
|
}
|
||||||
|
.online {
|
||||||
|
border: 10px solid green;
|
||||||
|
}
|
||||||
|
.offline {
|
||||||
|
border: 10px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
BIN
img/satoshi.gif
Normal file
BIN
img/satoshi.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
35
index.html
35
index.html
|
|
@ -205,21 +205,29 @@
|
||||||
<script type="text/ng-template" id="peer.html">
|
<script type="text/ng-template" id="peer.html">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="large-12 columns p70l">
|
<div class="large-12 columns p70l">
|
||||||
<h3 class="panel-title">Online Copayers: {{$root.wallet.network.connectedCopayers().length}}</h3>
|
|
||||||
|
|
||||||
<p class="text-info" ng-show="$root.wallet.publicKeyRing.requiredCopayers >$root.wallet.network.connectedCopayers()"> <i class="fi-alert size-28"></i>
|
<p class="text-info" ng-show="$root.wallet.publicKeyRing.requiredCopayers >$root.wallet.network.connectedCopayers()"> <i class="fi-alert size-28"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="large-12 columns p70l">
|
||||||
{{$root.wallet.publicKeyRing.requiredCopayers}} copayers needed for signing transactions
|
{{$root.wallet.publicKeyRing.requiredCopayers}} copayers needed for signing transactions
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<ul class="no-bullet">
|
<div class="row">
|
||||||
<li class="panel" ng-repeat="copayer in $root.wallet.network.connectedCopayers()">
|
<div class="large-4 columns"
|
||||||
<span ng-if="copayer === $root.wallet.getMyCopayerId()"> You </span>
|
ng-repeat="copayer in $root.wallet.getRegisteredPeerIds()">
|
||||||
{{copayer}}
|
<video
|
||||||
<span>
|
ng-class="($root.wallet.getOnlinePeerIDs().indexOf(copayer) != -1) ? 'online' : 'offline'"
|
||||||
<i class="fi-check size-16 panel-sign right p5h br100"></i>
|
class="video-small"
|
||||||
</span>
|
autoplay ng-show="$root.videoSrc[copayer]"
|
||||||
</li>
|
ng-src="{{$root.getVideoURL(copayer)}}"
|
||||||
</ul>
|
id="{{copayer + '-video'}}" muted="true"
|
||||||
|
title="{{copayer + (copayer == $root.wallet.network.peerId?' (You)':'')}}" ></video>
|
||||||
|
<img ng-show="!$root.videoSrc[copayer]"
|
||||||
|
ng-class="($root.wallet.getOnlinePeerIDs().indexOf(copayer) != -1) ? 'online' : 'offline'"
|
||||||
|
class="video-small"
|
||||||
|
src="/img/satoshi.gif"
|
||||||
|
title="{{copayer + (copayer == $root.wallet.network.peerId?' (You)':'')}}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -511,6 +519,7 @@
|
||||||
<script src="js/directives.js"></script>
|
<script src="js/directives.js"></script>
|
||||||
<script src="js/filters.js"></script>
|
<script src="js/filters.js"></script>
|
||||||
<script src="js/services/socket.js"></script>
|
<script src="js/services/socket.js"></script>
|
||||||
|
<script src="js/services/video.js"></script>
|
||||||
<script src="js/services/walletFactory.js"></script>
|
<script src="js/services/walletFactory.js"></script>
|
||||||
<script src="js/services/controllerUtils.js"></script>
|
<script src="js/services/controllerUtils.js"></script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ var copayApp = window.copayApp = angular.module('copay',[
|
||||||
'copay.socket',
|
'copay.socket',
|
||||||
'copay.controllerUtils',
|
'copay.controllerUtils',
|
||||||
'copay.setup',
|
'copay.setup',
|
||||||
'copay.directives'
|
'copay.directives',
|
||||||
|
'copay.video'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
angular.module('copay.header', []);
|
angular.module('copay.header', []);
|
||||||
|
|
@ -28,4 +29,5 @@ angular.module('copay.signin', []);
|
||||||
angular.module('copay.setup', []);
|
angular.module('copay.setup', []);
|
||||||
angular.module('copay.socket', []);
|
angular.module('copay.socket', []);
|
||||||
angular.module('copay.directives', []);
|
angular.module('copay.directives', []);
|
||||||
|
angular.module('copay.video', []);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ Wallet.prototype._handleNetworkChange = function(newCopayerId) {
|
||||||
if (newCopayerId) {
|
if (newCopayerId) {
|
||||||
this.log('#### Setting new PEER:', newCopayerId);
|
this.log('#### Setting new PEER:', newCopayerId);
|
||||||
this.sendWalletId(newCopayerId);
|
this.sendWalletId(newCopayerId);
|
||||||
|
this.emit('peer', this.network.peerFromCopayer(newCopayerId));
|
||||||
}
|
}
|
||||||
this.emit('refresh');
|
this.emit('refresh');
|
||||||
};
|
};
|
||||||
|
|
@ -176,7 +177,8 @@ Wallet.prototype.netStart = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
net.start(startOpts, function() {
|
net.start(startOpts, function() {
|
||||||
self.emit('created');
|
self.emit('created', net.getPeer());
|
||||||
|
var registered = self.getRegisteredPeerIds();
|
||||||
for (var i = 0; i < self.publicKeyRing.registeredCopayers(); i++) {
|
for (var i = 0; i < self.publicKeyRing.registeredCopayers(); i++) {
|
||||||
var otherId = self.getCopayerId(i);
|
var otherId = self.getCopayerId(i);
|
||||||
if (otherId !== myId) {
|
if (otherId !== myId) {
|
||||||
|
|
@ -191,6 +193,20 @@ Wallet.prototype.netStart = function() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Wallet.prototype.getOnlinePeerIDs = function() {
|
||||||
|
return this.network.getOnlinePeerIDs();
|
||||||
|
};
|
||||||
|
|
||||||
|
Wallet.prototype.getRegisteredPeerIds = function() {
|
||||||
|
var ret = [];
|
||||||
|
for (var i = 0; i < this.publicKeyRing.registeredCopayers(); i++) {
|
||||||
|
var cid = this.getCopayerId(i)
|
||||||
|
var pid = this.network.peerFromCopayer(cid);
|
||||||
|
ret.push(pid);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
Wallet.prototype.store = function(isSync) {
|
Wallet.prototype.store = function(isSync) {
|
||||||
this.log('[Wallet.js.135:store:]'); //TODO
|
this.log('[Wallet.js.135:store:]'); //TODO
|
||||||
var wallet = this.toObj();
|
var wallet = this.toObj();
|
||||||
|
|
@ -198,8 +214,7 @@ Wallet.prototype.store = function(isSync) {
|
||||||
|
|
||||||
if (isSync) {
|
if (isSync) {
|
||||||
this.log('Wallet stored.'); //TODO
|
this.log('Wallet stored.'); //TODO
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.log('Wallet stored. REFRESH Emitted'); //TODO
|
this.log('Wallet stored. REFRESH Emitted'); //TODO
|
||||||
this.emit('refresh');
|
this.emit('refresh');
|
||||||
}
|
}
|
||||||
|
|
@ -482,14 +497,18 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.remainderOut) {
|
if (!opts.remainderOut) {
|
||||||
opts.remainderOut ={ address: this.generateAddress(true).toString() };
|
opts.remainderOut = {
|
||||||
|
address: this.generateAddress(true).toString()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var b = new Builder(opts)
|
var b = new Builder(opts)
|
||||||
.setUnspent(utxos)
|
.setUnspent(utxos)
|
||||||
.setHashToScriptMap(pkr.getRedeemScriptMap())
|
.setHashToScriptMap(pkr.getRedeemScriptMap())
|
||||||
.setOutputs([{address: toAddress, amountSat: amountSat}])
|
.setOutputs([{
|
||||||
;
|
address: toAddress,
|
||||||
|
amountSat: amountSat
|
||||||
|
}]);
|
||||||
|
|
||||||
var signRet;
|
var signRet;
|
||||||
if (priv) {
|
if (priv) {
|
||||||
|
|
@ -526,4 +545,8 @@ console.log('[Wallet.js.524] DISC'); //TODO
|
||||||
this.network.disconnect();
|
this.network.disconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Wallet.prototype.getNetwork = function() {
|
||||||
|
return this.network;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = require('soop')(Wallet);
|
module.exports = require('soop')(Wallet);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ var Key = bitcore.Key;
|
||||||
* when an unknown data type arrives
|
* when an unknown data type arrives
|
||||||
*
|
*
|
||||||
* Provides
|
* Provides
|
||||||
|
* send(toPeerIds, {data}, cb?)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -23,7 +24,9 @@ function Network(opts) {
|
||||||
this.apiKey = opts.apiKey || 'lwjd5qra8257b9';
|
this.apiKey = opts.apiKey || 'lwjd5qra8257b9';
|
||||||
this.debug = opts.debug || 3;
|
this.debug = opts.debug || 3;
|
||||||
this.maxPeers = opts.maxPeers || 10;
|
this.maxPeers = opts.maxPeers || 10;
|
||||||
this.opts = { key: opts.key };
|
this.opts = {
|
||||||
|
key: opts.key
|
||||||
|
};
|
||||||
this.connections = {};
|
this.connections = {};
|
||||||
this.copayerForPeer = {};
|
this.copayerForPeer = {};
|
||||||
|
|
||||||
|
|
@ -71,7 +74,6 @@ Network._arrayRemove = function(el, array) {
|
||||||
return array;
|
return array;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Network.prototype.connectedCopayers = function() {
|
Network.prototype.connectedCopayers = function() {
|
||||||
var ret =[];
|
var ret =[];
|
||||||
for(var i in this.connectedPeers){
|
for(var i in this.connectedPeers){
|
||||||
|
|
@ -187,8 +189,6 @@ Network.prototype._onData = function(data, isInbound, peerId) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Network.prototype._checkAnyPeer = function() {
|
Network.prototype._checkAnyPeer = function() {
|
||||||
if (!this.connectedPeers.length) {
|
if (!this.connectedPeers.length) {
|
||||||
console.log('EMIT openError: no more peers, not even you!');
|
console.log('EMIT openError: no more peers, not even you!');
|
||||||
|
|
@ -267,8 +267,7 @@ Network.prototype._setupPeerHandlers = function(openCallback) {
|
||||||
console.log('### CLOSING CONN FROM:' + dataConn.peer);
|
console.log('### CLOSING CONN FROM:' + dataConn.peer);
|
||||||
dataConn.close();
|
dataConn.close();
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
self._setupConnectionHandlers(dataConn, true);
|
self._setupConnectionHandlers(dataConn, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -348,6 +347,13 @@ Network.prototype._sign = function(payload, copayerId) {
|
||||||
).toString('hex');
|
).toString('hex');
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
Network.prototype.getOnlinePeerIDs = function() {
|
||||||
|
return this.connectedPeers;
|
||||||
|
};
|
||||||
|
|
||||||
|
Network.prototype.getPeer = function() {
|
||||||
|
return this.peer;
|
||||||
};
|
};
|
||||||
|
|
||||||
Network.prototype._sendToOne = function(copayerId, payload, cb) {
|
Network.prototype._sendToOne = function(copayerId, payload, cb) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,16 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('copay.controllerUtils').factory('controllerUtils', function ($rootScope, $location, Socket) {
|
angular.module('copay.controllerUtils')
|
||||||
|
.factory('controllerUtils', function($rootScope, $sce, $location, Socket, video) {
|
||||||
var root = {};
|
var root = {};
|
||||||
|
$rootScope.videoSrc = {};
|
||||||
|
$rootScope.getVideoURL = function(copayer) {
|
||||||
|
var encoded = $rootScope.videoSrc[copayer];
|
||||||
|
if (!encoded) return;
|
||||||
|
var url = decodeURI(encoded);
|
||||||
|
var trusted = $sce.trustAsResourceUrl(url);
|
||||||
|
return trusted;
|
||||||
|
};
|
||||||
|
|
||||||
root.logout = function() {
|
root.logout = function() {
|
||||||
console.log('### DELETING WALLET'); //TODO
|
console.log('### DELETING WALLET'); //TODO
|
||||||
|
|
@ -13,7 +22,11 @@ angular.module('copay.controllerUtils').factory('controllerUtils', function ($ro
|
||||||
|
|
||||||
root.onError = function(scope) {
|
root.onError = function(scope) {
|
||||||
if (scope) scope.loading = false;
|
if (scope) scope.loading = false;
|
||||||
$rootScope.flashMessage = {type:'error', message: 'Could not connect to peer'};
|
$rootScope.flashMessage = {
|
||||||
|
type: 'error',
|
||||||
|
message: 'Could not connect to peer: ' +
|
||||||
|
scope
|
||||||
|
};
|
||||||
root.logout();
|
root.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -21,24 +34,34 @@ angular.module('copay.controllerUtils').factory('controllerUtils', function ($ro
|
||||||
root.onError(scope);
|
root.onError(scope);
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
root.setupUxHandlers = function(w) {
|
root.setupUxHandlers = function(w) {
|
||||||
|
var handlePeerVideo = function(err, peerID, url) {
|
||||||
|
if (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$rootScope.videoSrc[peerID] = encodeURI(url);
|
||||||
|
$rootScope.$apply();
|
||||||
|
};
|
||||||
w.on('badMessage', function(peerId) {
|
w.on('badMessage', function(peerId) {
|
||||||
$rootScope.flashMessage = {type:'error', message: 'Received wrong message from peer id:' + peerId};
|
$rootScope.flashMessage = {
|
||||||
|
type: 'error',
|
||||||
|
message: 'Received wrong message from peer id:' + peerId
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
w.on('created', function(myPeerID) {
|
||||||
w.on('created', function() {
|
video.setOwnPeer(myPeerID, w, handlePeerVideo);
|
||||||
$location.path('peer');
|
$location.path('peer');
|
||||||
$rootScope.wallet = w;
|
$rootScope.wallet = w;
|
||||||
root.updateBalance();
|
root.updateBalance();
|
||||||
});
|
});
|
||||||
|
|
||||||
w.on('refresh', function() {
|
w.on('refresh', function() {
|
||||||
console.log('[controllerUtils.js] Refreshing'); //TODO
|
console.log('[controllerUtils.js] Refreshing'); //TODO
|
||||||
root.updateBalance();
|
root.updateBalance();
|
||||||
});
|
});
|
||||||
|
|
||||||
w.on('openError', root.onErrorDigest);
|
w.on('openError', root.onErrorDigest);
|
||||||
|
w.on('peer', function(peerID) {
|
||||||
|
video.callPeer(peerID, handlePeerVideo);
|
||||||
|
});
|
||||||
w.on('close', root.onErrorDigest);
|
w.on('close', root.onErrorDigest);
|
||||||
w.netStart();
|
w.netStart();
|
||||||
};
|
};
|
||||||
|
|
@ -46,7 +69,6 @@ angular.module('copay.controllerUtils').factory('controllerUtils', function ($ro
|
||||||
root.updateBalance = function() {
|
root.updateBalance = function() {
|
||||||
var w = $rootScope.wallet;
|
var w = $rootScope.wallet;
|
||||||
if (!w) return;
|
if (!w) return;
|
||||||
|
|
||||||
w.getBalance(false, function(balance, balanceByAddr) {
|
w.getBalance(false, function(balance, balanceByAddr) {
|
||||||
$rootScope.totalBalance = balance;
|
$rootScope.totalBalance = balance;
|
||||||
$rootScope.balanceByAddr = balanceByAddr;
|
$rootScope.balanceByAddr = balanceByAddr;
|
||||||
|
|
@ -77,4 +99,3 @@ console.log('[controllerUtils.js.64]'); //TODO
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
68
js/services/video.js
Normal file
68
js/services/video.js
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Video = function() {
|
||||||
|
navigator.getUserMedia = navigator.getUserMedia ||
|
||||||
|
navigator.webkitGetUserMedia ||
|
||||||
|
navigator.mozGetUserMedia;
|
||||||
|
|
||||||
|
this.mediaConnections = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
Video.prototype.setOwnPeer = function(peer, wallet, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
|
||||||
|
navigator.getUserMedia({
|
||||||
|
audio: true,
|
||||||
|
video: true
|
||||||
|
}, function(stream) {
|
||||||
|
// This is called when user accepts using webcam
|
||||||
|
self.localStream = stream;
|
||||||
|
var online = wallet.getOnlinePeerIDs();
|
||||||
|
for (var i = 0; i < online.length; i++) {
|
||||||
|
var o = online[i];
|
||||||
|
var mc = self.mediaConnections[o];
|
||||||
|
if (o !== peer.id) {
|
||||||
|
self.callPeer(o, cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb(null, peer.id, URL.createObjectURL(stream));
|
||||||
|
}, function() {
|
||||||
|
cb(new Error('Failed to access the webcam and microphone.'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Receiving a call
|
||||||
|
peer.on('call', function(mediaConnection) {
|
||||||
|
if (self.localStream) {
|
||||||
|
mediaConnection.answer(self.localStream);
|
||||||
|
} else {
|
||||||
|
mediaConnection.answer();
|
||||||
|
}
|
||||||
|
self.mediaConnections[mediaConnection.peer] = mediaConnection;
|
||||||
|
self._addCall(mediaConnection, cb);
|
||||||
|
});
|
||||||
|
this.peer = peer;
|
||||||
|
};
|
||||||
|
|
||||||
|
Video.prototype.callPeer = function(peerID, cb) {
|
||||||
|
if (this.localStream) {
|
||||||
|
var mediaConnection = this.peer.call(peerID, this.localStream);
|
||||||
|
this._addCall(mediaConnection, cb);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Video.prototype._addCall = function(mediaConnection, cb) {
|
||||||
|
var peerID = mediaConnection.peer;
|
||||||
|
|
||||||
|
// Wait for stream on the call, then set peer video display
|
||||||
|
mediaConnection.on('stream', function(stream) {
|
||||||
|
cb(null, peerID, URL.createObjectURL(stream));
|
||||||
|
});
|
||||||
|
|
||||||
|
mediaConnection.on('close', function() {
|
||||||
|
});
|
||||||
|
mediaConnection.on('error', function() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
angular.module('copay.video').value('video', new Video());
|
||||||
Loading…
Add table
Add a link
Reference in a new issue