2014-04-17 07:46:49 -07:00
'use strict' ;
2014-06-12 13:42:26 -07:00
var bitcore = require ( 'bitcore' ) ;
2014-04-17 07:46:49 -07:00
2014-06-03 13:42:36 -07:00
angular . module ( 'copayApp.services' )
2014-06-30 14:41:17 -07:00
. factory ( 'controllerUtils' , function ( $rootScope , $sce , $location , notification , $timeout , Socket , video , uriHandler ) {
2014-04-23 17:20:44 -07:00
var root = { } ;
2014-05-16 14:33:06 -07:00
root . getVideoMutedStatus = function ( copayer ) {
2014-07-07 15:38:45 -07:00
if ( ! $rootScope . videoInfo ) return ;
2014-05-07 15:04:36 -07:00
var vi = $rootScope . videoInfo [ copayer ]
if ( ! vi ) {
return ;
}
return vi . muted ;
} ;
2014-04-23 17:20:44 -07:00
root . logout = function ( ) {
2014-06-24 08:57:15 -07:00
Socket . removeAllListeners ( ) ;
2014-04-23 17:20:44 -07:00
$rootScope . wallet = null ;
delete $rootScope [ 'wallet' ] ;
2014-04-28 07:56:27 -07:00
video . close ( ) ;
2014-05-16 14:33:06 -07:00
// Clear rootScope
for ( var i in $rootScope ) {
2014-05-20 08:30:20 -07:00
if ( i . charAt ( 0 ) != '$' ) {
2014-05-16 14:33:06 -07:00
delete $rootScope [ i ] ;
}
}
2014-07-23 13:10:02 -07:00
$location . path ( '/' ) ;
2014-04-23 17:20:44 -07:00
} ;
2014-04-17 12:27:15 -07:00
2014-04-23 17:20:44 -07:00
root . onError = function ( scope ) {
if ( scope ) scope . loading = false ;
root . logout ( ) ;
}
2014-04-23 14:07:20 -07:00
2014-06-09 17:00:28 -07:00
root . onErrorDigest = function ( scope , msg ) {
2014-04-23 17:20:44 -07:00
root . onError ( scope ) ;
2014-06-26 13:17:24 -07:00
if ( msg ) {
notification . error ( 'Error' , msg ) ;
}
2014-04-23 17:20:44 -07:00
$rootScope . $digest ( ) ;
2014-06-12 07:03:24 -07:00
} ;
root . installStartupHandlers = function ( wallet , $scope ) {
wallet . on ( 'connectionError' , function ( ) {
2014-06-26 13:17:24 -07:00
var message = "Looks like you are already connected to this wallet, please logout and try importing it again." ;
notification . error ( 'PeerJS Error' , message ) ;
2014-06-12 07:03:24 -07:00
root . onErrorDigest ( $scope ) ;
} ) ;
2014-07-07 10:18:11 -07:00
wallet . on ( 'serverError' , function ( m ) {
var message = m || 'The PeerJS server is not responding, please try again' ;
$location . path ( 'addresses' ) ;
root . onErrorDigest ( $scope , message ) ;
2014-06-12 07:03:24 -07:00
} ) ;
wallet . on ( 'ready' , function ( ) {
$scope . loading = false ;
} ) ;
} ;
2014-06-24 08:57:15 -07:00
root . setupRootVariables = function ( ) {
2014-06-30 14:41:17 -07:00
uriHandler . register ( ) ;
2014-06-24 08:57:15 -07:00
$rootScope . unitName = config . unitName ;
$rootScope . txAlertCount = 0 ;
$rootScope . insightError = 0 ;
$rootScope . isCollapsed = true ;
$rootScope . $watch ( 'txAlertCount' , function ( txAlertCount ) {
if ( txAlertCount && txAlertCount > 0 ) {
2014-07-08 04:58:24 -07:00
2014-06-24 08:57:15 -07:00
notification . info ( 'New Transaction' , ( $rootScope . txAlertCount == 1 ) ? 'You have a pending transaction proposal' : 'You have ' + $rootScope . txAlertCount + ' pending transaction proposals' , txAlertCount ) ;
}
} ) ;
2014-07-08 04:58:24 -07:00
$rootScope . $watch ( 'receivedFund' , function ( receivedFund ) {
if ( receivedFund ) {
var currentAddr ;
for ( var i = 0 ; i < $rootScope . addrInfos . length ; i ++ ) {
var addrinfo = $rootScope . addrInfos [ i ] ;
if ( addrinfo . address . toString ( ) == receivedFund [ 1 ] && ! addrinfo . isChange ) {
currentAddr = addrinfo . address . toString ( ) ;
break ;
}
}
if ( currentAddr ) {
//var beep = new Audio('sound/transaction.mp3');
notification . funds ( 'Received fund' , currentAddr , receivedFund ) ;
//beep.play();
}
}
} ) ;
2014-06-24 08:57:15 -07:00
} ;
2014-06-12 07:03:24 -07:00
root . startNetwork = function ( w , $scope ) {
2014-06-24 08:57:15 -07:00
Socket . removeAllListeners ( ) ;
2014-06-12 07:03:24 -07:00
2014-06-24 08:57:15 -07:00
root . setupRootVariables ( ) ;
2014-06-12 07:03:24 -07:00
root . installStartupHandlers ( w , $scope ) ;
2014-06-24 08:57:15 -07:00
root . setSocketHandlers ( ) ;
2014-04-24 19:13:55 -07:00
2014-04-23 17:20:44 -07:00
var handlePeerVideo = function ( err , peerID , url ) {
if ( err ) {
2014-05-07 15:04:36 -07:00
delete $rootScope . videoInfo [ peerID ] ;
2014-04-24 14:24:03 -07:00
return ;
2014-04-23 17:20:44 -07:00
}
2014-05-07 15:04:36 -07:00
$rootScope . videoInfo [ peerID ] = {
url : encodeURI ( url ) ,
muted : peerID === w . network . peerId
} ;
2014-04-30 15:50:13 -07:00
$rootScope . $digest ( ) ;
2014-04-23 17:20:44 -07:00
} ;
2014-05-20 07:05:18 -07:00
2014-06-18 09:01:50 -07:00
notification . enableHtml5Mode ( ) ; // for chrome: if support, enable it
2014-05-20 07:05:18 -07:00
2014-04-23 17:20:44 -07:00
w . on ( 'badMessage' , function ( peerId ) {
2014-06-26 13:17:24 -07:00
notification . error ( 'Error' , 'Received wrong message from peer ' + peerId ) ;
2014-04-23 17:20:44 -07:00
} ) ;
2014-05-09 08:14:57 -07:00
w . on ( 'ready' , function ( myPeerID ) {
2014-04-23 17:20:44 -07:00
$rootScope . wallet = w ;
2014-07-02 13:35:37 -07:00
if ( $rootScope . pendingPayment ) {
$location . path ( 'send' ) ;
} else {
$location . path ( 'addresses' ) ;
}
2014-06-09 11:59:18 -07:00
if ( ! config . disableVideo )
video . setOwnPeer ( myPeerID , w , handlePeerVideo ) ;
2014-04-23 17:20:44 -07:00
} ) ;
2014-05-16 14:48:17 -07:00
2014-05-16 21:19:52 -07:00
w . on ( 'publicKeyRingUpdated' , function ( dontDigest ) {
2014-06-24 08:57:15 -07:00
root . setSocketHandlers ( ) ;
2014-05-16 21:19:52 -07:00
if ( ! dontDigest ) {
$rootScope . $digest ( ) ;
}
2014-04-23 17:20:44 -07:00
} ) ;
2014-05-16 21:19:52 -07:00
w . on ( 'txProposalsUpdated' , function ( dontDigest ) {
2014-06-16 08:44:18 -07:00
root . updateTxs ( {
onlyPending : true
} ) ;
2014-06-12 13:42:26 -07:00
// give sometime to the tx to propagate.
$timeout ( function ( ) {
2014-06-16 08:44:18 -07:00
root . updateBalance ( function ( ) {
2014-06-12 13:42:26 -07:00
if ( ! dontDigest ) {
$rootScope . $digest ( ) ;
}
} ) ;
2014-06-16 08:44:18 -07:00
} , 3000 ) ;
2014-05-13 00:03:09 -07:00
} ) ;
2014-06-24 08:57:15 -07:00
w . on ( 'txProposalEvent' , function ( e ) {
2014-07-24 06:42:47 -07:00
var user = w . publicKeyRing . nicknameForCopayer ( e . cId ) ;
2014-06-13 13:24:44 -07:00
switch ( e . type ) {
case 'signed' :
2014-06-18 09:01:50 -07:00
notification . info ( 'Transaction Update' , 'A transaction was signed by ' + user ) ;
2014-06-13 13:24:44 -07:00
break ;
case 'rejected' :
2014-06-18 09:01:50 -07:00
notification . info ( 'Transaction Update' , 'A transaction was rejected by ' + user ) ;
2014-06-13 13:24:44 -07:00
break ;
2014-07-24 06:42:47 -07:00
case 'corrupt' :
notification . error ( 'Transaction Error' , 'Received corrupt transaction from ' + user ) ;
break ;
2014-06-13 13:24:44 -07:00
}
} ) ;
2014-06-18 16:18:13 -07:00
w . on ( 'addressBookUpdated' , function ( dontDigest ) {
if ( ! dontDigest ) {
$rootScope . $digest ( ) ;
}
} ) ;
2014-06-07 15:12:24 -07:00
w . on ( 'connectionError' , function ( msg ) {
2014-06-09 17:00:28 -07:00
root . onErrorDigest ( null , msg ) ;
2014-06-07 15:12:24 -07:00
} ) ;
2014-05-09 10:35:57 -07:00
w . on ( 'connect' , function ( peerID ) {
2014-06-09 11:59:18 -07:00
if ( peerID && ! config . disableVideo ) {
2014-05-09 10:35:57 -07:00
video . callPeer ( peerID , handlePeerVideo ) ;
}
2014-05-09 07:59:38 -07:00
$rootScope . $digest ( ) ;
2014-04-23 17:20:44 -07:00
} ) ;
2014-05-09 10:44:05 -07:00
w . on ( 'disconnect' , function ( peerID ) {
$rootScope . $digest ( ) ;
} ) ;
2014-04-23 17:20:44 -07:00
w . on ( 'close' , root . onErrorDigest ) ;
w . netStart ( ) ;
} ;
2014-04-24 12:35:52 -07:00
2014-05-16 14:33:06 -07:00
root . updateAddressList = function ( ) {
var w = $rootScope . wallet ;
2014-07-31 12:13:27 -07:00
if ( w && w . isReady ( ) )
2014-06-25 07:12:38 -07:00
$rootScope . addrInfos = w . getAddressesInfo ( ) ;
2014-05-16 14:33:06 -07:00
} ;
2014-05-15 13:43:41 -07:00
2014-05-16 14:33:06 -07:00
root . updateBalance = function ( cb ) {
2014-04-23 17:20:44 -07:00
var w = $rootScope . wallet ;
2014-06-05 08:18:54 -07:00
if ( ! w ) return root . onErrorDigest ( ) ;
2014-07-31 12:13:27 -07:00
if ( ! w . isReady ( ) ) return ;
2014-06-05 08:18:54 -07:00
2014-05-16 14:33:06 -07:00
$rootScope . balanceByAddr = { } ;
$rootScope . updatingBalance = true ;
2014-06-13 15:45:00 -07:00
2014-06-16 08:44:18 -07:00
w . getBalance ( function ( err , balanceSat , balanceByAddrSat , safeBalanceSat ) {
2014-05-21 14:03:11 -07:00
if ( err ) {
console . error ( 'Error: ' + err . message ) ; //TODO
2014-06-05 08:18:54 -07:00
root . _setCommError ( ) ;
2014-05-21 14:03:11 -07:00
return null ;
2014-06-16 08:44:18 -07:00
} else {
2014-06-05 08:18:54 -07:00
root . _clearCommError ( ) ;
}
2014-06-16 08:44:18 -07:00
var satToUnit = 1 / config . unitToSatoshi ;
var COIN = bitcore . util . COIN ;
$rootScope . totalBalance = balanceSat * satToUnit ;
2014-06-26 22:46:28 -07:00
$rootScope . totalBalanceBTC = ( balanceSat / COIN ) ;
2014-06-16 08:44:18 -07:00
$rootScope . availableBalance = safeBalanceSat * satToUnit ;
2014-06-26 22:46:28 -07:00
$rootScope . availableBalanceBTC = ( safeBalanceSat / COIN ) ;
2014-07-31 07:55:53 -07:00
$rootScope . lockedBalance = ( balanceSat - safeBalanceSat ) * satToUnit ;
$rootScope . lockedBalanceBTC = ( balanceSat - safeBalanceSat ) / COIN ;
2014-06-16 08:44:18 -07:00
var balanceByAddr = { } ;
for ( var ii in balanceByAddrSat ) {
balanceByAddr [ ii ] = balanceByAddrSat [ ii ] * satToUnit ;
}
2014-06-12 13:42:26 -07:00
$rootScope . balanceByAddr = balanceByAddr ;
2014-05-21 14:53:17 -07:00
root . updateAddressList ( ) ;
2014-05-16 14:33:06 -07:00
$rootScope . updatingBalance = false ;
2014-06-16 08:44:18 -07:00
return cb ? cb ( ) : null ;
2014-04-21 09:16:15 -07:00
} ) ;
2014-04-23 17:20:44 -07:00
} ;
2014-04-17 07:46:49 -07:00
2014-05-16 21:19:52 -07:00
root . updateTxs = function ( opts ) {
2014-05-13 00:03:09 -07:00
var w = $rootScope . wallet ;
if ( ! w ) return ;
2014-05-16 21:19:52 -07:00
opts = opts || { } ;
2014-06-16 08:44:18 -07:00
var satToUnit = 1 / config . unitToSatoshi ;
2014-05-14 22:12:14 -07:00
var myCopayerId = w . getMyCopayerId ( ) ;
2014-05-16 21:19:52 -07:00
var pendingForUs = 0 ;
2014-06-16 08:44:18 -07:00
var inT = w . getTxProposals ( ) . sort ( function ( t1 , t2 ) {
return t2 . createdTs - t1 . createdTs
} ) ;
var txs = [ ] ;
2014-05-13 00:03:09 -07:00
2014-06-16 08:44:18 -07:00
inT . forEach ( function ( i , index ) {
2014-05-20 14:34:55 -07:00
if ( opts . skip && ( index < opts . skip [ 0 ] || index >= opts . skip [ 1 ] ) ) {
return txs . push ( null ) ;
}
2014-05-14 22:12:14 -07:00
if ( myCopayerId != i . creator && ! i . finallyRejected && ! i . sentTs && ! i . rejectedByUs && ! i . signedByUs ) {
2014-05-16 21:19:52 -07:00
pendingForUs ++ ;
}
if ( ! i . finallyRejected && ! i . sentTs ) {
2014-06-16 08:44:18 -07:00
i . isPending = 1 ;
2014-05-16 21:19:52 -07:00
}
if ( ! opts . onlyPending || i . isPending ) {
2014-06-16 08:44:18 -07:00
var tx = i . builder . build ( ) ;
2014-05-16 21:19:52 -07:00
var outs = [ ] ;
tx . outs . forEach ( function ( o ) {
var addr = bitcore . Address . fromScriptPubKey ( o . getScript ( ) , config . networkName ) [ 0 ] . toString ( ) ;
2014-06-16 08:44:18 -07:00
if ( ! w . addressIsOwn ( addr , {
excludeMain : true
} ) ) {
2014-05-16 21:19:52 -07:00
outs . push ( {
2014-06-16 08:44:18 -07:00
address : addr ,
value : bitcore . util . valueToBigInt ( o . getValue ( ) ) * satToUnit ,
2014-05-16 21:19:52 -07:00
} ) ;
}
} ) ;
// extra fields
i . outs = outs ;
2014-06-16 08:44:18 -07:00
i . fee = i . builder . feeSat * satToUnit ;
2014-05-16 21:19:52 -07:00
i . missingSignatures = tx . countInputMissingSignatures ( 0 ) ;
2014-08-04 09:54:08 -07:00
i . actionList = getActionList ( i . peerActions ) ;
2014-05-16 21:19:52 -07:00
txs . push ( i ) ;
2014-05-13 01:02:21 -07:00
}
2014-05-14 22:12:14 -07:00
} ) ;
2014-06-16 08:44:18 -07:00
2014-08-04 09:54:08 -07:00
$rootScope . txs = txs ;
2014-05-16 21:19:52 -07:00
if ( $rootScope . pendingTxCount < pendingForUs ) {
$rootScope . txAlertCount = pendingForUs ;
2014-05-13 01:02:21 -07:00
}
2014-05-16 21:19:52 -07:00
$rootScope . pendingTxCount = pendingForUs ;
2014-06-16 08:44:18 -07:00
} ;
2014-05-13 00:03:09 -07:00
2014-08-04 09:54:08 -07:00
function getActionList ( actions ) {
var peers = Object . keys ( actions ) . map ( function ( i ) {
return { cId : i , actions : actions [ i ] }
} ) ;
return peers . sort ( function ( a , b ) {
return ! ! b . actions . create - ! ! a . actions . create ;
} ) ;
}
2014-06-30 08:00:14 -07:00
$rootScope . $watch ( 'insightError' , function ( status ) {
if ( status ) {
if ( status === - 1 ) {
notification . success ( 'Networking restored' , 'Connection to Insight re-established' ) ;
} else if ( ! isNaN ( status ) ) {
notification . error ( 'Networking problem' , 'Connection to Insight lost, reconnecting (attempt number ' + status + ')' ) ;
}
}
} ) ;
2014-06-04 14:10:47 -07:00
root . _setCommError = function ( e ) {
2014-06-16 08:44:18 -07:00
if ( $rootScope . insightError < 0 )
$rootScope . insightError = 0 ;
2014-06-05 08:18:54 -07:00
$rootScope . insightError ++ ;
2014-06-04 14:10:47 -07:00
} ;
root . _clearCommError = function ( e ) {
2014-06-16 08:44:18 -07:00
if ( $rootScope . insightError > 0 )
$rootScope . insightError = - 1 ;
2014-06-05 10:55:19 -07:00
else
2014-06-16 08:44:18 -07:00
$rootScope . insightError = 0 ;
2014-06-04 14:10:47 -07:00
} ;
2014-04-23 17:20:44 -07:00
root . setSocketHandlers = function ( ) {
2014-06-25 07:12:38 -07:00
root . updateAddressList ( ) ;
2014-06-04 14:10:47 -07:00
if ( ! Socket . sysEventsSet ) {
Socket . sysOn ( 'error' , root . _setCommError ) ;
Socket . sysOn ( 'reconnect_error' , root . _setCommError ) ;
Socket . sysOn ( 'reconnect_failed' , root . _setCommError ) ;
Socket . sysOn ( 'connect' , root . _clearCommError ) ;
Socket . sysOn ( 'reconnect' , root . _clearCommError ) ;
2014-06-16 08:44:18 -07:00
Socket . sysEventsSet = true ;
2014-06-04 14:10:47 -07:00
}
2014-04-30 10:28:33 -07:00
if ( ! $rootScope . wallet ) return ;
2014-04-18 15:08:01 -07:00
2014-06-16 08:44:18 -07:00
var currentAddrs = Socket . getListeners ( ) ;
2014-06-24 08:57:15 -07:00
var allAddrs = $rootScope . addrInfos ;
2014-06-16 08:44:18 -07:00
var newAddrs = [ ] ;
2014-06-24 08:57:15 -07:00
for ( var i in allAddrs ) {
var a = allAddrs [ i ] ;
if ( ! currentAddrs [ a . addressStr ] )
2014-05-16 14:33:06 -07:00
newAddrs . push ( a ) ;
}
for ( var i = 0 ; i < newAddrs . length ; i ++ ) {
2014-06-24 08:57:15 -07:00
Socket . emit ( 'subscribe' , newAddrs [ i ] . addressStr ) ;
2014-04-23 17:20:44 -07:00
}
2014-06-24 08:57:15 -07:00
newAddrs . forEach ( function ( a ) {
Socket . on ( a . addressStr , function ( txid ) {
if ( ! a . isChange )
2014-06-25 07:12:38 -07:00
notification . funds ( 'Funds received!' , a . addressStr ) ;
2014-06-24 08:57:15 -07:00
2014-06-16 08:44:18 -07:00
root . updateBalance ( function ( ) {
2014-05-16 14:33:06 -07:00
$rootScope . $digest ( ) ;
} ) ;
2014-04-23 17:20:44 -07:00
} ) ;
2014-04-17 09:25:36 -07:00
} ) ;
2014-06-23 10:57:23 -07:00
if ( ! $rootScope . wallet . spendUnconfirmed && ! Socket . isListeningBlocks ( ) ) {
Socket . emit ( 'subscribe' , 'inv' ) ;
Socket . on ( 'block' , function ( block ) {
root . updateBalance ( function ( ) {
2014-06-24 08:57:15 -07:00
$rootScope . $digest ( ) ;
2014-06-23 10:57:23 -07:00
} ) ;
} ) ;
}
2014-04-23 17:20:44 -07:00
} ;
return root ;
} ) ;