aioupnp/txupnp/cli.py
Jack Robison 69f35aa54b
refactor
2018-10-04 17:06:02 -04:00

159 lines
5.2 KiB
Python

import os
import json
import argparse
import logging
from twisted.internet import reactor, defer
from txupnp.upnp import UPnP
log = logging.getLogger("txupnp")
@defer.inlineCallbacks
def get_external_ip(u, *_):
ip = yield u.get_external_ip()
print(ip)
@defer.inlineCallbacks
def list_mappings(u, *_):
redirects = yield u.get_redirects()
ext_ip = yield u.get_external_ip()
for (ext_host, ext_port, proto, int_port, int_host, enabled, desc, lease) in redirects:
print("{}:{}/{} --> {}:{} ({}) (expires: {}) - {} ".format(
ext_host or ext_ip, ext_port, proto, int_host, int_port, "enabled" if enabled else "disabled",
"never" if not lease else lease, desc)
)
@defer.inlineCallbacks
def add_mapping(u, *_):
port = 51413
protocol = "UDP"
description = "txupnp test mapping"
ext_port = yield u.get_next_mapping(port, protocol, description)
if ext_port:
print("external port: %i to local %i/%s" % (ext_port, port, protocol))
@defer.inlineCallbacks
def delete_mapping(u, *_):
port = 4567
protocol = "UDP"
yield u.delete_port_mapping(port, protocol)
mapping = yield u.get_specific_port_mapping(port, protocol)
if mapping:
print("failed to remove mapping")
else:
print("removed mapping")
def _encode(x):
if isinstance(x, bytes):
return x.decode()
elif isinstance(x, Exception):
return str(x)
return x
@defer.inlineCallbacks
def generate_test_data(u, *_):
external_ip = yield u.get_external_ip()
redirects = yield u.get_redirects()
ext_port = yield u.get_next_mapping(4567, "UDP", "txupnp test mapping")
delete = yield u.delete_port_mapping(ext_port, "UDP")
after_delete = yield u.get_specific_port_mapping(ext_port, "UDP")
commands_test_case = (
("get_external_ip", (), "1.2.3.4"),
("get_redirects", (), redirects),
("get_next_mapping", (4567, "UDP", "txupnp test mapping"), ext_port),
("delete_port_mapping", (ext_port, "UDP"), delete),
("get_specific_port_mapping", (ext_port, "UDP"), after_delete),
)
gateway = u.gateway
device = list(gateway.devices.values())[0]
assert device.manufacturer and device.modelName
device_path = os.path.join(os.getcwd(), "%s %s" % (device.manufacturer, device.modelName))
commands = gateway.debug_commands()
with open(device_path, "w") as f:
f.write(json.dumps({
"router_address": u.router_ip,
"client_address": u.lan_address,
"port": gateway.port,
"gateway_dict": gateway.as_dict(),
'expected_devices': [
{
'cache_control': 'max-age=1800',
'location': gateway.location,
'server': gateway.server,
'st': gateway.urn,
'usn': gateway.usn
}
],
'commands': commands,
'ssdp': u.sspd_factory.get_ssdp_packet_replay(),
'scpd': gateway.requester.dump_packets(),
'soap': commands_test_case
}, default=_encode, indent=2).replace(external_ip, "1.2.3.4"))
print("Generated test data! -> %s" % device_path)
cli_commands = {
"get_external_ip": get_external_ip,
"list_mappings": list_mappings,
"add_mapping": add_mapping,
"delete_mapping": delete_mapping,
"generate_test_data": generate_test_data,
}
@defer.inlineCallbacks
def run_command(found, u, command, debug_xml):
if not found:
print("failed to find gateway")
reactor.callLater(0, reactor.stop)
return
if command not in cli_commands:
print("unrecognized command: valid commands: %s" % list(cli_commands.keys()))
else:
yield cli_commands[command](u, debug_xml)
def main():
import logging
log = logging.getLogger("txupnp")
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(asctime)-15s-%(filename)s:%(lineno)s->%(message)s'))
log.addHandler(handler)
log.setLevel(logging.INFO)
parser = argparse.ArgumentParser(description="upnp command line utility")
parser.add_argument(dest="command", type=str, help="debug_gateway | list_mappings | get_external_ip | add_mapping | delete_mapping")
parser.add_argument("--debug_logging", dest="debug_logging", default=False, action="store_true")
parser.add_argument("--include_igd_xml", dest="include_igd_xml", default=False, action="store_true")
args = parser.parse_args()
if args.debug_logging:
# from twisted.python import log as tx_log
# observer = tx_log.PythonLoggingObserver(loggerName="txupnp")
# observer.start()
log.setLevel(logging.DEBUG)
command = args.command
command = command.replace("-", "_")
if command not in cli_commands:
print("unrecognized command: %s is not in %s" % (command, cli_commands.keys()))
return
def show(err):
print("error: {}".format(err))
u = UPnP(reactor, debug_ssdp=(command == "generate_test_data"))
d = u.discover()
d.addCallback(run_command, u, command, args.include_igd_xml)
d.addErrback(show)
d.addBoth(lambda _: reactor.callLater(0, reactor.stop))
reactor.run()
if __name__ == "__main__":
main()