@ -361,21 +361,30 @@ class ServerManager(util.LoggedClass):
coro = session . serve_requests ( )
future = asyncio . ensure_future ( coro )
self . sessions [ session ] = future
self . logger . info ( ' connection from {} , {:,d} total '
session . log_ info( ' connection from {} , {:,d} total '
. format ( session . peername ( ) , len ( self . sessions ) ) )
# Some connections are acknowledged after the servers are closed
if not self . servers :
self . close_session ( session )
def remove_session ( self , session ) :
self . subscription_count - = session . sub_count ( )
future = self . sessions . pop ( session )
future . cancel ( )
def close_session ( self , session ) :
''' Close the session ' s transport and cancel its future. '''
session . transport . close ( )
self . sessions [ session ] . cancel ( )
return ' {:d} disconnected ' . format ( session . id_ )
def remove_session ( self , session ) :
self . subscription_count - = session . sub_count ( )
future = self . sessions . pop ( session )
future . cancel ( )
def toggle_logging ( self , session ) :
''' Close the session ' s transport and cancel its future. '''
session . log_me = not session . log_me
if session . log_me :
return ' logging {:d} ' . format ( session . id_ )
else :
return ' not logging {:d} ' . format ( session . id_ )
def clear_stale_sessions ( self ) :
''' Cut off sessions that haven ' t done anything for 10 minutes. '''
@ -426,14 +435,15 @@ class ServerManager(util.LoggedClass):
return ( ' {:3d} : {:02d} : {:02d} '
. format ( t / / 3600 , ( t % 3600 ) / / 60 , t % 60 ) )
fmt = ( ' {:<4} {:>23} {:>15} {:>7} '
fmt = ( ' {:<4} {:>7} {:> 23} {:>15} {:>7} '
' {:>7} {:>7} {:>7} {:>7} {:>5} {:>9} ' )
yield fmt . format ( ' Type ' , ' Peer ' , ' Client ' , ' Subs ' ,
yield fmt . format ( ' Type ' , ' ID ' , ' Peer' , ' Client ' , ' Subs ' ,
' Recv ' , ' Recv KB ' , ' Sent ' , ' Sent KB ' ,
' Txs ' , ' Time ' )
for ( kind , peer , subs , client , recv_count , recv_size ,
for ( kind , id_ , log_me , peer , subs , client , recv_count , recv_size ,
send_count , send_size , txs_sent , time ) in data :
yield fmt . format ( kind , peer , client ,
yield fmt . format ( kind , str ( id_ ) + ( ' L ' if log_me else ' ' ) ,
peer , client ,
' {:,d} ' . format ( subs ) ,
' {:,d} ' . format ( recv_count ) ,
' {:,d} ' . format ( recv_size / / 1024 ) ,
@ -447,6 +457,8 @@ class ServerManager(util.LoggedClass):
now = time . time ( )
sessions = sorted ( self . sessions . keys ( ) , key = lambda s : s . start )
return [ ( session . kind ,
session . id_ ,
session . log_me ,
session . peername ( for_log = for_log ) ,
session . sub_count ( ) ,
session . client ,
@ -456,6 +468,33 @@ class ServerManager(util.LoggedClass):
now - session . start )
for session in sessions ]
def lookup_session ( self , param ) :
try :
id_ = int ( param )
except :
pass
else :
for session in self . sessions :
if session . id_ == id_ :
return session
return None
def for_each_session ( self , params , operation ) :
result = [ ]
for param in params :
session = self . lookup_session ( param )
if session :
result . append ( operation ( session ) )
else :
result . append ( ' unknown session: {} ' . format ( param ) )
return result
async def rpc_disconnect ( self , params ) :
return self . for_each_session ( params , self . close_session )
async def rpc_log ( self , params ) :
return self . for_each_session ( params , self . toggle_logging )
async def rpc_getinfo ( self , params ) :
return self . server_summary ( )
@ -503,10 +542,10 @@ class Session(JSONRPC):
''' Handle client disconnection. '''
super ( ) . connection_lost ( exc )
if self . error_count or self . send_size > = 1024 * 1024 :
self . logger . info ( ' {} disconnected. '
' Sent {:,d} bytes in {:,d} messages {:,d} errors '
. format ( self . peername ( ) , self . send_size ,
self . send_count , self . error_count ) )
self . log_info ( ' disconnected. Sent {:,d} bytes in {:,d} messages '
' {:,d} errors '
. format ( self . send_size , self . send_count ,
self . error_count ) )
self . manager . remove_session ( self )
async def handle_request ( self , method , params ) :
@ -532,7 +571,7 @@ class Session(JSONRPC):
break
except Exception :
# Getting here should probably be considered a bug and fixed
self . logger . error ( ' error handling request {} ' . format ( message ) )
self . log_ error ( ' error handling request {} ' . format ( message ) )
traceback . print_exc ( )
def sub_count ( self ) :
@ -656,8 +695,7 @@ class ElectrumX(Session):
self . send_json ( payload )
if matches :
self . logger . info ( ' notified {} of {} addresses '
. format ( self . peername ( ) , len ( matches ) ) )
self . log_info ( ' notified of {:,d} addresses ' . format ( len ( matches ) ) )
def height ( self ) :
''' Return the current flushed database height. '''
@ -843,12 +881,12 @@ class ElectrumX(Session):
tx_hash = await self . daemon . sendrawtransaction ( params )
self . txs_sent + = 1
self . manager . txs_sent + = 1
self . logger . info ( ' sent tx: {} ' . format ( tx_hash ) )
self . log_ info ( ' sent tx: {} ' . format ( tx_hash ) )
return tx_hash
except DaemonError as e :
error = e . args [ 0 ]
message = error [ ' message ' ]
self . logger . info ( ' sendrawtransaction: {} ' . format ( message ) )
self . log_ info ( ' sendrawtransaction: {} ' . format ( message ) )
if ' non-mandatory-script-verify-flag ' in message :
return (
' Your client produced a transaction that is not accepted '
@ -904,8 +942,8 @@ class ElectrumX(Session):
with codecs . open ( self . env . banner_file , ' r ' , ' utf-8 ' ) as f :
banner = f . read ( )
except Exception as e :
self . logger . error ( ' reading banner file {} : {} '
. format ( self . env . banner_file , e ) )
self . log_ error ( ' reading banner file {} : {} '
. format ( self . env . banner_file , e ) )
else :
network_info = await self . daemon . getnetworkinfo ( )
version = network_info [ ' version ' ]
@ -950,7 +988,8 @@ class LocalRPC(Session):
def __init__ ( self , * args ) :
super ( ) . __init__ ( * args )
cmds = ' getinfo sessions numsessions peers numpeers ' . split ( )
cmds = ( ' disconnect getinfo log numpeers numsessions peers sessions '
. split ( ) )
self . handlers = { cmd : getattr ( self . manager , ' rpc_ {} ' . format ( cmd ) )
for cmd in cmds }
self . client = ' RPC '