230 lines
6.6 KiB
JavaScript
230 lines
6.6 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const Gio = imports.gi.Gio;
|
||
|
const GLib = imports.gi.GLib;
|
||
|
const GObject = imports.gi.GObject;
|
||
|
const Gtk = imports.gi.Gtk;
|
||
|
|
||
|
const PluginsBase = imports.service.plugins.base;
|
||
|
|
||
|
|
||
|
var Metadata = {
|
||
|
label: _('Run Commands'),
|
||
|
id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.RunCommand',
|
||
|
incomingCapabilities: ['kdeconnect.runcommand', 'kdeconnect.runcommand.request'],
|
||
|
outgoingCapabilities: ['kdeconnect.runcommand', 'kdeconnect.runcommand.request'],
|
||
|
actions: {
|
||
|
commands: {
|
||
|
label: _('Commands'),
|
||
|
icon_name: 'system-run-symbolic',
|
||
|
|
||
|
parameter_type: new GLib.VariantType('s'),
|
||
|
incoming: ['kdeconnect.runcommand'],
|
||
|
outgoing: ['kdeconnect.runcommand.request']
|
||
|
},
|
||
|
executeCommand: {
|
||
|
label: _('Commands'),
|
||
|
icon_name: 'system-run-symbolic',
|
||
|
|
||
|
parameter_type: new GLib.VariantType('s'),
|
||
|
incoming: ['kdeconnect.runcommand'],
|
||
|
outgoing: ['kdeconnect.runcommand.request']
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
* RunCommand Plugin
|
||
|
* https://github.com/KDE/kdeconnect-kde/tree/master/plugins/remotecommands
|
||
|
* https://github.com/KDE/kdeconnect-kde/tree/master/plugins/runcommand
|
||
|
*/
|
||
|
var Plugin = GObject.registerClass({
|
||
|
GTypeName: 'GSConnectRunCommandPlugin',
|
||
|
Properties: {
|
||
|
'remote-commands': GObject.param_spec_variant(
|
||
|
'remote-commands',
|
||
|
'Remote Command List',
|
||
|
'A list of the device\'s remote commands',
|
||
|
new GLib.VariantType('a{sv}'),
|
||
|
null,
|
||
|
GObject.ParamFlags.READABLE
|
||
|
)
|
||
|
}
|
||
|
}, class Plugin extends PluginsBase.Plugin {
|
||
|
|
||
|
_init(device) {
|
||
|
super._init(device, 'runcommand');
|
||
|
|
||
|
// Local Commands
|
||
|
this._commandListChangedId = this.settings.connect(
|
||
|
'changed::command-list',
|
||
|
this.sendCommandList.bind(this)
|
||
|
);
|
||
|
|
||
|
// We cache remote commands so they can be used in the settings even
|
||
|
// when the device is offline.
|
||
|
this._remote_commands = {};
|
||
|
this.cacheProperties(['_remote_commands']);
|
||
|
}
|
||
|
|
||
|
get remote_commands() {
|
||
|
return this._remote_commands;
|
||
|
}
|
||
|
|
||
|
handlePacket(packet) {
|
||
|
// A request...
|
||
|
if (packet.type === 'kdeconnect.runcommand.request') {
|
||
|
// ...for the local command list
|
||
|
if (packet.body.hasOwnProperty('requestCommandList')) {
|
||
|
this.sendCommandList();
|
||
|
// ...to execute a command
|
||
|
} else if (packet.body.hasOwnProperty('key')) {
|
||
|
this._handleCommand(packet.body.key);
|
||
|
}
|
||
|
// A response to a request for the remote command list
|
||
|
} else if (packet.type === 'kdeconnect.runcommand') {
|
||
|
this._handleCommandList(packet.body.commandList);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
connected() {
|
||
|
super.connected();
|
||
|
|
||
|
// Disable the commands action until we know better
|
||
|
this.sendCommandList();
|
||
|
this.requestCommandList();
|
||
|
|
||
|
this._handleCommandList(this.remote_commands);
|
||
|
}
|
||
|
|
||
|
clearCache() {
|
||
|
this._remote_commands = {};
|
||
|
this.__cache_write();
|
||
|
this.notify('remote-commands');
|
||
|
}
|
||
|
|
||
|
cacheLoaded() {
|
||
|
if (this.device.connected) {
|
||
|
this.connected();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle a request to execute the local command with the UUID @key
|
||
|
* @param {String} key - The UUID of the local command
|
||
|
*/
|
||
|
_handleCommand(key) {
|
||
|
try {
|
||
|
let commandList = this.settings.get_value('command-list').recursiveUnpack();
|
||
|
|
||
|
if (!commandList.hasOwnProperty(key)) {
|
||
|
throw new Error(`Unknown command: ${key}`);
|
||
|
}
|
||
|
|
||
|
this.device.launchProcess([
|
||
|
'/bin/sh',
|
||
|
'-c',
|
||
|
commandList[key].command
|
||
|
]);
|
||
|
} catch (e) {
|
||
|
logError(e, this.device.name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Parse the response to a request for the remote command list. Remove the
|
||
|
* command menu if there are no commands, otherwise amend the menu.
|
||
|
*/
|
||
|
_handleCommandList(commandList) {
|
||
|
this._remote_commands = commandList;
|
||
|
this.notify('remote-commands');
|
||
|
|
||
|
let commandEntries = Object.entries(this.remote_commands);
|
||
|
|
||
|
// If there are no commands, hide the menu by disabling the action
|
||
|
this.device.lookup_action('commands').enabled = (commandEntries.length > 0);
|
||
|
|
||
|
// Commands Submenu
|
||
|
let submenu = new Gio.Menu();
|
||
|
|
||
|
for (let [uuid, info] of commandEntries) {
|
||
|
let item = new Gio.MenuItem();
|
||
|
item.set_label(info.name);
|
||
|
item.set_icon(
|
||
|
new Gio.ThemedIcon({name: 'application-x-executable-symbolic'})
|
||
|
);
|
||
|
item.set_detailed_action(`device.executeCommand::${uuid}`);
|
||
|
submenu.append_item(item);
|
||
|
}
|
||
|
|
||
|
// Commands Item
|
||
|
let item = new Gio.MenuItem();
|
||
|
item.set_detailed_action('device.commands::menu');
|
||
|
item.set_attribute_value(
|
||
|
'hidden-when',
|
||
|
new GLib.Variant('s', 'action-disabled')
|
||
|
);
|
||
|
item.set_icon(
|
||
|
new Gio.ThemedIcon({name: 'system-run-symbolic'})
|
||
|
);
|
||
|
item.set_label(_('Commands'));
|
||
|
item.set_submenu(submenu);
|
||
|
|
||
|
// If the submenu item is already present it will be replaced
|
||
|
let index = this.device.settings.get_strv('menu-actions').indexOf('commands');
|
||
|
|
||
|
if (index > -1) {
|
||
|
this.device.removeMenuAction('commands');
|
||
|
this.device.addMenuItem(item, index);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Placeholder function for command action
|
||
|
*/
|
||
|
commands() {}
|
||
|
|
||
|
/**
|
||
|
* Send a request to execute the remote command with the UUID @key
|
||
|
* @param {String} key - The UUID of the remote command
|
||
|
*/
|
||
|
executeCommand(key) {
|
||
|
this.device.sendPacket({
|
||
|
type: 'kdeconnect.runcommand.request',
|
||
|
body: {key: key}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send a request for the remote command list
|
||
|
*/
|
||
|
requestCommandList() {
|
||
|
this.device.sendPacket({
|
||
|
type: 'kdeconnect.runcommand.request',
|
||
|
body: {requestCommandList: true}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send the local command list
|
||
|
*/
|
||
|
sendCommandList() {
|
||
|
let commands = this.settings.get_value('command-list').recursiveUnpack();
|
||
|
|
||
|
this.device.sendPacket({
|
||
|
type: 'kdeconnect.runcommand',
|
||
|
body: {commandList: commands}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
destroy() {
|
||
|
if (this._commandListChangedId) {
|
||
|
this.settings.disconnect(this._commandListChangedId);
|
||
|
}
|
||
|
|
||
|
super.destroy();
|
||
|
}
|
||
|
});
|
||
|
|