2013-01-29 17:47:40 +05:00
angular
2018-08-30 15:07:55 +05:30
. module ( "webui.services.rpc" , [
"webui.services.rpc.syscall" ,
"webui.services.configuration" ,
"webui.services.alerts" ,
"webui.services.utils"
] )
. factory ( "$rpc" , [
"$syscall" ,
"$globalTimeout" ,
"$alerts" ,
"$utils" ,
"$rootScope" ,
"$location" ,
"$authconf" ,
"$filter" ,
function ( syscall , globalTimeout , alerts , utils , rootScope , uri , authconf , filter ) {
var subscriptions = [ ] ,
configurations = [ authconf ] ,
currentConf = { } ,
currentToken ,
timeout = null ,
forceNextUpdate = false ;
var cookieConf = utils . getCookie ( "aria2conf" ) ;
// try at the start, so that it is presistant even when default authconf works
if ( cookieConf ) configurations . unshift ( cookieConf ) ;
if ( uri . search ( ) . host ) {
configurations . unshift ( uri . search ( ) ) ;
configurations [ 0 ] . auth = {
token : configurations [ 0 ] . token ,
user : configurations [ 0 ] . username ,
pass : configurations [ 0 ] . password
} ;
2014-05-17 17:41:00 +02:00
}
2013-01-15 13:24:09 +05:00
2018-08-30 15:07:55 +05:30
if ( [ "http" , "https" ] . indexOf ( uri . protocol ( ) ) != - 1 && uri . host ( ) != "localhost" ) {
configurations . push (
{
host : uri . host ( ) ,
path : "/jsonrpc" ,
port : 6800 ,
encrypt : false
} ,
{
host : uri . host ( ) ,
port : uri . port ( ) ,
path : "/jsonrpc" ,
encrypt : uri . protocol ( ) == "https"
} ,
{
host : uri . host ( ) ,
port : uri . port ( ) ,
path : authconf . path ,
encrypt : uri . protocol ( ) == "https"
}
) ;
2014-05-17 17:41:00 +02:00
}
2013-01-15 13:24:09 +05:00
2018-08-30 15:07:55 +05:30
// set if we got error on connection. This will cause another connection attempt.
var needNewConnection = true ;
2014-05-31 20:42:09 +08:00
2018-08-30 15:07:55 +05:30
// 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 ( ) {
clearTimeout ( timeout ) ;
timeout = null ;
2014-05-31 20:42:09 +08:00
2018-08-30 15:07:55 +05:30
subscriptions = _ . filter ( subscriptions , function ( e ) {
return ! ! e && e . once !== 2 ;
} ) ;
var subs = subscriptions . slice ( ) ;
if ( ! subs . length ) {
2016-03-09 22:37:51 +08:00
timeout = setTimeout ( update , globalTimeout ) ;
2014-05-17 17:41:00 +02:00
return ;
}
2018-08-30 15:07:55 +05:30
if ( syscall . state == "initializing" ) {
console . log ( "Syscall is initializing, waiting" ) ;
timeout = setTimeout ( update , globalTimeout ) ;
return ;
2013-03-02 12:01:07 +01:00
}
2018-08-30 15:07:55 +05:30
if ( needNewConnection && configurations . length ) {
needNewConnection = false ;
currentConf = configurations [ 0 ] ;
if ( currentConf && currentConf . auth && currentConf . auth . token ) {
currentToken = currentConf . auth . token ;
} else {
currentToken = null ;
}
syscall . init ( currentConf ) ;
timeout = setTimeout ( update , globalTimeout ) ;
return ;
}
2013-03-11 19:16:48 +01:00
2018-08-30 15:07:55 +05:30
var params = _ . map ( subs , function ( s ) {
var p = s . params ;
if ( currentToken ) {
p = [ "token:" + currentToken ] . concat ( p || [ ] ) ;
2013-01-15 13:24:09 +05:00
}
2018-08-30 15:07:55 +05:30
return {
methodName : s . name ,
params : p && p . length ? p : undefined
} ;
2013-01-15 13:24:09 +05:00
} ) ;
2018-08-30 15:07:55 +05:30
var error = function ( ) {
needNewConnection = true ;
var ind = configurations . indexOf ( currentConf ) ;
if ( ind != - 1 ) configurations . splice ( ind , 1 ) ;
// If some proposed configurations are still in the pipeline then retry
if ( configurations . length ) {
alerts . log (
filter ( "translate" ) (
"The last connection attempt was unsuccessful. Trying another configuration"
)
) ;
timeout = setTimeout ( update , 0 ) ;
} else {
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"
) ;
timeout = setTimeout ( update , globalTimeout ) ;
}
} ;
syscall . invoke ( {
name : "system.multicall" ,
params : [ params ] ,
success : function ( data ) {
var failed = _ . some ( data . result , function ( d ) {
return d . code && d . message === "Unauthorized" ;
} ) ;
if ( failed ) {
needNewConnection = true ;
alerts . addAlert (
"<strong>" +
filter ( "translate" ) ( "Oh Snap!" ) +
"</strong> " +
filter ( "translate" ) (
"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"
)
) ;
timeout = setTimeout ( update , globalTimeout ) ;
return ;
}
if ( configurations . length ) {
// configuration worked, save it in cookie for next time and
// delete the pipelined configurations!!
if ( currentToken )
alerts . addAlert (
filter ( "translate" ) ( "Successfully connected to Aria2 through its remote RPC …" ) ,
"success"
) ;
else
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)"
)
) ;
configurations = [ ] ;
}
2013-03-18 15:59:40 +01:00
2018-08-30 15:07:55 +05:30
utils . setCookie ( "aria2conf" , currentConf ) ;
var cbs = [ ] ;
_ . each ( data . result , function ( d , i ) {
var handle = subs [ i ] ;
if ( handle ) {
if ( d . code ) {
console . error ( handle , d ) ;
alerts . addAlert ( d . message , "error" ) ;
}
// run them later as the cb itself can mutate the subscriptions
cbs . push ( { cb : handle . cb , data : d } ) ;
if ( handle . once ) {
handle . once = 2 ;
}
}
} ) ;
_ . each ( cbs , function ( hnd ) {
hnd . cb ( hnd . data ) ;
} ) ;
rootScope . $digest ( ) ;
if ( forceNextUpdate ) {
forceNextUpdate = false ;
timeout = setTimeout ( update , 0 ) ;
} else {
timeout = setTimeout ( update , globalTimeout ) ;
}
} ,
error : error
2013-03-18 15:59:40 +01:00
} ) ;
2018-08-30 15:07:55 +05:30
} ;
2013-03-18 15:59:40 +01:00
2018-08-30 15:07:55 +05:30
// initiate the update loop
timeout = setTimeout ( update , globalTimeout ) ;
2013-03-12 07:51:44 +01:00
2018-08-30 15:07:55 +05:30
return {
// 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
configure : function ( conf ) {
alerts . addAlert (
filter ( "translate" ) (
"Trying to connect to aria2 using the new connection configuration"
) ,
"info"
) ;
if ( conf instanceof Array ) configurations = conf ;
else configurations = [ conf ] ;
if ( timeout ) {
clearTimeout ( timeout ) ;
timeout = setTimeout ( update , 0 ) ;
}
} ,
// get current configuration being used
getConfiguration : function ( ) {
return currentConf ;
} ,
// get currently configured directURL
getDirectURL : function ( ) {
return currentConf . directURL ;
} ,
// 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 ) {
cb = cb || angular . noop ;
params = params || [ ] ;
subscriptions . push ( {
once : true ,
name : "aria2." + name ,
params : params ,
cb : cb
} ) ;
if ( ! delay ) {
this . forceUpdate ( ) ;
}
} ,
// callback is called each time with updated syscall data
// 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 ) {
cb = cb || angular . noop ;
params = params || [ ] ;
var handle = {
once : false ,
name : "aria2." + name ,
params : params ,
cb : cb
} ;
subscriptions . push ( handle ) ;
if ( ! delay ) this . forceUpdate ( ) ;
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 ) ;
timeout = setTimeout ( update , 0 ) ;
} else {
// a batch call is already in progress,
// wait till it returns and force the next one
forceNextUpdate = true ;
}
2013-01-15 13:24:09 +05:00
}
} ;
}
2018-08-30 15:07:55 +05:30
] ) ;