From 89514e4a4e6229db5ba965353c9414eab30b4301 Mon Sep 17 00:00:00 2001 From: Andy Holmes Date: Thu, 3 Aug 2023 20:57:13 -0700 Subject: [PATCH] refactor: port to `Gio._promisify()` This tech-preview isn't going anywhere, and in fact will become a part of GJS soon. Port to the more modern async-await patterns throughout the service. --- installed-tests/fixtures/backend.js | 192 +++++------------- src/service/__init__.js | 40 ++++ src/service/backends/lan.js | 271 +++++++------------------ src/service/components/clipboard.js | 121 ++--------- src/service/components/contacts.js | 130 ++---------- src/service/components/input.js | 123 ++++------- src/service/components/mpris.js | 64 ++---- src/service/components/notification.js | 163 ++++++--------- src/service/components/session.js | 72 ++----- src/service/components/sound.js | 13 +- src/service/components/upower.js | 19 +- src/service/core.js | 117 ++++------- src/service/plugin.js | 20 +- src/service/plugins/notification.js | 29 +-- src/service/plugins/photo.js | 33 ++- src/service/plugins/sftp.js | 173 +++++----------- src/service/utils/dbus.js | 20 -- 17 files changed, 448 insertions(+), 1152 deletions(-) diff --git a/installed-tests/fixtures/backend.js b/installed-tests/fixtures/backend.js index b3f3873a0..e126c35e7 100644 --- a/installed-tests/fixtures/backend.js +++ b/installed-tests/fixtures/backend.js @@ -113,16 +113,11 @@ var ChannelService = GObject.registerClass({ _initUdpListener() { // Default broadcast address this._udp_address = Gio.InetSocketAddress.new_from_string( - '255.255.255.255', - this.port - ); + '255.255.255.255', this.port); try { - this._udp6 = Gio.Socket.new( - Gio.SocketFamily.IPV6, - Gio.SocketType.DATAGRAM, - Gio.SocketProtocol.UDP - ); + this._udp6 = Gio.Socket.new(Gio.SocketFamily.IPV6, + Gio.SocketType.DATAGRAM, Gio.SocketProtocol.UDP); this._udp6.set_broadcast(true); // Bind the socket @@ -153,11 +148,8 @@ var ChannelService = GObject.registerClass({ } try { - this._udp4 = Gio.Socket.new( - Gio.SocketFamily.IPV4, - Gio.SocketType.DATAGRAM, - Gio.SocketProtocol.UDP - ); + this._udp4 = Gio.Socket.new(Gio.SocketFamily.IPV4, + Gio.SocketType.DATAGRAM, Gio.SocketProtocol.UDP); this._udp4.set_broadcast(true); // Bind the socket @@ -191,11 +183,8 @@ var ChannelService = GObject.registerClass({ // Try to peek the remote address try { - host = socket.receive_message( - [], - Gio.SocketMsgFlags.PEEK, - null - )[1].address.to_string(); + host = socket.receive_message([], Gio.SocketMsgFlags.PEEK, null)[1] + .address.to_string(); } catch (e) { logError(e); } @@ -246,21 +235,12 @@ var ChannelService = GObject.registerClass({ this._channels.set(channel.address, channel); // Open a TCP connection - const connection = await new Promise((resolve, reject) => { - const address = Gio.InetSocketAddress.new_from_string( - packet.body.tcpHost, - packet.body.tcpPort - ); - const client = new Gio.SocketClient({enable_proxy: false}); - - client.connect_async(address, null, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - reject(e); - } - }); - }); + const address = Gio.InetSocketAddress.new_from_string( + packet.body.tcpHost, packet.body.tcpPort); + + const client = new Gio.SocketClient({enable_proxy: false}); + const connection = await client.connect_async(address, + this.cancellable); // Connect the channel and attach it to the device on success await channel.open(connection); @@ -406,45 +386,6 @@ var Channel = GObject.registerClass({ this._port = port; } - _receiveIdent(connection) { - return new Promise((resolve, reject) => { - this.input_stream.read_line_async( - GLib.PRIORITY_DEFAULT, - this.cancellable, - (stream, res) => { - try { - const data = stream.read_line_finish_utf8(res)[0]; - this.identity = new Core.Packet(data); - - if (!this.identity.body.deviceId) - throw new Error('missing deviceId'); - - resolve(); - } catch (e) { - reject(e); - } - } - ); - }); - } - - _sendIdent(connection) { - return new Promise((resolve, reject) => { - connection.get_output_stream().write_all_async( - this.backend.identity.serialize(), - GLib.PRIORITY_DEFAULT, - this.cancellable, - (stream, res) => { - try { - resolve(stream.write_all_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - async accept(connection) { try { this._connection = connection; @@ -454,7 +395,13 @@ var Channel = GObject.registerClass({ base_stream: this._connection.get_input_stream(), }); - await this._receiveIdent(this._connection); + const [data] = await this.input_stream.read_line_async( + GLib.PRIORITY_DEFAULT, this.cancellable); + + this.identity = new Core.Packet(data); + + if (!this.identity.body.deviceId) + throw new Error('missing deviceId'); } catch (e) { this.close(); return e; @@ -470,7 +417,10 @@ var Channel = GObject.registerClass({ base_stream: this._connection.get_input_stream(), }); - await this._sendIdent(this._connection); + await connection.output_stream.write_all_async( + this.backend.identity.serialize(), + GLib.PRIORITY_DEFAULT, + this.cancellable); } catch (e) { this.close(); return e; @@ -487,6 +437,7 @@ var Channel = GObject.registerClass({ this.backend.channels.delete(this.address); this.cancellable.cancel(); + // These calls are not Promisified, so they can finish themselves if (this._connection) this._connection.close_async(GLib.PRIORITY_DEFAULT, null, null); @@ -498,27 +449,18 @@ var Channel = GObject.registerClass({ } async download(packet, target, cancellable = null) { - const connection = await new Promise((resolve, reject) => { - const client = new Gio.SocketClient({enable_proxy: false}); + const address = Gio.InetSocketAddress.new_from_string(this.host, + packet.payloadTransferInfo.port); - const address = Gio.InetSocketAddress.new_from_string( - this.host, - packet.payloadTransferInfo.port - ); - - client.connect_async(address, cancellable, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - const source = connection.get_input_stream(); + const client = new Gio.SocketClient({enable_proxy: false}); + const connection = await client.connect_async(address, cancellable); // Start the transfer - const transferredSize = await this._transfer(source, target, cancellable); + const transferredSize = await connection.output_stream.splice_async( + target, connection.input_stream, + (Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | + Gio.OutputStreamSpliceFlags.CLOSE_TARGET), + GLib.PRIORITY_DEFAULT, cancellable); if (transferredSize !== packet.payloadSize) { throw new Gio.IOErrorEnum({ @@ -548,31 +490,24 @@ var Channel = GObject.registerClass({ } // Listen for the incoming connection - const acceptConnection = new Promise((resolve, reject) => { - listener.accept_async( - cancellable, - (listener, res, source_object) => { - try { - resolve(listener.accept_finish(res)[0]); - } catch (e) { - reject(e); - } - } - ); - }); + const acceptConnection = listener.accept_async(cancellable); // Notify the device we're ready packet.body.payloadHash = this.checksum; packet.payloadSize = size; packet.payloadTransferInfo = {port: port}; - this.sendPacket(new Core.Packet(packet)); + const sendPacket = this.sendPacket(new Core.Packet(packet), + cancellable); // Accept the connection and configure the channel - const connection = await acceptConnection; - const target = connection.get_output_stream(); + const [, connection] = await Promise([sendPacket, acceptConnection]); // Start the transfer - const transferredSize = await this._transfer(source, target, cancellable); + const transferredSize = await connection.output_stream.splice_async( + source, + (Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | + Gio.OutputStreamSpliceFlags.CLOSE_TARGET), + GLib.PRIORITY_DEFAULT, cancellable); if (transferredSize !== size) { throw new Gio.IOErrorEnum({ @@ -582,25 +517,6 @@ var Channel = GObject.registerClass({ } } - _transfer(source, target, cancellable) { - return new Promise((resolve, reject) => { - target.splice_async( - source, - (Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | - Gio.OutputStreamSpliceFlags.CLOSE_TARGET), - GLib.PRIORITY_DEFAULT, - cancellable, - (target, res) => { - try { - resolve(target.splice_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - async rejectTransfer(packet) { try { if (!packet || !packet.hasPayload()) @@ -609,22 +525,12 @@ var Channel = GObject.registerClass({ if (packet.payloadTransferInfo.port === undefined) return; - const connection = await new Promise((resolve, reject) => { - const client = new Gio.SocketClient({enable_proxy: false}); - - const address = Gio.InetSocketAddress.new_from_string( - this.host, - packet.payloadTransferInfo.port - ); - - client.connect_async(address, null, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - resolve(); - } - }); - }); + const address = Gio.InetSocketAddress.new_from_string(this.host, + packet.payloadTransferInfo.port); + + const client = new Gio.SocketClient({enable_proxy: false}); + const connection = await client.connect_async(address, + this.cancellable); connection.close_async(GLib.PRIORITY_DEFAULT, null, null); } catch (e) { diff --git a/src/service/__init__.js b/src/service/__init__.js index 24ec8867c..a1e7a82b1 100644 --- a/src/service/__init__.js +++ b/src/service/__init__.js @@ -14,6 +14,46 @@ const GLib = imports.gi.GLib; const Config = imports.config; +// Promise Wrappers +try { + const {EBook, EDataServer} = imports.gi; + + Gio._promisify(EBook.BookClient, 'connect'); + Gio._promisify(EBook.BookClient.prototype, 'get_view'); + Gio._promisify(EBook.BookClient.prototype, 'get_contacts'); + Gio._promisify(EDataServer.SourceRegistry, 'new'); +} finally { + // Silence import errors +} + +Gio._promisify(Gio.AsyncInitable.prototype, 'init_async'); +Gio._promisify(Gio.DBusConnection.prototype, 'call'); +Gio._promisify(Gio.DBusProxy.prototype, 'call'); +Gio._promisify(Gio.DataInputStream.prototype, 'read_line_async', + 'read_line_finish_utf8'); +Gio._promisify(Gio.File.prototype, 'delete_async'); +Gio._promisify(Gio.File.prototype, 'enumerate_children_async'); +Gio._promisify(Gio.File.prototype, 'load_contents_async'); +Gio._promisify(Gio.File.prototype, 'mount_enclosing_volume'); +Gio._promisify(Gio.File.prototype, 'query_info_async'); +Gio._promisify(Gio.File.prototype, 'read_async'); +Gio._promisify(Gio.File.prototype, 'replace_async'); +Gio._promisify(Gio.File.prototype, 'replace_contents_bytes_async', + 'replace_contents_finish'); +Gio._promisify(Gio.FileEnumerator.prototype, 'next_files_async'); +Gio._promisify(Gio.Mount.prototype, 'unmount_with_operation'); +Gio._promisify(Gio.InputStream.prototype, 'close_async'); +Gio._promisify(Gio.OutputStream.prototype, 'close_async'); +Gio._promisify(Gio.OutputStream.prototype, 'splice_async'); +Gio._promisify(Gio.OutputStream.prototype, 'write_all_async'); +Gio._promisify(Gio.SocketClient.prototype, 'connect_async'); +Gio._promisify(Gio.SocketListener.prototype, 'accept_async'); +Gio._promisify(Gio.Subprocess.prototype, 'communicate_utf8_async'); +Gio._promisify(Gio.Subprocess.prototype, 'wait_check_async'); +Gio._promisify(Gio.TlsConnection.prototype, 'handshake_async'); +Gio._promisify(Gio.DtlsConnection.prototype, 'handshake_async'); + + // User Directories Config.CACHEDIR = GLib.build_filenamev([GLib.get_user_cache_dir(), 'gsconnect']); Config.CONFIGDIR = GLib.build_filenamev([GLib.get_user_config_dir(), 'gsconnect']); diff --git a/src/service/backends/lan.js b/src/service/backends/lan.js index c8b1902aa..a5357bf28 100644 --- a/src/service/backends/lan.js +++ b/src/service/backends/lan.js @@ -250,16 +250,11 @@ var ChannelService = GObject.registerClass({ _initUdpListener() { // Default broadcast address this._udp_address = Gio.InetSocketAddress.new_from_string( - '255.255.255.255', - this.port - ); + '255.255.255.255', this.port); try { - this._udp6 = Gio.Socket.new( - Gio.SocketFamily.IPV6, - Gio.SocketType.DATAGRAM, - Gio.SocketProtocol.UDP - ); + this._udp6 = Gio.Socket.new(Gio.SocketFamily.IPV6, + Gio.SocketType.DATAGRAM, Gio.SocketProtocol.UDP); this._udp6.set_broadcast(true); // Bind the socket @@ -290,11 +285,8 @@ var ChannelService = GObject.registerClass({ } try { - this._udp4 = Gio.Socket.new( - Gio.SocketFamily.IPV4, - Gio.SocketType.DATAGRAM, - Gio.SocketProtocol.UDP - ); + this._udp4 = Gio.Socket.new(Gio.SocketFamily.IPV4, + Gio.SocketType.DATAGRAM, Gio.SocketProtocol.UDP); this._udp4.set_broadcast(true); // Bind the socket @@ -324,21 +316,20 @@ var ChannelService = GObject.registerClass({ } _onIncomingIdentity(socket) { - let host, data, packet; + let host; // Try to peek the remote address try { - host = socket.receive_message( - [], - Gio.SocketMsgFlags.PEEK, - null - )[1].address.to_string(); + host = socket.receive_message([], Gio.SocketMsgFlags.PEEK, null)[1] + .address.to_string(); } catch (e) { logError(e); } // Whether or not we peeked the address, we need to read the packet try { + let data; + if (socket === this._udp6) data = this._udp6_stream.read_line_utf8(null)[0]; else @@ -346,9 +337,9 @@ var ChannelService = GObject.registerClass({ // Discard the packet if we failed to peek the address if (host === undefined) - return; + return GLib.SOURCE_CONTINUE; - packet = new Core.Packet(data); + const packet = new Core.Packet(data); packet.body.tcpHost = host; this._onIdentity(packet); } catch (e) { @@ -386,21 +377,12 @@ var ChannelService = GObject.registerClass({ this._channels.set(channel.address, channel); // Open a TCP connection - const connection = await new Promise((resolve, reject) => { - const address = Gio.InetSocketAddress.new_from_string( - packet.body.tcpHost, - packet.body.tcpPort - ); - const client = new Gio.SocketClient({enable_proxy: false}); - - client.connect_async(address, null, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - reject(e); - } - }); - }); + const address = Gio.InetSocketAddress.new_from_string( + packet.body.tcpHost, packet.body.tcpPort); + + const client = new Gio.SocketClient({enable_proxy: false}); + const connection = await client.connect_async(address, + this.cancellable); // Connect the channel and attach it to the device on success await channel.open(connection); @@ -488,9 +470,7 @@ var ChannelService = GObject.registerClass({ if (this._networkChangedId === 0) { this._networkAvailable = this._networkMonitor.network_available; this._networkChangedId = this._networkMonitor.connect( - 'network-changed', - this._onNetworkChanged.bind(this) - ); + 'network-changed', this._onNetworkChanged.bind(this)); } this._active = true; @@ -604,31 +584,6 @@ var Channel = GObject.registerClass({ this._port = port; } - /** - * Handshake Gio.TlsConnection - * - * @param {Gio.TlsConnection} connection - A TLS connection - * @return {Promise} A promise for the operation - */ - _handshake(connection) { - return new Promise((resolve, reject) => { - connection.validation_flags = Gio.TlsCertificateFlags.EXPIRED; - connection.authentication_mode = Gio.TlsAuthenticationMode.REQUIRED; - - connection.handshake_async( - GLib.PRIORITY_DEFAULT, - this.cancellable, - (connection, res) => { - try { - resolve(connection.handshake_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - /** * Authenticate a TLS connection. * @@ -637,7 +592,11 @@ var Channel = GObject.registerClass({ */ async _authenticate(connection) { // Standard TLS Handshake - await this._handshake(connection); + connection.validation_flags = Gio.TlsCertificateFlags.EXPIRED; + connection.authentication_mode = Gio.TlsAuthenticationMode.REQUIRED; + + await connection.handshake_async(GLib.PRIORITY_DEFAULT, + this.cancellable); // Get a settings object for the device let settings; @@ -706,10 +665,8 @@ var Channel = GObject.registerClass({ _encryptClient(connection) { _configureSocket(connection); - connection = Gio.TlsClientConnection.new( - connection, - connection.socket.remote_address - ); + connection = Gio.TlsClientConnection.new(connection, + connection.socket.remote_address); connection.set_certificate(this.certificate); return this._authenticate(connection); @@ -736,13 +693,17 @@ var Channel = GObject.registerClass({ } /** - * Read the identity packet from the new connection + * Negotiate an incoming connection * - * @param {Gio.SocketConnection} connection - An unencrypted socket - * @return {Promise} A promise for the operation + * @param {Gio.TcpConnection} connection - The incoming connection */ - _receiveIdent(connection) { - return new Promise((resolve, reject) => { + async accept(connection) { + debug(`${this.address} (${this.uuid})`); + + try { + this._connection = connection; + this.backend.channels.set(this.address, this); + // In principle this disposable wrapper could buffer more than the // identity packet, but in practice the remote device shouldn't send // any more data until the TLS connection is negotiated. @@ -751,66 +712,15 @@ var Channel = GObject.registerClass({ close_base_stream: false, }); - stream.read_line_async( - GLib.PRIORITY_DEFAULT, - this.cancellable, - (stream, res) => { - try { - const data = stream.read_line_finish_utf8(res)[0]; - stream.close(null); - - // Store the identity as an object property - this.identity = new Core.Packet(data); - - // Reject connections without a deviceId - if (!this.identity.body.deviceId) - throw new Error('missing deviceId'); - - resolve(); - } catch (e) { - reject(e); - } - } - ); - }); - } + const data = await stream.read_line_async(GLib.PRIORITY_DEFAULT, + this.cancellable); + stream.close_async(GLib.PRIORITY_DEFAULT, null, null); - /** - * Write our identity packet to the new connection - * - * @param {Gio.SocketConnection} connection - An unencrypted socket - * @return {Promise} A promise for the operation - */ - _sendIdent(connection) { - return new Promise((resolve, reject) => { - connection.get_output_stream().write_all_async( - this.backend.identity.serialize(), - GLib.PRIORITY_DEFAULT, - this.cancellable, - (stream, res) => { - try { - resolve(stream.write_all_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - - /** - * Negotiate an incoming connection - * - * @param {Gio.TcpConnection} connection - The incoming connection - */ - async accept(connection) { - debug(`${this.address} (${this.uuid})`); + this.identity = new Core.Packet(data[0]); - try { - this._connection = connection; - this.backend.channels.set(this.address, this); + if (!this.identity.body.deviceId) + throw new Error('missing deviceId'); - await this._receiveIdent(this._connection); this._connection = await this._encryptClient(connection); } catch (e) { this.close(); @@ -830,7 +740,11 @@ var Channel = GObject.registerClass({ this._connection = connection; this.backend.channels.set(this.address, this); - await this._sendIdent(this._connection); + await connection.get_output_stream().write_all_async( + this.backend.identity.serialize(), + GLib.PRIORITY_DEFAULT, + this.cancellable); + this._connection = await this._encryptServer(connection); } catch (e) { this.close(); @@ -863,28 +777,19 @@ var Channel = GObject.registerClass({ } async download(packet, target, cancellable = null) { - const openConnection = new Promise((resolve, reject) => { - const client = new Gio.SocketClient({enable_proxy: false}); + const address = Gio.InetSocketAddress.new_from_string(this.host, + packet.payloadTransferInfo.port); - const address = Gio.InetSocketAddress.new_from_string( - this.host, - packet.payloadTransferInfo.port - ); - - client.connect_async(address, cancellable, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - reject(e); - } - }); - }).then(this._encryptClient.bind(this)); - - const connection = await openConnection; - const source = connection.get_input_stream(); + const client = new Gio.SocketClient({enable_proxy: false}); + const connection = await client.connect_async(address, cancellable) + .then(this._encryptClient.bind(this)); // Start the transfer - const transferredSize = await this._transfer(source, target, cancellable); + const transferredSize = await target.splice_async( + connection.input_stream, + (Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | + Gio.OutputStreamSpliceFlags.CLOSE_TARGET), + GLib.PRIORITY_DEFAULT, cancellable); // If we get less than expected, we've certainly got corruption if (transferredSize < packet.payloadSize) { @@ -923,32 +828,26 @@ var Channel = GObject.registerClass({ } // Listen for the incoming connection - const acceptConnection = new Promise((resolve, reject) => { - listener.accept_async( - cancellable, - (listener, res, source_object) => { - try { - resolve(listener.accept_finish(res)[0]); - } catch (e) { - reject(e); - } - } - ); - }).then(this._encryptServer.bind(this)); + const acceptConnection = listener.accept_async(cancellable) + .then(result => this._encryptServer(result[0])); // Create an upload request packet.body.payloadHash = this.checksum; packet.payloadSize = size; packet.payloadTransferInfo = {port: port}; - const requestUpload = this.sendPacket(new Core.Packet(packet)); + const requestUpload = this.sendPacket(new Core.Packet(packet), + cancellable); // Request an upload stream, accept the connection and get the output const [, connection] = await Promise.all([requestUpload, acceptConnection]); - const target = connection.get_output_stream(); // Start the transfer - const transferredSize = await this._transfer(source, target, cancellable); + const transferredSize = await connection.output_stream.splice_async( + source, + (Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | + Gio.OutputStreamSpliceFlags.CLOSE_TARGET), + GLib.PRIORITY_DEFAULT, cancellable); if (transferredSize !== size) { throw new Gio.IOErrorEnum({ @@ -958,25 +857,6 @@ var Channel = GObject.registerClass({ } } - _transfer(source, target, cancellable) { - return new Promise((resolve, reject) => { - target.splice_async( - source, - (Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | - Gio.OutputStreamSpliceFlags.CLOSE_TARGET), - GLib.PRIORITY_DEFAULT, - cancellable, - (target, res) => { - try { - resolve(target.splice_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - async rejectTransfer(packet) { try { if (!packet || !packet.hasPayload()) @@ -985,24 +865,13 @@ var Channel = GObject.registerClass({ if (packet.payloadTransferInfo.port === undefined) return; - let connection = await new Promise((resolve, reject) => { - const client = new Gio.SocketClient({enable_proxy: false}); + const address = Gio.InetSocketAddress.new_from_string(this.host, + packet.payloadTransferInfo.port); - const address = Gio.InetSocketAddress.new_from_string( - this.host, - packet.payloadTransferInfo.port - ); - - client.connect_async(address, null, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - resolve(); - } - }); - }); + const client = new Gio.SocketClient({enable_proxy: false}); + const connection = await client.connect_async(address, null) + .then(this._encryptClient.bind(this)); - connection = await this._encryptClient(connection); connection.close_async(GLib.PRIORITY_DEFAULT, null, null); } catch (e) { debug(e, this.device.name); diff --git a/src/service/components/clipboard.js b/src/service/components/clipboard.js index 439a9fcc4..d51b9f74f 100644 --- a/src/service/components/clipboard.js +++ b/src/service/components/clipboard.js @@ -64,8 +64,11 @@ var Clipboard = GObject.registerClass({ if (this._clipboard instanceof Gtk.Clipboard) this._clipboard.set_text(content, -1); - if (this._clipboard instanceof Gio.DBusProxy) - this._proxySetText(content); + if (this._clipboard instanceof Gio.DBusProxy) { + this._clipboard.call('SetText', new GLib.Variant('(s)', [content]), + Gio.DBusCallFlags.NO_AUTO_START, -1, this._cancellable) + .catch(debug); + } } async _onNameAppeared(connection, name, name_owner) { @@ -85,24 +88,11 @@ var Clipboard = GObject.registerClass({ g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES, }); - await new Promise((resolve, reject) => { - this._clipboard.init_async( - GLib.PRIORITY_DEFAULT, - this._cancellable, - (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + await this._clipboard.init_async(GLib.PRIORITY_DEFAULT, + this._cancellable); - this._ownerChangeId = this._clipboard.connect( - 'g-signal', - this._onOwnerChange.bind(this) - ); + this._ownerChangeId = this._clipboard.connect('g-signal', + this._onOwnerChange.bind(this)); this._onOwnerChange(); if (!globalThis.HAVE_GNOME) { @@ -135,10 +125,8 @@ var Clipboard = GObject.registerClass({ const display = Gdk.Display.get_default(); this._clipboard = Gtk.Clipboard.get_default(display); - this._ownerChangeId = this._clipboard.connect( - 'owner-change', - this._onOwnerChange.bind(this) - ); + this._ownerChangeId = this._clipboard.connect('owner-change', + this._onOwnerChange.bind(this)); this._onOwnerChange(); } @@ -167,68 +155,10 @@ var Clipboard = GObject.registerClass({ /* * Proxy Clipboard */ - _proxyGetMimetypes() { - return new Promise((resolve, reject) => { - this._clipboard.call( - 'GetMimetypes', - null, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - this._cancellable, - (proxy, res) => { - try { - const reply = proxy.call_finish(res); - resolve(reply.deepUnpack()[0]); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - } - - _proxyGetText() { - return new Promise((resolve, reject) => { - this._clipboard.call( - 'GetText', - null, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - this._cancellable, - (proxy, res) => { - try { - const reply = proxy.call_finish(res); - resolve(reply.deepUnpack()[0]); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - } - - _proxySetText(text) { - this._clipboard.call( - 'SetText', - new GLib.Variant('(s)', [text]), - Gio.DBusCallFlags.NO_AUTO_START, - -1, - this._cancellable, - (proxy, res) => { - try { - proxy.call_finish(res); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - debug(e); - } - } - ); - } - async _proxyUpdateText() { - const mimetypes = await this._proxyGetMimetypes(); + let reply = await this._clipboard.call('GetMimetypes', null, + Gio.DBusCallFlags.NO_AUTO_START, -1, this._cancellable); + const mimetypes = reply.deepUnpack()[0]; // Special case for a cleared clipboard if (mimetypes.length === 0) @@ -238,7 +168,9 @@ var Clipboard = GObject.registerClass({ if (mimetypes.includes('text/uri-list')) return; - const text = await this._proxyGetText(); + reply = await this._clipboard.call('GetText', null, + Gio.DBusCallFlags.NO_AUTO_START, -1, this._cancellable); + const text = reply.deepUnpack()[0]; this._applyUpdate(text); } @@ -246,20 +178,10 @@ var Clipboard = GObject.registerClass({ /* * GtkClipboard */ - _gtkGetMimetypes() { - return new Promise((resolve, reject) => { + async _gtkUpdateText() { + const mimetypes = await new Promise((resolve, reject) => { this._clipboard.request_targets((clipboard, atoms) => resolve(atoms)); }); - } - - _gtkGetText() { - return new Promise((resolve, reject) => { - this._clipboard.request_text((clipboard, text) => resolve(text)); - }); - } - - async _gtkUpdateText() { - const mimetypes = await this._gtkGetMimetypes(); // Special case for a cleared clipboard if (mimetypes.length === 0) @@ -269,7 +191,9 @@ var Clipboard = GObject.registerClass({ if (mimetypes.includes('text/uri-list')) return; - const text = await this._gtkGetText(); + const text = await new Promise((resolve, reject) => { + this._clipboard.request_text((clipboard, text) => resolve(text)); + }); this._applyUpdate(text); } @@ -292,7 +216,6 @@ var Clipboard = GObject.registerClass({ if (!globalThis.HAVE_GNOME && this.signalHandler) Gio.DBus.session.signal_unsubscribe(this.signalHandler); - } }); diff --git a/src/service/components/contacts.js b/src/service/components/contacts.js index 252ffaaf1..7b948ad6a 100644 --- a/src/service/components/contacts.js +++ b/src/service/components/contacts.js @@ -124,58 +124,6 @@ var Store = GObject.registerClass({ } } - /* - * EDS Helpers - */ - _getEBookClient(source, cancellable = null) { - return new Promise((resolve, reject) => { - EBook.BookClient.connect(source, 0, cancellable, (source, res) => { - try { - resolve(EBook.BookClient.connect_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - } - - _getEBookView(client, query = '', cancellable = null) { - return new Promise((resolve, reject) => { - client.get_view(query, cancellable, (client, res) => { - try { - resolve(client.get_view_finish(res)[1]); - } catch (e) { - reject(e); - } - }); - }); - } - - _getEContacts(client, query = '', cancellable = null) { - return new Promise((resolve, reject) => { - client.get_contacts(query, cancellable, (client, res) => { - try { - resolve(client.get_contacts_finish(res)[1]); - } catch (e) { - debug(e); - resolve([]); - } - }); - }); - } - - _getESourceRegistry(cancellable = null) { - return new Promise((resolve, reject) => { - EDataServer.SourceRegistry.new(cancellable, (registry, res) => { - try { - resolve(EDataServer.SourceRegistry.new_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - } - /* * AddressBook DBus callbacks */ @@ -240,8 +188,8 @@ var Store = GObject.registerClass({ try { // Get an EBookClient and EBookView const uid = source.get_uid(); - const client = await this._getEBookClient(source); - const view = await this._getEBookView(client, 'exists "tel"'); + const client = await EBook.BookClient.connect(source, null); + const [view] = await client.get_view('exists "tel"', null); // Watch the view for changes to the address book const connection = view.get_connection(); @@ -387,35 +335,23 @@ var Store = GObject.registerClass({ * @param {ByteArray} contents - An image ByteArray * @return {string|undefined} File path or %undefined on failure */ - storeAvatar(contents) { - return new Promise((resolve, reject) => { - const md5 = GLib.compute_checksum_for_data( - GLib.ChecksumType.MD5, - contents - ); - const file = this._cacheDir.get_child(`${md5}`); - - if (file.query_exists(null)) { - resolve(file.get_path()); - } else { - file.replace_contents_bytes_async( + async storeAvatar(contents) { + const md5 = GLib.compute_checksum_for_data(GLib.ChecksumType.MD5, + contents); + const file = this._cacheDir.get_child(`${md5}`); + + if (!file.query_exists(null)) { + try { + await file.replace_contents_bytes_async( new GLib.Bytes(contents), - null, - false, - Gio.FileCreateFlags.REPLACE_DESTINATION, - null, - (file, res) => { - try { - file.replace_contents_finish(res); - resolve(file.get_path()); - } catch (e) { - debug(e, 'Storing avatar'); - resolve(undefined); - } - } - ); + null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); + } catch (e) { + debug(e, 'Storing avatar'); + return undefined; } - }); + } + + return file.get_path(); } /** @@ -623,17 +559,8 @@ var Store = GObject.registerClass({ */ async load() { try { - this._cacheData = await new Promise((resolve, reject) => { - this._cacheFile.load_contents_async(null, (file, res) => { - try { - const contents = file.load_contents_finish(res)[1]; - - resolve(JSON.parse(ByteArray.toString(contents))); - } catch (e) { - reject(e); - } - }); - }); + const [contents] = await this._cacheFile.load_contents_async(null); + this._cacheData = JSON.parse(ByteArray.toString(contents)); } catch (e) { debug(e); } finally { @@ -657,22 +584,9 @@ var Store = GObject.registerClass({ try { this.__cache_lock = true; - await new Promise((resolve, reject) => { - this._cacheFile.replace_contents_bytes_async( - new GLib.Bytes(JSON.stringify(this._cacheData, null, 2)), - null, - false, - Gio.FileCreateFlags.REPLACE_DESTINATION, - null, - (file, res) => { - try { - resolve(file.replace_contents_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + const contents = new GLib.Bytes(JSON.stringify(this._cacheData, null, 2)); + await this._cacheFile.replace_contents_bytes_async(contents, null, + false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); } catch (e) { debug(e); } finally { diff --git a/src/service/components/input.js b/src/service/components/input.js index 5dc22564c..795224ef1 100644 --- a/src/service/components/input.js +++ b/src/service/components/input.js @@ -44,6 +44,7 @@ const RemoteSession = GObject.registerClass({ if (!this._started) return; + // Pass a null callback to allow this call to finish itself this.call(name, parameters, Gio.DBusCallFlags.NONE, -1, null, null); } @@ -60,39 +61,9 @@ const RemoteSession = GObject.registerClass({ if (this._started) return; - // Initialize the proxy - await new Promise((resolve, reject) => { - this.init_async( - GLib.PRIORITY_DEFAULT, - null, - (proxy, res) => { - try { - proxy.init_finish(res); - resolve(); - } catch (e) { - reject(e); - } - } - ); - }); - - // Start the session - await new Promise((resolve, reject) => { - this.call( - 'Start', - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (proxy, res) => { - try { - resolve(proxy.call_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + // Initialize the proxy, and start the session + await this.init_async(GLib.PRIORITY_DEFAULT, null); + await this.call('Start', null, Gio.DBusCallFlags.NONE, -1, null); this._started = true; } catch (e) { @@ -106,6 +77,8 @@ const RemoteSession = GObject.registerClass({ stop() { if (this._started) { this._started = false; + + // Pass a null callback to allow this call to finish itself this.call('Stop', null, Gio.DBusCallFlags.NONE, -1, null, null); } } @@ -390,63 +363,45 @@ class Controller { return GLib.SOURCE_REMOVE; } - _createRemoteDesktopSession() { + async _createRemoteDesktopSession() { if (this.connection === null) return Promise.reject(new Error('No DBus connection')); - return new Promise((resolve, reject) => { - this.connection.call( - 'org.gnome.Mutter.RemoteDesktop', - '/org/gnome/Mutter/RemoteDesktop', - 'org.gnome.Mutter.RemoteDesktop', - 'CreateSession', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); + const reply = await this.connection.call( + 'org.gnome.Mutter.RemoteDesktop', + '/org/gnome/Mutter/RemoteDesktop', + 'org.gnome.Mutter.RemoteDesktop', + 'CreateSession', + null, + null, + Gio.DBusCallFlags.NONE, + -1, + null); + + return reply.deepUnpack()[0]; } - _createScreenCastSession(sessionId) { + async _createScreenCastSession(sessionId) { if (this.connection === null) - return Promise.reject(new Error('No DBus connection')); - - return new Promise((resolve, reject) => { - const options = new GLib.Variant('(a{sv})', [{ - 'disable-animations': GLib.Variant.new_boolean(false), - 'remote-desktop-session-id': GLib.Variant.new_string(sessionId), - }]); - - this.connection.call( - 'org.gnome.Mutter.ScreenCast', - '/org/gnome/Mutter/ScreenCast', - 'org.gnome.Mutter.ScreenCast', - 'CreateSession', - options, - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); + throw new Error('No DBus connection'); + + const options = new GLib.Variant('(a{sv})', [{ + 'disable-animations': GLib.Variant.new_boolean(false), + 'remote-desktop-session-id': GLib.Variant.new_string(sessionId), + }]); + + const reply = await this.connection.call( + 'org.gnome.Mutter.ScreenCast', + '/org/gnome/Mutter/ScreenCast', + 'org.gnome.Mutter.ScreenCast', + 'CreateSession', + options, + null, + Gio.DBusCallFlags.NONE, + -1, + null); + + return reply.deepUnpack()[0]; } async _ensureAdapter() { diff --git a/src/service/components/mpris.js b/src/service/components/mpris.js index 52f35d7f6..df9adafae 100644 --- a/src/service/components/mpris.js +++ b/src/service/components/mpris.js @@ -583,30 +583,6 @@ const PlayerProxy = GObject.registerClass({ } } - initPromise() { - const application = new Promise((resolve, reject) => { - this._application.init_async(0, this._cancellable, (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - const player = new Promise((resolve, reject) => { - this._player.init_async(0, this._cancellable, (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - return Promise.all([application, player]); - } - /* * The org.mpris.MediaPlayer2 Interface */ @@ -856,27 +832,18 @@ var Manager = GObject.registerClass({ async _loadPlayers() { try { - const names = await new Promise((resolve, reject) => { - this._connection.call( - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus', - 'ListNames', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - this._cancellable, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); + const reply = await this._connection.call( + 'org.freedesktop.DBus', + '/org/freedesktop/DBus', + 'org.freedesktop.DBus', + 'ListNames', + null, + null, + Gio.DBusCallFlags.NONE, + -1, + this._cancellable); + + const names = reply.deepUnpack()[0]; for (let i = 0, len = names.length; i < len; i++) { const name = names[i]; @@ -909,7 +876,12 @@ var Manager = GObject.registerClass({ try { if (!this._players.has(name)) { const player = new PlayerProxy(name); - await player.initPromise(); + await Promise.all([ + player._application.init_async(GLib.PRIORITY_DEFAULT, + this._cancellable), + player._player.init_async(GLib.PRIORITY_DEFAULT, + this._cancellable), + ]); player.connect('notify', (player) => this.emit('player-changed', player)); diff --git a/src/service/components/notification.js b/src/service/components/notification.js index cc47474c8..17b31d6d3 100644 --- a/src/service/components/notification.js +++ b/src/service/components/notification.js @@ -111,52 +111,34 @@ const Listener = GObject.registerClass({ } } - _listNames() { - return new Promise((resolve, reject) => { - this._session.call( - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus', - 'ListNames', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); + async _listNames() { + const reply = await this._session.call( + 'org.freedesktop.DBus', + '/org/freedesktop/DBus', + 'org.freedesktop.DBus', + 'ListNames', + null, + null, + Gio.DBusCallFlags.NONE, + -1, + null); + + return reply.deepUnpack()[0]; } - _getNameOwner(name) { - return new Promise((resolve, reject) => { - this._session.call( - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus', - 'GetNameOwner', - new GLib.Variant('(s)', [name]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); + async _getNameOwner(name) { + const reply = await this._session.call( + 'org.freedesktop.DBus', + '/org/freedesktop/DBus', + 'org.freedesktop.DBus', + 'GetNameOwner', + new GLib.Variant('(s)', [name]), + null, + Gio.DBusCallFlags.NONE, + -1, + null); + + return reply.deepUnpack()[0]; } /** @@ -284,68 +266,49 @@ const Listener = GObject.registerClass({ * @return {Promise} A promise for the operation */ _monitorConnection() { - return new Promise((resolve, reject) => { - // libnotify Interface - this._fdoNotifications = new GjsPrivate.DBusImplementation({ - g_interface_info: FDO_IFACE, - }); - this._fdoMethodCallId = this._fdoNotifications.connect( - 'handle-method-call', - this._onHandleMethodCall.bind(this) - ); - this._fdoNotifications.export( - this._monitor, - '/org/freedesktop/Notifications' - ); - - this._fdoNameOwnerChangedId = this._session.signal_subscribe( - 'org.freedesktop.DBus', - 'org.freedesktop.DBus', - 'NameOwnerChanged', - '/org/freedesktop/DBus', - 'org.freedesktop.Notifications', - Gio.DBusSignalFlags.MATCH_ARG0_NAMESPACE, - this._onFdoNameOwnerChanged.bind(this) - ); - - // GNotification Interface - this._gtkNotifications = new GjsPrivate.DBusImplementation({ - g_interface_info: GTK_IFACE, - }); - this._gtkMethodCallId = this._gtkNotifications.connect( - 'handle-method-call', - this._onHandleMethodCall.bind(this) - ); - this._gtkNotifications.export( - this._monitor, - '/org/gtk/Notifications' - ); + // libnotify Interface + this._fdoNotifications = new GjsPrivate.DBusImplementation({ + g_interface_info: FDO_IFACE, + }); + this._fdoMethodCallId = this._fdoNotifications.connect( + 'handle-method-call', this._onHandleMethodCall.bind(this)); + this._fdoNotifications.export(this._monitor, + '/org/freedesktop/Notifications'); + + this._fdoNameOwnerChangedId = this._session.signal_subscribe( + 'org.freedesktop.DBus', + 'org.freedesktop.DBus', + 'NameOwnerChanged', + '/org/freedesktop/DBus', + 'org.freedesktop.Notifications', + Gio.DBusSignalFlags.MATCH_ARG0_NAMESPACE, + this._onFdoNameOwnerChanged.bind(this) + ); - // Become a monitor for Fdo & Gtk notifications - this._monitor.call( - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus.Monitoring', - 'BecomeMonitor', - new GLib.Variant('(asu)', [[FDO_MATCH, GTK_MATCH], 0]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - resolve(connection.call_finish(res)); - } catch (e) { - reject(e); - } - } - ); + // GNotification Interface + this._gtkNotifications = new GjsPrivate.DBusImplementation({ + g_interface_info: GTK_IFACE, }); + this._gtkMethodCallId = this._gtkNotifications.connect( + 'handle-method-call', this._onHandleMethodCall.bind(this)); + this._gtkNotifications.export(this._monitor, '/org/gtk/Notifications'); + + // Become a monitor for Fdo & Gtk notifications + return this._monitor.call( + 'org.freedesktop.DBus', + '/org/freedesktop/DBus', + 'org.freedesktop.DBus.Monitoring', + 'BecomeMonitor', + new GLib.Variant('(asu)', [[FDO_MATCH, GTK_MATCH], 0]), + null, + Gio.DBusCallFlags.NONE, + -1, + null); } async _init_async() { try { - this._session = await DBus.getConnection(); + this._session = Gio.DBus.session; this._monitor = await DBus.newConnection(); await this._monitorConnection(); } catch (e) { diff --git a/src/service/components/session.js b/src/service/components/session.js index 5f2edcf85..512ace2f5 100644 --- a/src/service/components/session.js +++ b/src/service/components/session.js @@ -18,8 +18,19 @@ const Session = class { async _initAsync() { try { + const reply = await this._connection.call( + 'org.freedesktop.login1', + '/org/freedesktop/login1', + 'org.freedesktop.login1.Manager', + 'ListSessions', + null, + null, + Gio.DBusCallFlags.NONE, + -1, + null); + + const sessions = reply.deepUnpack()[0]; const userName = GLib.get_user_name(); - const sessions = await this._listSessions(); let sessionPath = '/org/freedesktop/login1/session/auto'; // eslint-disable-next-line no-unused-vars @@ -30,7 +41,13 @@ const Session = class { } } - this._session = await this._getSession(sessionPath); + this._session = new Gio.DBusProxy({ + g_connection: this._connection, + g_name: 'org.freedesktop.login1', + g_object_path: sessionPath, + g_interface_name: 'org.freedesktop.login1.Session', + }); + await this._session.init_async(GLib.PRIORITY_DEFAULT, null); } catch (e) { this._session = null; logError(e); @@ -56,57 +73,6 @@ const Session = class { return !(this.idle || this.locked); } - _listSessions() { - return new Promise((resolve, reject) => { - this._connection.call( - 'org.freedesktop.login1', - '/org/freedesktop/login1', - 'org.freedesktop.login1.Manager', - 'ListSessions', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - } - - async _getSession(objectPath) { - const session = new Gio.DBusProxy({ - g_connection: this._connection, - g_name: 'org.freedesktop.login1', - g_object_path: objectPath, - g_interface_name: 'org.freedesktop.login1.Session', - }); - - // Initialize the proxy - await new Promise((resolve, reject) => { - session.init_async( - GLib.PRIORITY_DEFAULT, - null, - (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - - return session; - } - destroy() { this._session = null; } diff --git a/src/service/components/sound.js b/src/service/components/sound.js index f79cee2b3..4634d50bd 100644 --- a/src/service/components/sound.js +++ b/src/service/components/sound.js @@ -50,17 +50,8 @@ var Player = class Player { } _canberraPlaySound(name, cancellable) { - return new Promise((resolve, reject) => { - const proc = this._canberra.spawnv(['canberra-gtk-play', '-i', name]); - - proc.wait_check_async(cancellable, (proc, res) => { - try { - resolve(proc.wait_check_finish(res)); - } catch (e) { - reject(e); - } - }); - }); + const proc = this._canberra.spawnv(['canberra-gtk-play', '-i', name]); + return proc.wait_check_async(cancellable); } async _canberraLoopSound(name, cancellable) { diff --git a/src/service/components/upower.js b/src/service/components/upower.js index 700b4fff5..f090a92b0 100644 --- a/src/service/components/upower.js +++ b/src/service/components/upower.js @@ -103,24 +103,11 @@ var Battery = GObject.registerClass({ g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START, }); - await new Promise((resolve, reject) => { - this._proxy.init_async( - GLib.PRIORITY_DEFAULT, - this._cancellable, - (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + await this._proxy.init_async(GLib.PRIORITY_DEFAULT, + this._cancellable); this._propertiesChangedId = this._proxy.connect( - 'g-properties-changed', - this._onPropertiesChanged.bind(this) - ); + 'g-properties-changed', this._onPropertiesChanged.bind(this)); this._initProperties(this._proxy); } catch (e) { diff --git a/src/service/core.js b/src/service/core.js index 22cca1cc4..ba592d506 100644 --- a/src/service/core.js +++ b/src/service/core.js @@ -218,7 +218,7 @@ var Channel = GObject.registerClass({ * @param {Gio.Cancellable} [cancellable] - A cancellable * @return {Promise} The packet */ - readPacket(cancellable = null) { + async readPacket(cancellable = null) { if (cancellable === null) cancellable = this.cancellable; @@ -228,28 +228,17 @@ var Channel = GObject.registerClass({ }); } - return new Promise((resolve, reject) => { - this.input_stream.read_line_async( - GLib.PRIORITY_DEFAULT, - cancellable, - (stream, res) => { - try { - const data = stream.read_line_finish_utf8(res)[0]; - - if (data === null) { - throw new Gio.IOErrorEnum({ - message: 'End of stream', - code: Gio.IOErrorEnum.CONNECTION_CLOSED, - }); - } - - resolve(new Packet(data)); - } catch (e) { - reject(e); - } - } - ); - }); + const [data] = await this.input_stream.read_line_async( + GLib.PRIORITY_DEFAULT, cancellable); + + if (data === null) { + throw new Gio.IOErrorEnum({ + message: 'End of stream', + code: Gio.IOErrorEnum.CONNECTION_CLOSED, + }); + } + + return new Packet(data); } /** @@ -263,20 +252,8 @@ var Channel = GObject.registerClass({ if (cancellable === null) cancellable = this.cancellable; - return new Promise((resolve, reject) => { - this.output_stream.write_all_async( - packet.serialize(), - GLib.PRIORITY_DEFAULT, - cancellable, - (stream, res) => { - try { - resolve(stream.write_all_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + return this.output_stream.write_all_async(packet.serialize(), + GLib.PRIORITY_DEFAULT, cancellable); } /** @@ -361,6 +338,13 @@ var ChannelService = GObject.registerClass({ return this._active; } + get cancellable() { + if (this._cancellable === undefined) + this._cancellable = new Gio.Cancellable(); + + return this._cancellable; + } + get name() { if (this._name === undefined) this._name = GLib.get_host_name(); @@ -569,57 +553,26 @@ var Transfer = GObject.registerClass({ return; if (item.file instanceof Gio.File) { - item.target = await new Promise((resolve, reject) => { - item.file.replace_async( - null, - false, - Gio.FileCreateFlags.REPLACE_DESTINATION, - GLib.PRIORITY_DEFAULT, - this._cancellable, - (file, res) => { - try { - resolve(file.replace_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + item.target = await item.file.replace_async( + null, + false, + Gio.FileCreateFlags.REPLACE_DESTINATION, + GLib.PRIORITY_DEFAULT, + this._cancellable); } } else { if (item.source instanceof Gio.InputStream) return; if (item.file instanceof Gio.File) { - const read = new Promise((resolve, reject) => { - item.file.read_async( - GLib.PRIORITY_DEFAULT, - cancellable, - (file, res) => { - try { - resolve(file.read_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - const query = new Promise((resolve, reject) => { - item.file.query_info_async( - Gio.FILE_ATTRIBUTE_STANDARD_SIZE, - Gio.FileQueryInfoFlags.NONE, - GLib.PRIORITY_DEFAULT, - cancellable, - (file, res) => { - try { - resolve(file.query_info_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + const read = item.file.read_async(GLib.PRIORITY_DEFAULT, + cancellable); + + const query = item.file.query_info_async( + Gio.FILE_ATTRIBUTE_STANDARD_SIZE, + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_DEFAULT, + cancellable); const [stream, info] = await Promise.all([read, query]); item.source = stream; diff --git a/src/service/plugin.js b/src/service/plugin.js index 6e17c87c8..28ffab287 100644 --- a/src/service/plugin.js +++ b/src/service/plugin.js @@ -185,23 +185,13 @@ var Plugin = GObject.registerClass({ GLib.mkdir_with_parents(cachedir, 448); this._cacheFile = Gio.File.new_for_path( - GLib.build_filenamev([cachedir, `${this.name}.json`]) - ); + GLib.build_filenamev([cachedir, `${this.name}.json`])); // Read the cache from disk - await new Promise((resolve, reject) => { - this._cacheFile.load_contents_async(null, (file, res) => { - try { - const contents = file.load_contents_finish(res)[1]; - const cache = JSON.parse(ByteArray.toString(contents)); - Object.assign(this, cache); - - resolve(); - } catch (e) { - reject(e); - } - }); - }); + const [contents] = await this._cacheFile.load_contents_async( + this.cancellable); + const cache = JSON.parse(ByteArray.toString(contents)); + Object.assign(this, cache); } catch (e) { debug(e.message, `${this.device.name}: ${this.name}`); } finally { diff --git a/src/service/plugins/notification.js b/src/service/plugins/notification.js index 232c71a3f..369761523 100644 --- a/src/service/plugins/notification.js +++ b/src/service/plugins/notification.js @@ -357,32 +357,9 @@ var Plugin = GObject.registerClass({ * @param {Gio.File} file - A file object for the icon */ async _uploadFileIcon(packet, file) { - const read = new Promise((resolve, reject) => { - file.read_async(GLib.PRIORITY_DEFAULT, null, (file, res) => { - try { - resolve(file.read_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - const query = new Promise((resolve, reject) => { - file.query_info_async( - 'standard::size', - Gio.FileQueryInfoFlags.NONE, - GLib.PRIORITY_DEFAULT, - null, - (file, res) => { - try { - resolve(file.query_info_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - + const read = file.read_async(GLib.PRIORITY_DEFAULT, null); + const query = file.query_info_async('standard::size', + Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_DEFAULT, null); const [stream, info] = await Promise.all([read, query]); this._uploadIconStream(packet, stream, info.get_size()); diff --git a/src/service/plugins/photo.js b/src/service/plugins/photo.js index dc604a567..0f0cd2d22 100644 --- a/src/service/plugins/photo.js +++ b/src/service/plugins/photo.js @@ -161,27 +161,18 @@ var Plugin = GObject.registerClass({ * @return {Promise} A file path */ _takePhoto(packet) { - return new Promise((resolve, reject) => { - const time = GLib.DateTime.new_now_local().format('%T'); - const path = GLib.build_filenamev([GLib.get_tmp_dir(), `${time}.jpg`]); - const proc = this._launcher.spawnv([ - Config.FFMPEG_PATH, - '-f', 'video4linux2', - '-ss', '0:0:2', - '-i', '/dev/video0', - '-frames', '1', - path, - ]); - - proc.wait_check_async(null, (proc, res) => { - try { - proc.wait_check_finish(res); - resolve(path); - } catch (e) { - reject(e); - } - }); - }); + const time = GLib.DateTime.new_now_local().format('%T'); + const path = GLib.build_filenamev([GLib.get_tmp_dir(), `${time}.jpg`]); + const proc = this._launcher.spawnv([ + Config.FFMPEG_PATH, + '-f', 'video4linux2', + '-ss', '0:0:2', + '-i', '/dev/video0', + '-frames', '1', + path, + ]); + + return proc.wait_check_async(null); } /** diff --git a/src/service/plugins/sftp.js b/src/service/plugins/sftp.js index f7b8b2a11..100749c0a 100644 --- a/src/service/plugins/sftp.js +++ b/src/service/plugins/sftp.js @@ -154,37 +154,14 @@ var Plugin = GObject.registerClass({ async _listDirectories(mount) { const file = mount.get_root(); - const iter = await new Promise((resolve, reject) => { - file.enumerate_children_async( - Gio.FILE_ATTRIBUTE_STANDARD_NAME, - Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, - GLib.PRIORITY_DEFAULT, - this.cancellable, - (file, res) => { - try { - resolve(file.enumerate_children_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - const infos = await new Promise((resolve, reject) => { - iter.next_files_async( - MAX_MOUNT_DIRS, - GLib.PRIORITY_DEFAULT, - this.cancellable, - (iter, res) => { - try { - resolve(iter.next_files_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - + const iter = await file.enumerate_children_async( + Gio.FILE_ATTRIBUTE_STANDARD_NAME, + Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, + GLib.PRIORITY_DEFAULT, + this.cancellable); + + const infos = await iter.next_files_async(MAX_MOUNT_DIRS, + GLib.PRIORITY_DEFAULT, this.cancellable); iter.close_async(GLib.PRIORITY_DEFAULT, null, null); const directories = {}; @@ -251,26 +228,17 @@ var Plugin = GObject.registerClass({ const uri = `sftp://${host}:${packet.body.port}/`; const file = Gio.File.new_for_uri(uri); - await new Promise((resolve, reject) => { - file.mount_enclosing_volume(0, op, null, (file, res) => { - try { - resolve(file.mount_enclosing_volume_finish(res)); - } catch (e) { - // Special case when the GMount didn't unmount properly - // but is still on the same port and can be reused. - if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.ALREADY_MOUNTED)) { - resolve(true); - - // There's a good chance this is a host key verification - // error; regardless we'll remove the key for security. - } else { - this._removeHostKey(host); - reject(e); - } - } - }); - }); + await file.mount_enclosing_volume(GLib.PRIORITY_DEFAULT, op, + this.cancellable); } catch (e) { + // Special case when the GMount didn't unmount properly but is still + // on the same port and can be reused. + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.ALREADY_MOUNTED)) + return; + + // There's a good chance this is a host key verification error; + // regardless we'll remove the key for security. + this._removeHostKey(this.device.channel.host); logError(e, this.device.name); } finally { this._mounting = false; @@ -283,26 +251,17 @@ var Plugin = GObject.registerClass({ * * @return {Promise} A promise for the operation */ - _addPrivateKey() { + async _addPrivateKey() { const ssh_add = this._launcher.spawnv([ Config.SSHADD_PATH, GLib.build_filenamev([Config.CONFIGDIR, 'private.pem']), ]); - return new Promise((resolve, reject) => { - ssh_add.communicate_utf8_async(null, null, (proc, res) => { - try { - const result = proc.communicate_utf8_finish(res)[1].trim(); + const [stdout] = await ssh_add.communicate_utf8_async(null, + this.cancellable); - if (proc.get_exit_status() !== 0) - debug(result, this.device.name); - - resolve(); - } catch (e) { - reject(e); - } - }); - }); + if (ssh_add.get_exit_status() !== 0) + debug(stdout.trim(), this.device.name); } /** @@ -320,25 +279,17 @@ var Plugin = GObject.registerClass({ `[${host}]:${port}`, ]); - await new Promise((resolve, reject) => { - ssh_keygen.communicate_utf8_async(null, null, (proc, res) => { - try { - const stdout = proc.communicate_utf8_finish(res)[1]; - const status = proc.get_exit_status(); - - if (status !== 0) { - throw new Gio.IOErrorEnum({ - code: Gio.io_error_from_errno(status), - message: `${GLib.strerror(status)}\n${stdout}`.trim(), - }); - } - - resolve(); - } catch (e) { - reject(e); - } + const [stdout] = await ssh_keygen.communicate_utf8_async(null, + this.cancellable); + + const status = ssh_keygen.get_exit_status(); + + if (status !== 0) { + throw new Gio.IOErrorEnum({ + code: Gio.io_error_from_errno(status), + message: `${GLib.strerror(status)}\n${stdout}`.trim(), }); - }); + } } catch (e) { logError(e, this.device.name); } @@ -464,49 +415,27 @@ var Plugin = GObject.registerClass({ const link_target = mount.get_root().get_path(); const link = Gio.File.new_for_path( - `${by_name_dir.get_path()}/${safe_device_name}` - ); + `${by_name_dir.get_path()}/${safe_device_name}`); // Check for and remove any existing stale link try { - const link_stat = await new Promise((resolve, reject) => { - link.query_info_async( - 'standard::symlink-target', - Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, - GLib.PRIORITY_DEFAULT, - null, - (link, res) => { - try { - resolve(link.query_info_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + const link_stat = await link.query_info_async( + 'standard::symlink-target', + Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, + GLib.PRIORITY_DEFAULT, + this.cancellable); if (link_stat.get_symlink_target() === link_target) return; - await new Promise((resolve, reject) => { - link.delete_async( - GLib.PRIORITY_DEFAULT, - null, - (link, res) => { - try { - resolve(link.delete_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + await link.delete_async(GLib.PRIORITY_DEFAULT, + this.cancellable); } catch (e) { if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) throw e; } - link.make_symbolic_link(link_target, null); + link.make_symbolic_link(link_target, this.cancellable); } catch (e) { debug(e, this.device.name); } @@ -538,20 +467,10 @@ var Plugin = GObject.registerClass({ this._removeSubmenu(); this._mounting = false; - await new Promise((resolve, reject) => { - this.gmount.unmount_with_operation( - Gio.MountUnmountFlags.FORCE, - new Gio.MountOperation(), - null, - (mount, res) => { - try { - resolve(mount.unmount_with_operation_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); + await this.gmount.unmount_with_operation( + Gio.MountUnmountFlags.FORCE, + new Gio.MountOperation(), + this.cancellable); } catch (e) { debug(e, this.device.name); } diff --git a/src/service/utils/dbus.js b/src/service/utils/dbus.js index 631f8381b..954f7cec9 100644 --- a/src/service/utils/dbus.js +++ b/src/service/utils/dbus.js @@ -234,26 +234,6 @@ var Interface = GObject.registerClass({ } }); - -/** - * Get the DBus connection on @busType - * - * @param {Gio.BusType} [busType] - a Gio.BusType constant - * @param {Gio.Cancellable} [cancellable] - an optional Gio.Cancellable - * @return {Promise} A DBus connection - */ -function getConnection(busType = Gio.BusType.SESSION, cancellable = null) { - return new Promise((resolve, reject) => { - Gio.bus_get(busType, cancellable, (connection, res) => { - try { - resolve(Gio.bus_get_finish(res)); - } catch (e) { - reject(e); - } - }); - }); -} - /** * Get a new, dedicated DBus connection on @busType *