2013-01-29 13:47:40 +01:00
angular
2013-03-02 12:01:07 +01:00
. module ( 'webui.services.rpc' , [
2014-06-02 21:36:21 +02:00
'webui.services.rpc.syscall' , 'webui.services.configuration' , 'webui.services.alerts' ,
2013-03-11 19:16:48 +01:00
'webui.services.utils'
2013-03-02 12:01:07 +01:00
] )
2013-03-12 07:51:44 +01:00
. factory ( '$rpc' , [
'$syscall' , '$globalTimeout' , '$alerts' , '$utils' ,
2016-05-02 04:35:47 +02:00
'$rootScope' , '$location' , '$authconf' , '$filter' ,
function ( syscall , globalTimeout , alerts , utils , rootScope , uri , authconf , filter ) {
2013-03-02 12:01:07 +01:00
2013-01-17 07:51:03 +01:00
var subscriptions = [ ]
2016-03-10 07:55:29 +01:00
, configurations = [ authconf ]
2013-03-02 12:01:07 +01:00
, currentConf = { }
2014-05-17 17:41:00 +02:00
, currentToken
2013-01-17 07:51:03 +01:00
, timeout = null
, forceNextUpdate = false ;
2013-01-15 09:24:09 +01:00
2014-06-02 21:36:21 +02:00
var cookieConf = utils . getCookie ( 'aria2conf' ) ;
// try at the start, so that it is presistant even when default authconf works
2016-03-10 07:55:29 +01:00
if ( cookieConf ) configurations . unshift ( cookieConf ) ;
2014-06-02 21:36:21 +02:00
2014-05-31 14:59:02 +02:00
if ( [ 'http' , 'https' ] . indexOf ( uri . protocol ( ) ) != - 1 && uri . host ( ) != 'localhost' ) {
2014-06-02 21:36:21 +02:00
configurations . push ( {
2013-03-20 10:08:50 +01:00
host : uri . host ( ) ,
2015-09-12 10:55:02 +02:00
path : '/jsonrpc' ,
2013-03-19 22:03:34 +01:00
port : 6800 ,
encrypt : false
2015-09-12 10:55:02 +02:00
} ,
{
host : uri . host ( ) ,
port : uri . port ( ) ,
path : '/jsonrpc' ,
encrypt : ( uri . protocol ( ) == 'https' )
2016-03-04 20:01:26 +01:00
} ,
{
host : uri . host ( ) ,
port : uri . port ( ) ,
path : authconf . path ,
encrypt : ( uri . protocol ( ) == 'https' )
2013-03-19 22:03:34 +01:00
} ) ;
2013-03-20 10:08:50 +01:00
}
2013-03-19 22:03:34 +01:00
2013-01-15 09:24:09 +01:00
2016-04-13 11:23:19 +02:00
// set if we got error on connection. This will cause another connection attempt.
var needNewConnection = true ;
2013-01-15 09:24:09 +01:00
// update is implemented such that
// only one syscall at max is ongoing
// (i.e. serially) so should be private
// to maintain that invariant
var update = function ( ) {
2013-03-02 12:01:07 +01:00
clearTimeout ( timeout ) ;
timeout = null ;
2014-01-09 04:18:44 +01:00
subscriptions = _ . filter ( subscriptions , function ( e ) {
2014-03-14 13:59:12 +01:00
return ! ! e && e . once !== 2 ;
2014-01-09 04:18:44 +01:00
} ) ;
var subs = subscriptions . slice ( ) ;
if ( ! subs . length ) {
2016-04-13 11:23:19 +02:00
timeout = setTimeout ( update , globalTimeout ) ;
2013-01-17 07:51:03 +01:00
return ;
2013-03-02 12:01:07 +01:00
}
2013-01-17 07:51:03 +01:00
2016-04-13 11:23:19 +02:00
if ( syscall . state == 'initializing' ) {
console . log ( "Syscall is initializing, waiting" ) ;
timeout = setTimeout ( update , globalTimeout ) ;
return ;
}
if ( needNewConnection && configurations . length ) {
needNewConnection = false ;
2014-05-31 14:42:09 +02:00
currentConf = configurations [ 0 ] ;
2014-05-17 17:41:00 +02:00
if ( currentConf && currentConf . auth && currentConf . auth . token ) {
currentToken = currentConf . auth . token ;
}
else {
currentToken = null ;
}
2013-03-02 12:01:07 +01:00
syscall . init ( currentConf ) ;
2016-04-13 11:23:19 +02:00
timeout = setTimeout ( update , globalTimeout ) ;
return ;
2013-03-02 12:01:07 +01:00
}
2013-01-15 09:24:09 +01:00
2014-01-09 04:18:44 +01:00
var params = _ . map ( subs , function ( s ) {
2014-05-17 17:41:00 +02:00
var p = s . params ;
if ( currentToken ) {
p = [ "token:" + currentToken ] . concat ( p || [ ] ) ;
}
2013-01-15 09:24:09 +01:00
return {
methodName : s . name ,
2014-05-17 17:41:00 +02:00
params : p && p . length ? p : undefined
2013-01-15 09:24:09 +01:00
} ;
} ) ;
2014-05-17 17:41:00 +02:00
var error = function ( ) {
2016-04-13 11:23:19 +02:00
needNewConnection = true ;
2014-05-31 14:42:09 +02:00
var ind = configurations . indexOf ( currentConf ) ;
if ( ind != - 1 ) configurations . splice ( ind , 1 ) ;
2014-05-17 17:41:00 +02:00
// If some proposed configurations are still in the pipeline then retry
if ( configurations . length ) {
2016-05-02 04:35:47 +02:00
alerts . log ( filter ( 'translate' ) ( "The last connection attempt was unsuccessful. Trying another configuration" ) ) ;
2014-05-17 17:41:00 +02:00
timeout = setTimeout ( update , 0 ) ;
}
else {
2016-05-02 04:35:47 +02:00
alerts . addAlert ( '<strong>' + filter ( 'translate' ) ( 'Oh Snap!' ) + '</strong> ' +
filter ( 'translate' ) ( 'Could not connect to the aria2 RPC server. Will retry in 10 secs. You might want to check the connection settings by going to Settings > Connection Settings' )
, 'error' )
2016-03-09 15:37:51 +01:00
timeout = setTimeout ( update , globalTimeout ) ;
2014-05-17 17:41:00 +02:00
}
} ;
2013-01-15 09:24:09 +01:00
syscall . invoke ( {
name : 'system.multicall' ,
params : [ params ] ,
success : function ( data ) {
2016-12-23 11:31:01 +01:00
var failed = _ . some ( data . result , function ( d ) {
2014-05-17 17:41:00 +02:00
return d . code && d . message === "Unauthorized" ;
} ) ;
2014-05-31 14:42:09 +02:00
2014-05-17 17:41:00 +02:00
if ( failed ) {
2016-05-04 22:51:44 +02:00
needNewConnection = true ;
2014-05-31 14:42:09 +02:00
alerts . addAlert ( '<strong>Oh Snap!</strong> Authentication failed while connecting to Aria2 RPC server. Will retry in 10 secs. You might want to confirm your authentication details by going to Settings > Connection Settings' , 'error' ) ;
2016-03-09 15:37:51 +01:00
timeout = setTimeout ( update , globalTimeout ) ;
2014-05-17 17:41:00 +02:00
return ;
}
2013-03-02 12:01:07 +01:00
if ( configurations . length ) {
// configuration worked, save it in cookie for next time and
// delete the pipelined configurations!!
2014-05-31 14:59:02 +02:00
if ( currentToken )
2016-05-02 04:35:47 +02:00
alerts . addAlert ( filter ( 'translate' ) ( 'Successfully connected to Aria2 through its remote RPC …' ) , 'success' ) ;
2014-05-31 14:59:02 +02:00
else
2016-05-02 04:35:47 +02:00
alerts . addAlert ( filter ( 'translate' ) ( 'Successfully connected to Aria2 through remote RPC, however the connection is still insecure. For complete security try adding an authorization secret token while starting Aria2 (through the flag --rpc-secret)' ) ) ;
2013-03-02 12:01:07 +01:00
configurations = [ ] ;
}
2013-03-11 19:16:48 +01:00
utils . setCookie ( 'aria2conf' , currentConf ) ;
2013-03-18 15:59:40 +01:00
var cbs = [ ] ;
2013-01-15 09:24:09 +01:00
_ . each ( data . result , function ( d , i ) {
2014-01-09 04:18:44 +01:00
var handle = subs [ i ] ;
2013-01-15 09:24:09 +01:00
if ( handle ) {
2013-02-22 20:44:10 +01:00
if ( d . code ) {
2014-01-09 04:18:44 +01:00
console . error ( handle , d ) ;
2013-02-22 20:44:10 +01:00
alerts . addAlert ( d . message , 'error' ) ;
}
2013-03-18 15:59:40 +01:00
// run them later as the cb itself can mutate the subscriptions
cbs . push ( { cb : handle . cb , data : d } ) ;
2013-01-15 09:24:09 +01:00
if ( handle . once ) {
2014-01-09 04:18:44 +01:00
handle . once = 2 ;
2013-01-15 09:24:09 +01:00
}
}
} ) ;
2013-03-18 15:59:40 +01:00
_ . each ( cbs , function ( hnd ) {
hnd . cb ( hnd . data ) ;
} ) ;
rootScope . $digest ( ) ;
2013-03-12 07:51:44 +01:00
2013-01-15 09:24:09 +01:00
if ( forceNextUpdate ) {
forceNextUpdate = false ;
2013-03-02 12:01:07 +01:00
timeout = setTimeout ( update , 0 ) ;
}
else {
2016-03-09 15:37:51 +01:00
timeout = setTimeout ( update , globalTimeout ) ;
2013-01-15 09:24:09 +01:00
}
} ,
2014-05-17 17:41:00 +02:00
error : error
2013-01-15 09:24:09 +01:00
} ) ;
2013-03-02 12:01:07 +01:00
} ;
// initiate the update loop
2016-03-09 15:37:51 +01:00
timeout = setTimeout ( update , globalTimeout ) ;
2013-03-02 12:01:07 +01:00
2013-01-15 09:24:09 +01:00
return {
2013-01-17 07:51:03 +01:00
// conf can be configuration or array of configurations,
// each one will be tried one after the other till success,
// for all options for one conf read rpc/syscall.js
2013-01-15 09:24:09 +01:00
configure : function ( conf ) {
2016-05-02 04:35:47 +02:00
alerts . addAlert ( filter ( 'translate' ) ( 'Trying to connect to aria2 using the new connection configuration' ) , 'info' ) ;
2013-03-09 06:35:53 +01:00
2013-01-17 07:51:03 +01:00
if ( conf instanceof Array )
configurations = conf ;
else
configurations = [ conf ] ;
2014-05-31 14:42:09 +02:00
if ( timeout ) {
clearTimeout ( timeout ) ;
timeout = setTimeout ( update , 0 ) ;
}
2013-01-15 09:24:09 +01:00
} ,
2013-03-09 06:35:53 +01:00
// get current configuration being used
getConfiguration : function ( ) { return currentConf } ,
2015-04-28 19:31:04 +02:00
// get currently configured directURL
getDirectURL : function ( ) { return currentConf . directURL } ,
2015-07-11 07:59:31 +02:00
2013-01-28 15:18:21 +01:00
// syscall is done only once, delay is optional
// and pass true to only dispatch it in the global timeout
// which can be used to batch up once calls
once : function ( name , params , cb , delay ) {
2013-01-22 11:12:40 +01:00
cb = cb || angular . noop ;
params = params || [ ] ;
2015-07-11 07:59:31 +02:00
subscriptions . push ( {
2013-01-15 09:24:09 +01:00
once : true ,
name : 'aria2.' + name ,
params : params ,
cb : cb
} ) ;
2013-01-28 15:18:21 +01:00
if ( ! delay ) {
this . forceUpdate ( ) ;
}
2013-01-15 09:24:09 +01:00
} ,
// callback is called each time with updated syscall data
2013-01-28 15:18:21 +01:00
// after the global timeout, delay is optional and pass it
// true to dispatch the first syscall also on global timeout
// which can be used to batch the subscribe calls
subscribe : function ( name , params , cb , delay ) {
2013-01-22 11:12:40 +01:00
cb = cb || angular . noop ;
params = params || [ ] ;
2013-01-15 09:24:09 +01:00
var handle = {
once : false ,
name : 'aria2.' + name ,
params : params ,
cb : cb
} ;
subscriptions . push ( handle ) ;
2013-01-28 15:18:21 +01:00
if ( ! delay ) this . forceUpdate ( ) ;
2013-01-15 09:24:09 +01:00
return handle ;
} ,
// remove the subscribed callback by passing
// the returned handle bysubscribe
unsubscribe : function ( handle ) {
var ind = subscriptions . indexOf ( handle ) ;
subscriptions [ ind ] = null ;
} ,
// force the global syscall update
forceUpdate : function ( ) {
if ( timeout ) {
clearTimeout ( timeout ) ;
2013-03-02 12:01:07 +01:00
timeout = setTimeout ( update , 0 ) ;
2013-01-15 09:24:09 +01:00
}
else {
// a batch call is already in progress,
// wait till it returns and force the next one
forceNextUpdate = true ;
}
}
} ;
} ] ) ;