Skip to content

Commit

Permalink
exec commands by name
Browse files Browse the repository at this point in the history
  • Loading branch information
metallkopf committed Oct 29, 2024
1 parent ae5067e commit 4627142
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 24 deletions.
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ Konnect is based on the [KDE Connect](https://community.kde.org/KDEConnect) prot
python3 -m venv venv

# Wheels for systemd
venv/bin/pip install "konnect[systemd] @ https://github.com/metallkopf/konnect/releases/download/0.2.0/konnect-0.2.0-py3-none-any.whl"
venv/bin/pip install "konnect[systemd] @ https://github.com/metallkopf/konnect/releases/download/0.2.1/konnect-0.2.1-py3-none-any.whl"

# Wheels for generic init
venv/bin/pip install https://github.com/metallkopf/konnect/releases/download/0.2.0/konnect-0.2.0-py3-none-any.whl
venv/bin/pip install https://github.com/metallkopf/konnect/releases/download/0.2.1/konnect-0.2.1-py3-none-any.whl

# From source
venv/bin/pip install git+https://github.com/metallkopf/konnect.git@master#egg=konnect
Expand Down Expand Up @@ -111,9 +111,9 @@ sudo systemctl enable konnect
| GET | /command/\(@name\|identifier\) | List device commands | |
| POST | /command/\(@name\|identifier\) | Add device command | name, command |
| DELETE | /command/\(@name\|identifier\) | Remove all device commands | |
| PUT | /command/\(@name\|identifier\)/\(key\) | Update device command | name, command |
| DELETE | /command/\(@name\|identifier\)/\(key\) | Remove device command | |
| PATCH | /command/\(@name\|identifier\)/\(key\) | Execute \(remote\) device command | |
| PUT | /command/\(@name\|identifier\)/\(=name\|key\) | Update device command | name, command |
| DELETE | /command/\(@name\|identifier\)/\(=name\|key\) | Remove device command | |
| PATCH | /command/\(@name\|identifier\)/\(=name\|key\) | Execute \(remote\) device command | |
| POST | /custom/\(@name\|identifier\) | Custom packet \(for testing only\) | type, body \(optional\) |
| GET | /device | List all devices | |
| GET | /device/\(@name\|identifier\) | Device info | |
Expand Down Expand Up @@ -193,12 +193,16 @@ devices:
```bash
./venv/bin/konnect pair --device @computer
# or
./venv/bin/konnect pair --device f81d4fae-7dec-11d0-a765-00a0c91e6bf6
```

### Ping device

```bash
./venv/bin/konnect ping --device @computer
# or
./venv/bin/konnect pair --device f81d4fae-7dec-11d0-a765-00a0c91e6bf6
```

### Send notification
Expand All @@ -221,13 +225,15 @@ key: update
### Execute (remote) command

```bash
./venv/bin/konnect exec --device @computer --key =kernel
# or
./venv/bin/konnect exec --device @computer --key 00112233-4455-6677-8899-aabbccddeeff
```

### Add (local) command

```bash
./venv/bin/konnect command --device @computer --name "reboot" --command "sudo reboot"
./venv/bin/konnect command --device @computer --name reboot --command "sudo reboot"
```

```yaml
Expand Down
2 changes: 1 addition & 1 deletion konnect/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.2.0"
__version__ = "0.2.1"
41 changes: 31 additions & 10 deletions konnect/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from shutil import copyfile, move
from tempfile import gettempdir, mkstemp
from traceback import print_exc
from urllib.parse import unquote_plus
from uuid import uuid4

from PIL import Image
Expand Down Expand Up @@ -41,7 +42,7 @@

class API(Resource):
isLeaf = True
PATTERN = r"^\/(?P<res>[a-z]+)\/(?P<dev>[\w+\.@\- ]+)((?:\/)(?P<key>[\w+\-]+))?$"
PATTERN = r"^\/(?P<res>[a-z]+)\/(?P<dev>@?.+?)((?:\/)(?P<key>=?.+?))?$"

def __init__(self, konnect, discovery, database, debug):
super().__init__()
Expand All @@ -55,7 +56,7 @@ def __init__(self, konnect, discovery, database, debug):

def _getDeviceId(self, item):
key = "name" if item[0] == "@" else "identifier"
value = item[1:] if key == "name" else item
value = unquote_plus(item[1:] if key == "name" else item)

for device in self.konnect.getDevices().values():
if device[key] == value:
Expand Down Expand Up @@ -143,7 +144,7 @@ def process(self, method, uri, content):
if not client and checks[1]:
raise DeviceNotReachableError()

key = matches["key"]
key = unquote_plus(matches["key"]) if matches["key"] else None

if key and not checks[2]:
raise NotImplementedError2()
Expand All @@ -165,11 +166,11 @@ def process(self, method, uri, content):
elif resource == "command" and method == "GET":
return self._handleListCommands(identifier)
elif resource == "command" and method == "POST":
return self._handleCreateCommand(identifier, data)
return self._handleCreateCommand(identifier, client, data)
elif resource == "command" and method == "PUT":
return self._handleUpdateCommand(identifier, key, data)
return self._handleUpdateCommand(identifier, client, key, data)
elif resource == "command" and method == "DELETE":
return self._handleDeleteCommand(identifier, key)
return self._handleDeleteCommand(identifier, client, key)
elif resource == "command" and method == "PATCH":
return self._handleExecuteCommand(client, key)
elif resource == "custom" and method == "POST":
Expand Down Expand Up @@ -269,7 +270,7 @@ def _handleCreateNotification(self, identifier, client, data):

def _handleDeleteNotification(self, identifier, client, reference=None):
if not reference:
return {}, 501
raise ApiError("reference not found", 400)

self.database.cancelNotification(identifier, reference)

Expand All @@ -281,25 +282,33 @@ def _handleDeleteNotification(self, identifier, client, reference=None):
def _handleListCommands(self, identifier):
return {"commands": self.database.listCommands(identifier)}, 200

def _handleCreateCommand(self, identifier, data):
def _handleCreateCommand(self, identifier, client, data):
if not data.get("name") or not data.get("command"):
raise ApiError("name or command not found", 400)

key = str(uuid4())
self.database.addCommand(identifier, key, data["name"], data["command"])

if client:
client.sendCommands()

return {"key": key}, 201

def _handleUpdateCommand(self, identifier, key, data):
def _handleUpdateCommand(self, identifier, client, key, data):
if not data.get("name") or not data.get("command"):
raise ApiError("name or command not found", 400)

if self.database.getCommand(identifier, key):
self.database.updateCommand(identifier, key, data["name"], data["command"])

if client:
client.sendCommands()

return {}, 200

raise ApiError("not found", 404)

def _handleDeleteCommand(self, identifier, key=None):
def _handleDeleteCommand(self, identifier, client, key=None):
if key:
if self.database.getCommand(identifier, key):
self.database.remCommand(identifier, key)
Expand All @@ -308,9 +317,21 @@ def _handleDeleteCommand(self, identifier, key=None):
else:
self.database.remCommands(identifier)

if client:
client.sendCommands()

return {}, 204

def _handleExecuteCommand(self, client, key):
if key.startswith("="):
for key2, item in client.commands.items():
if item["name"] == key[1:]:
key = key2
break

if not client.commands.get(key):
raise ApiError("key not found", 404)

client.sendRun(key)
return {}, 200

Expand Down
4 changes: 2 additions & 2 deletions konnect/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def main():
command.add_argument("--delete", action="store_true", help="Delete command")
is_delete = "--delete" in sys.argv
delete = command.add_argument_group("delete")
delete.add_argument("--key", type=str, required=is_delete, help="Key identifier")
delete.add_argument("--key", type=str, required=is_delete, help="Command =name or key")
details = command.add_argument_group("details")
details.add_argument("--name", type=str, required=not is_delete, help="Name to show")
details.add_argument("--command", metavar="CMD", type=str, required=not is_delete, help="Command to execute")
Expand All @@ -178,7 +178,7 @@ def main():

exec_ = subparsers.add_parser("exec", help="Execute remote command...")
exec_.add_argument("--device", metavar="DEV", type=str, required=True)
exec_.add_argument("--key", type=str, required=True, help="Key identifier")
exec_.add_argument("--key", type=str, required=True, help="Command =name or key")

subparsers.add_parser("info", help="Show server info")

Expand Down
5 changes: 0 additions & 5 deletions konnect/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ def __init__(self, message, code=500, parent=None):
self.parent = str(parent) if parent else None


class UnknownError(ApiError):
def __init__(self, parent=None):
super().__init__("unknown error", 500, parent)


class UnserializationError(ApiError):
def __init__(self, parent=None):
super().__init__("unserialization error", 400, parent)
Expand Down
1 change: 1 addition & 0 deletions konnect/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def sendCancel(self, reference):

def sendCommands(self):
commands = {}

for row in self.database.listCommands(self.identifier):
commands[row["key"]] = {"name": row["name"], "command": row["command"]}

Expand Down

0 comments on commit 4627142

Please sign in to comment.