Files
i2p.itoopie/apps/sam/python/src/i2p/router.py

189 lines
5.5 KiB
Python
Raw Normal View History

# -------------------------------------------------------------
# router.py: I2P Project -- Router Control API for Python
# -------------------------------------------------------------
"""
Router Control API for Python
"""
import i2p
import i2p.sam
import i2p.eep
import socket as pysocket
import os, sys
import os.path
import time
import threading
import urllib2
check_addrlist = [i2p.sam.samaddr, i2p.eep.eepaddr]
router_config = 'router.config' # Router config filename
# True if our Python program started the router
our_router = False
our_router_lock = threading.Lock()
def find(dir=None):
"""Find the absolute path to a locally installed I2P router.
An I2P installation is located by looking in the
environment I2P, then in PATH, then in the dir argument
given to the function. It looks for startRouter.sh or
startRouter.bat. Raises ValueError if an I2P installation
could not be located.
"""
if sys.platform[:3] == 'win':
sep = ';'
else:
sep = ':'
L = []
if 'PATH' in os.environ: L += os.environ['PATH'].split(sep)
if 'I2P' in os.environ: L += os.environ['I2P'].split(sep)
if dir != None and dir != '': L += dir.split(sep)
for dirname in L:
filename = os.path.join(dirname, 'startRouter.bat')
if os.path.exists(filename):
return dirname
filename = os.path.join(dirname, 'startRouter.sh')
if os.path.exists(filename):
return dirname
raise ValueError('I2P installation not found')
def check(dir=None):
"""Checks whether a locally installed router is running. Does
nothing if successful, otherwise raises i2p.RouterError.
An I2P installation is located by using find(dir).
The router.config file is parsed for 'router.adminPort'.
This port is queried to determine whether the router is
running.
"""
config = _parse_config(os.path.join(find(dir), router_config))
port = config.get('router.adminPort', '')
try:
port = int(port)
except:
raise ValueError('router.adminPort missing or bad in ' +
router_config)
try:
s = pysocket.socket(pysocket.AF_INET, pysocket.SOCK_STREAM)
s.connect(('127.0.0.1', port))
s.close()
except pysocket.error:
raise i2p.RouterError('could not contact 127.0.0.1:' + str(port))
def _run_program(filename):
"""Runs the given program in a new process and new terminal."""
if sys.platform[:3] == 'win':
os.startfile(filename)
global our_router
our_router = True
else:
# Linux possibilities:
# sh -c command
# xterm -e command
# bash -c command
# Try os.spawnl() with the above.
raise ValueError('unimplemented')
def start(dir=None, hidden=False):
"""Start a locally installed I2P router. Does nothing if
the router has already been started.
An I2P installation is located by using find(dir).
If hidden is True, do not show a terminal for the router.
"""
routerdir = find(dir)
router = os.path.join(routerdir, 'startRouter.bat')
try:
check(dir)
return # Already running
except:
pass # Not yet running
olddir = os.getcwd()
if hidden:
raise ValueError('unimplemented')
our_router_lock.acquire()
try:
os.chdir(routerdir)
try:
_run_program(router)
finally:
os.chdir(olddir)
finally:
our_router_lock.release()
# Ideas for hidden=True:
# Parse startRouter.bat, and run same command with javaw
# on Windows to hide command box.
# Perhaps use javaw (?) or javaws (j2sdk1.4.2/jre/javaws/javaws)
# Perhaps /path-to/program 2>/dev/null 1>/dev/null&
def _parse_config(filename):
"""Return a dict with (name, value) items for the given I2P configuration file."""
f = open(filename, 'r')
s = f.read()
f.close()
ans = {}
for line in s.split('\n'):
line = line.strip()
if '#' in line: line = line[:line.find('#')]
pair = line.split('=')
if len(pair) == 2:
ans[pair[0].strip()] = pair[1].strip()
return ans
def stop(dir=None, force=False):
"""Stop a locally installed I2P router, if it was started by
the current Python program. If force is True, stop the
router even if it was started by another process. Do nothing
if force is False and the router was started by another program.
The file 'router.config' is located using the same search
process used for find(dir). It is parsed for
'router.shutdownPassword' and 'router.adminPort'. The
router is shut down through the admin port.
Raises i2p.RouterError if the I2P router is running but cannot
be stopped. You must uncomment the
'router.shutdownPassword' line for this command to work.
"""
if force == False and our_router == False:
return
config = _parse_config(os.path.join(find(dir), router_config))
password = config.get('router.shutdownPassword', '')
if password == '':
raise ValueError('router.shutdownPassword not found in ' +
router_config)
admin_port = config.get('router.adminPort', '')
if admin_port == '':
raise ValueError('router.adminPort not found in ' + router_config)
try:
admin_port = int(admin_port)
except:
raise ValueError('invalid router.adminPort in ' + router_config)
try:
sock = pysocket.socket(pysocket.AF_INET, pysocket.SOCK_STREAM)
sock.connect(('127.0.0.1', admin_port))
sock.send('GET /shutdown?password=' + password + ' HTTP/1.0\r\n\r\n')
time.sleep(0.01)
sock.close()
except:
raise i2p.RouterError('router shutdown failed')
# Assume shutdown succeeded (it will take 30 seconds).