mirror of
https://github.com/Klipper3d/klipper.git
synced 2026-02-08 09:10:56 -07:00
Merge 5e1b6242f8 into 87ea2ff1ce
This commit is contained in:
commit
75ad63ea76
4 changed files with 81 additions and 18 deletions
|
|
@ -9,16 +9,20 @@ control the Klipper host software.
|
|||
In order to use the API server, the klippy.py host software must be
|
||||
started with the `-a` parameter. For example:
|
||||
```
|
||||
~/klippy-env/bin/python ~/klipper/klippy/klippy.py ~/printer.cfg -a /tmp/klippy_uds -l /tmp/klippy.log
|
||||
~/klippy-env/bin/python ~/klipper/klippy/klippy.py ~/printer.cfg -a unix:///tmp/klippy_uds -l /tmp/klippy.log
|
||||
```
|
||||
|
||||
This causes the host software to create a Unix Domain Socket. A client
|
||||
can then open a connection on that socket and send commands to
|
||||
Klipper.
|
||||
|
||||
You can also use a TCP socket, using the tcp scheme (be careful if you expose Klipper on a public interface) :
|
||||
```
|
||||
~/klippy-env/bin/python ~/klipper/klippy/klippy.py ~/printer.cfg -a tcp://127.0.0.1:7120 -l /tmp/klippy.log
|
||||
```
|
||||
|
||||
See the [Moonraker](https://github.com/Arksine/moonraker) project for
|
||||
a popular tool that can forward HTTP requests to Klipper's API Server
|
||||
Unix Domain Socket.
|
||||
a popular tool that can forward HTTP requests to Klipper's API Server.
|
||||
|
||||
## Request format
|
||||
|
||||
|
|
@ -31,7 +35,8 @@ terminated by an ASCII 0x03 character:
|
|||
Klipper contains a `scripts/whconsole.py` tool that can perform the
|
||||
above message framing. For example:
|
||||
```
|
||||
~/klipper/scripts/whconsole.py /tmp/klippy_uds
|
||||
~/klipper/scripts/whconsole.py unix:///tmp/klippy_uds
|
||||
~/klipper/scripts/whconsole.py tcp://127.0.0.1:7120
|
||||
```
|
||||
|
||||
This tool can read a series of JSON commands from stdin, send them to
|
||||
|
|
|
|||
|
|
@ -268,7 +268,8 @@ def main():
|
|||
default='/tmp/printer',
|
||||
help="input tty name (default is /tmp/printer)")
|
||||
opts.add_option("-a", "--api-server", dest="apiserver",
|
||||
help="api server unix domain socket filename")
|
||||
help="api server url (unix:///path/to/file "
|
||||
"or tcp://ip[:port])")
|
||||
opts.add_option("-l", "--logfile", dest="logfile",
|
||||
help="write log to file instead of stderr")
|
||||
opts.add_option("-v", action="store_true", dest="verbose",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@
|
|||
# This file may be distributed under the terms of the GNU GPLv3 license
|
||||
import logging, socket, os, sys, errno, collections
|
||||
import gcode
|
||||
try:
|
||||
from urllib.parse import urlparse
|
||||
except ImportError:
|
||||
from urlparse import urlparse
|
||||
|
||||
try:
|
||||
import msgspec
|
||||
|
|
@ -126,10 +130,42 @@ class ServerSocket:
|
|||
if not server_address or is_fileinput:
|
||||
# Do not enable server
|
||||
return
|
||||
self._remove_socket_file(server_address)
|
||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
self.sock.setblocking(0)
|
||||
self.sock.bind(server_address)
|
||||
# Parsing the server_address configuration string
|
||||
server_url = urlparse(server_address, allow_fragments=False)
|
||||
if server_url.scheme == 'unix' or server_url.scheme == '':
|
||||
try:
|
||||
self._remove_socket_file(server_address)
|
||||
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
self.sock.setblocking(0)
|
||||
self.sock.bind(server_url.path)
|
||||
except FileNotFoundError as e:
|
||||
logging.exception(
|
||||
"webhooks: Unable to bind to unix socket '%s'"
|
||||
% (server_url.path))
|
||||
return
|
||||
elif server_url.scheme == 'tcp':
|
||||
try:
|
||||
if server_url.netloc.startswith('['):
|
||||
# IPv6 address
|
||||
self.sock = socket.socket(socket.AF_INET6,
|
||||
socket.SOCK_STREAM)
|
||||
else:
|
||||
# IPv4 address
|
||||
self.sock = socket.socket(socket.AF_INET,
|
||||
socket.SOCK_STREAM)
|
||||
self.sock.setblocking(0)
|
||||
self.sock.bind((server_url.hostname,
|
||||
server_url.port if server_url.port else 7120))
|
||||
except OSError as e:
|
||||
logging.exception(
|
||||
"webhooks: Unable to bind to '%s:%d'"
|
||||
% (server_url.hostname, server_url.port))
|
||||
return
|
||||
else:
|
||||
logging.exception(
|
||||
"webhooks: Unknown scheme '%s'"
|
||||
% (server_url.scheme))
|
||||
return
|
||||
self.sock.listen(1)
|
||||
self.fd_handle = self.reactor.register_fd(
|
||||
self.sock.fileno(), self._handle_accept)
|
||||
|
|
|
|||
|
|
@ -5,25 +5,46 @@
|
|||
#
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
import sys, os, optparse, socket, fcntl, select, json, errno, time
|
||||
try:
|
||||
from urllib.parse import urlparse
|
||||
except ImportError:
|
||||
from urlparse import urlparse
|
||||
|
||||
# Set a file-descriptor as non-blocking
|
||||
def set_nonblock(fd):
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL
|
||||
, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
||||
|
||||
def webhook_socket_create(uds_filename):
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.setblocking(0)
|
||||
sys.stderr.write("Waiting for connect to %s\n" % (uds_filename,))
|
||||
def webhook_socket_create(server_address):
|
||||
server_url = urlparse(server_address, allow_fragments=False)
|
||||
if server_url.scheme == 'unix' or server_url.scheme == '':
|
||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
sock.setblocking(0)
|
||||
server_address = server_url.path
|
||||
sys.stderr.write("Waiting for connect to %s\n" % (server_url.path,))
|
||||
elif server_url.scheme == 'tcp':
|
||||
if server_url.netloc.startswith('['):
|
||||
# IPv6 address
|
||||
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
|
||||
else:
|
||||
# IPv4 address
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server_address = (server_url.hostname,
|
||||
server_url.port if server_url.port else 7120)
|
||||
sys.stderr.write("Waiting for connect to %s:%d\n" % (server_address[0],
|
||||
server_address[1]))
|
||||
else:
|
||||
sys.stderr.write("Unknown scheme %s\n" % (server_url.scheme,))
|
||||
sys.exit(-1)
|
||||
while 1:
|
||||
try:
|
||||
sock.connect(uds_filename)
|
||||
sock.connect(server_address)
|
||||
except socket.error as e:
|
||||
if e.errno == errno.ECONNREFUSED:
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
sys.stderr.write("Unable to connect socket %s [%d,%s]\n"
|
||||
% (uds_filename, e.errno,
|
||||
% (server_address, e.errno,
|
||||
errno.errorcode[e.errno]))
|
||||
sys.exit(-1)
|
||||
break
|
||||
|
|
@ -31,10 +52,10 @@ def webhook_socket_create(uds_filename):
|
|||
return sock
|
||||
|
||||
class KeyboardReader:
|
||||
def __init__(self, uds_filename):
|
||||
def __init__(self, server_address):
|
||||
self.kbd_fd = sys.stdin.fileno()
|
||||
set_nonblock(self.kbd_fd)
|
||||
self.webhook_socket = webhook_socket_create(uds_filename)
|
||||
self.webhook_socket = webhook_socket_create(server_address)
|
||||
self.poll = select.poll()
|
||||
self.poll.register(sys.stdin, select.POLLIN | select.POLLHUP)
|
||||
self.poll.register(self.webhook_socket, select.POLLIN | select.POLLHUP)
|
||||
|
|
@ -76,7 +97,7 @@ class KeyboardReader:
|
|||
self.process_socket()
|
||||
|
||||
def main():
|
||||
usage = "%prog [options] <socket filename>"
|
||||
usage = "%prog [options] <server address>"
|
||||
opts = optparse.OptionParser(usage)
|
||||
options, args = opts.parse_args()
|
||||
if len(args) != 1:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue