MrDraw/src/octoprint/cli/client.py

239 lines
8 KiB
Python

# coding=utf-8
from __future__ import absolute_import, division, print_function
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
__copyright__ = "Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License"
import click
import json
import octoprint_client
from octoprint.cli import get_ctx_obj_option, bulk_options
from octoprint import init_settings, FatalStartupError
class JsonStringParamType(click.ParamType):
name = "json"
def convert(self, value, param, ctx):
try:
return json.loads(value)
except:
self.fail("%s is not a valid json string" % value, param, ctx)
def create_client(settings=None, apikey=None, host=None, port=None, httpuser=None, httppass=None, https=False, prefix=None):
assert(host is not None or settings is not None)
assert(port is not None or settings is not None)
assert(apikey is not None or settings is not None)
if not host:
host = settings.get(["server", "host"])
host = host if host != "0.0.0.0" else "127.0.0.1"
if not port:
port = settings.getInt(["server", "port"])
if not apikey:
apikey = settings.get(["api", "key"])
baseurl = octoprint_client.build_base_url(https=https,
httpuser=httpuser,
httppass=httppass,
host=host,
port=port,
prefix=prefix)
return octoprint_client.Client(baseurl, apikey)
client_options = bulk_options([
click.option("--apikey", "-a", type=click.STRING),
click.option("--host", "-h", type=click.STRING),
click.option("--port", "-p", type=click.INT),
click.option("--httpuser", type=click.STRING),
click.option("--httppass", type=click.STRING),
click.option("--https", is_flag=True),
click.option("--prefix", type=click.STRING)
])
"""Common options to configure an API client."""
@click.group()
def client_commands():
pass
@client_commands.group("client", context_settings=dict(ignore_unknown_options=True))
@client_options
@click.pass_context
def client(ctx, apikey, host, port, httpuser, httppass, https, prefix):
"""Basic API client."""
try:
settings = None
if not host or not port or not apikey:
settings = init_settings(get_ctx_obj_option(ctx, "basedir", None), get_ctx_obj_option(ctx, "configfile", None))
ctx.obj.client = create_client(settings=settings,
apikey=apikey,
host=host,
port=port,
httpuser=httpuser,
httppass=httppass,
https=https,
prefix=prefix)
except FatalStartupError as e:
click.echo(e.message, err=True)
click.echo("There was a fatal error initializing the client.", err=True)
ctx.exit(-1)
def log_response(response, status_code=True, body=True, headers=False):
if status_code:
click.echo("Status Code: {}".format(response.status_code))
if headers:
for header, value in response.headers.items():
click.echo("{}: {}".format(header, value))
click.echo()
if body:
click.echo(response.text)
@client.command("get")
@click.argument("path")
@click.option("--timeout", type=float, default=None)
@click.pass_context
def get(ctx, path, timeout):
"""Performs a GET request against the specified server path."""
r = ctx.obj.client.get(path, timeout=timeout)
log_response(r)
@client.command("post_json")
@click.argument("path")
@click.argument("data", type=JsonStringParamType())
@click.option("--timeout", type=float, default=None)
@click.pass_context
def post_json(ctx, path, data, timeout):
"""POSTs JSON data to the specified server path."""
r = ctx.obj.client.post_json(path, data, timeout=timeout)
log_response(r)
@client.command("patch_json")
@click.argument("path")
@click.argument("data", type=JsonStringParamType())
@click.option("--timeout", type=float, default=None, help="Request timeout in seconds")
@click.pass_context
def patch_json(ctx, path, data, timeout):
"""PATCHes JSON data to the specified server path."""
r = ctx.obj.client.patch(path, data, encoding="json", timeout=timeout)
log_response(r)
@client.command("post_from_file")
@click.argument("path")
@click.argument("file_path", type=click.Path(exists=True, dir_okay=False, resolve_path=True))
@click.option("--json", is_flag=True)
@click.option("--yaml", is_flag=True)
@click.option("--timeout", type=float, default=None, help="Request timeout in seconds")
@click.pass_context
def post_from_file(ctx, path, file_path, json_flag, yaml_flag, timeout):
"""POSTs JSON data to the specified server path, taking the data from the specified file."""
if json_flag or yaml_flag:
if json_flag:
with open(file_path, "rb") as fp:
data = json.load(fp)
else:
import yaml
with open(file_path, "rb") as fp:
data = yaml.safe_load(fp)
r = ctx.obj.client.post_json(path, data, timeout=timeout)
else:
with open(file_path, "rb") as fp:
data = fp.read()
r = ctx.obj.client.post(path, data, timeout=timeout)
log_response(r)
@client.command("command")
@click.argument("path")
@click.argument("command")
@click.option("--str", "-s", "str_params", multiple=True, nargs=2, type=click.Tuple([unicode, unicode]))
@click.option("--int", "-i", "int_params", multiple=True, nargs=2, type=click.Tuple([unicode, int]))
@click.option("--float", "-f", "float_params", multiple=True, nargs=2, type=click.Tuple([unicode, float]))
@click.option("--bool", "-b", "bool_params", multiple=True, nargs=2, type=click.Tuple([unicode, bool]))
@click.option("--timeout", type=float, default=None, help="Request timeout in seconds")
@click.pass_context
def command(ctx, path, command, str_params, int_params, float_params, bool_params, timeout):
"""Sends a JSON command to the specified server path."""
data = dict()
params = str_params + int_params + float_params + bool_params
for param in params:
data[param[0]] = param[1]
r = ctx.obj.client.post_command(path, command, additional=data, timeout=timeout)
log_response(r, body=False)
@client.command("upload")
@click.argument("path")
@click.argument("file_path", type=click.Path(exists=True, dir_okay=False, resolve_path=True))
@click.option("--parameter", "-P", "params", multiple=True, nargs=2, type=click.Tuple([unicode, unicode]))
@click.option("--file-name", type=click.STRING)
@click.option("--content-type", type=click.STRING)
@click.option("--timeout", type=float, default=None, help="Request timeout in seconds")
@click.pass_context
def upload(ctx, path, file_path, params, file_name, content_type, timeout):
"""Uploads the specified file to the specified server path."""
data = dict()
for param in params:
data[param[0]] = param[1]
r = ctx.obj.client.upload(path, file_path,
additional=data, file_name=file_name, content_type=content_type, timeout=timeout)
log_response(r)
@client.command("delete")
@click.argument("path")
@click.option("--timeout", type=float, default=None, help="Request timeout in seconds")
@click.pass_context
def delete(ctx, path, timeout):
"""Sends a DELETE request to the specified server path."""
r = ctx.obj.client.delete(path, timeout=timeout)
log_response(r)
@client.command("listen")
@click.pass_context
def listen(ctx):
def on_connect(ws):
click.echo(">>> Connected!")
def on_close(ws):
click.echo(">>> Connection closed!")
def on_error(ws, error):
click.echo("!!! Error: {}".format(error))
def on_heartbeat(ws):
click.echo("<3")
def on_message(ws, message_type, message_payload):
click.echo("Message: {}, Payload: {}".format(message_type, json.dumps(message_payload)))
socket = ctx.obj.client.create_socket(on_connect=on_connect,
on_close=on_close,
on_error=on_error,
on_heartbeat=on_heartbeat,
on_message=on_message)
click.echo(">>> Waiting for client to exit")
try:
socket.wait()
finally:
click.echo(">>> Goodbye...")