diff --git a/src/app.ts b/src/app.ts index 2170bb042..16ea18a14 100644 --- a/src/app.ts +++ b/src/app.ts @@ -367,6 +367,9 @@ function startGateway(): void { } function gracefulExit(): void { + if (Platform.implemented('stop')) { + Platform.stop(); + } AddonManager.unloadAddons(); TunnelService.stop(); } diff --git a/src/platform.ts b/src/platform.ts index d2e5b94ec..baadd9261 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -261,6 +261,7 @@ export const getNtpStatus = (): boolean => { return wrapPlatform(platform, 'getNtpStatus')(); }; +export const stop = wrapPlatform(platform, 'stop'); export const implemented = (fn: string): boolean => { if (platform === null) { diff --git a/src/platforms/base.ts b/src/platforms/base.ts index 724044df8..8176622d3 100644 --- a/src/platforms/base.ts +++ b/src/platforms/base.ts @@ -292,4 +292,11 @@ export default class BasePlatform { restartNtpSync(): boolean { throw new NotImplementedError('restartNtpSync'); } + + /** + * Gracefully stop any platform services on shutdown. + */ + stop(): void { + throw new NotImplementedError('stop'); + } } diff --git a/src/platforms/linux-ubuntu-core.ts b/src/platforms/linux-ubuntu-core.ts index 1d0b11a80..416663179 100644 --- a/src/platforms/linux-ubuntu-core.ts +++ b/src/platforms/linux-ubuntu-core.ts @@ -13,6 +13,13 @@ import NetworkManager, { ConnectionSettings } from './utilities/network-manager' import { LanMode, NetworkAddresses, WirelessNetwork } from './types'; export class LinuxUbuntuCorePlatform extends BasePlatform { + /** + * Disconnect NetworkManager. + */ + stop(): void { + NetworkManager.stop(); + } + /** * Get the current addresses for Wi-Fi and LAN. * diff --git a/src/platforms/utilities/network-manager.ts b/src/platforms/utilities/network-manager.ts index 3d3ef02c2..f50618854 100644 --- a/src/platforms/utilities/network-manager.ts +++ b/src/platforms/utilities/network-manager.ts @@ -36,6 +36,13 @@ class NetworkManager { // Note there can only be one system bus instance open at a time. private systemBus = DBus.getBus('system'); + /** + * Disconnect the system bus. + */ + stop(): void { + this.systemBus.disconnect(); + } + /** * Get a list of network adapters from the system network manager. * @@ -147,28 +154,27 @@ class NetworkManager { */ getDeviceConnection(path: string): Promise { return new Promise((resolve, reject) => { - const systemBus = this.systemBus; - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', path, 'org.freedesktop.NetworkManager.Device', - function (error, iface) { + (error, iface) => { if (error) { console.error(error); reject(); return; } - iface.getProperty('ActiveConnection', function (error, activeConnectionPath) { + iface.getProperty('ActiveConnection', (error, activeConnectionPath) => { if (error) { console.error(error); reject(); return; } - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', activeConnectionPath, 'org.freedesktop.NetworkManager.Connection.Active', - function (error, iface) { + (error, iface) => { if (error) { console.error(error); reject(); @@ -297,29 +303,28 @@ class NetworkManager { * @returns {Promise>} Promise resolves with IP4Config object. */ getDeviceIp4Config(path: string): Promise> { - const systemBus = this.systemBus; return new Promise((resolve, reject) => { - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', path, 'org.freedesktop.NetworkManager.Device', - function (error, iface) { + (error, iface) => { if (error) { console.error(error); reject(); return; } - iface.getProperty('Ip4Config', function (error, ip4ConfigPath) { + iface.getProperty('Ip4Config', (error, ip4ConfigPath) => { if (error) { console.error(error); reject(); return; } - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', ip4ConfigPath, 'org.freedesktop.NetworkManager.IP4Config', - function (error, iface) { + (error, iface) => { if (error) { console.error(error); reject(); @@ -350,9 +355,8 @@ class NetworkManager { * @returns {Promise} The SSID of the access point. */ getAccessPointSsid(path: string): Promise { - const systemBus = this.systemBus; return new Promise((resolve, reject) => { - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', path, 'org.freedesktop.NetworkManager.AccessPoint', @@ -386,9 +390,8 @@ class NetworkManager { * @returns {Promise} The strength of the signal as a percentage. */ getAccessPointStrength(path: string): Promise { - const systemBus = this.systemBus; return new Promise((resolve, reject) => { - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', path, 'org.freedesktop.NetworkManager.AccessPoint', @@ -420,13 +423,12 @@ class NetworkManager { * @returns {Promise} true if encrypted, false if not. */ async getAccessPointSecurity(path: string): Promise { - const systemBus = this.systemBus; const wpaFlagRequest = new Promise((resolve, reject) => { - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', path, 'org.freedesktop.NetworkManager.AccessPoint', - function (error, iface) { + (error, iface) => { if (error) { console.error(error); reject(); @@ -446,7 +448,7 @@ class NetworkManager { ); }); const wpa2FlagRequest = new Promise((resolve, reject) => { - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', path, 'org.freedesktop.NetworkManager.AccessPoint', @@ -536,9 +538,8 @@ class NetworkManager { * @returns {Promise} Promise resolves with the DBUS object path of an access point. */ getActiveAccessPoint(path: string): Promise { - const systemBus = this.systemBus; return new Promise((resolve, reject) => { - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', path, 'org.freedesktop.NetworkManager.Device.Wireless', @@ -632,9 +633,8 @@ class NetworkManager { secure: boolean, password: string ): Promise { - const systemBus = this.systemBus; return new Promise((resolve, reject) => { - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager', 'org.freedesktop.NetworkManager', @@ -695,9 +695,8 @@ class NetworkManager { * deactivation or rejects with an Error on failure. */ disconnectNetworkDevice(path: string): Promise { - const systemBus = this.systemBus; return new Promise((resolve, reject) => { - systemBus.getInterface( + this.systemBus.getInterface( 'org.freedesktop.NetworkManager', path, 'org.freedesktop.NetworkManager.Device', diff --git a/src/test/common.ts b/src/test/common.ts index 76f25931b..c8d1f5cd4 100644 --- a/src/test/common.ts +++ b/src/test/common.ts @@ -14,6 +14,7 @@ import Events from '../models/events'; import Logs from '../models/logs'; import Things from '../models/things'; import UserProfile from '../user-profile'; +import * as Platform from '../platform'; import e2p from 'event-to-promise'; import fs from 'fs'; import path from 'path'; @@ -91,6 +92,9 @@ afterEach(async () => { }); afterAll(async () => { + if (Platform.implemented('stop')) { + Platform.stop(); + } Logs.close(); await addonManager.unloadAddons();