@iotize/device-com-wifi.cordova
Version:
IoTize Cordova plugin for Wifi devices
402 lines (394 loc) • 16.7 kB
JavaScript
import { promiseTimeout } from '@iotize/common/promise';
import { BehaviorSubject, Subject, Observable, of } from 'rxjs';
import { createDebugger } from '@iotize/common/debug';
import { QueueComProtocol } from '@iotize/tap/protocol/core';
import { share } from 'rxjs/operators';
const debug = createDebugger(`/device-com-wifi.cordova`);
var __awaiter$2 = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const TAG$1 = "WifiScannerCordova";
const DEFAULT_STOP_TIMEOUT$1 = 10 * 1000;
/**
*
*/
class WifiScanner {
constructor() {
this._isScanning$ = new BehaviorSubject(false);
this._devices$ = new Subject();
}
get scanning() {
return this._isScanning$.asObservable();
}
get isScanning() {
return this._isScanning$.value;
}
get results() {
return this._devices$.asObservable();
}
isAvailable() {
return WifiWizard2.isWifiEnabled();
}
/**
* Launches the scan for BLE devices
*/
start(options = {}) {
return __awaiter$2(this, void 0, void 0, function* () {
// if (!await this.isAvailable()){
// throw new Error(`WiFi is not available. Please enabled Wi-Fi to start scan`);
// }
if (this.isScanning) {
debug(TAG$1, "Already scanning");
return;
}
debug(TAG$1, "Start Scanning ...");
this._isScanning$.next(true);
this._scanPromise = WifiWizard2.scan()
// .then(() => {
// const timeout = options.timeout || 5000;
// debug(TAG, `Waiting for ${timeout}ms...`);
// return WifiWizard2.timeout(timeout);
// })
// .then(() => {
// debug(TAG, 'Getting scan results...');
// return WifiWizard2.getScanResults();
// })
.then((scanResults) => {
this._devices$.next(scanResults);
debug(TAG$1, "Scanner stopped", scanResults);
this._isScanning$.next(false);
})
.catch((err) => {
this._isScanning$.next(false);
debug(TAG$1, "Scan result error", err);
});
});
}
stop(options) {
return __awaiter$2(this, void 0, void 0, function* () {
debug(TAG$1, "Stop Scanning ...");
return promiseTimeout((options === null || options === void 0 ? void 0 : options.timeout) || DEFAULT_STOP_TIMEOUT$1, this._cancelScan());
});
}
_cancelScan() {
return __awaiter$2(this, void 0, void 0, function* () {
this._isScanning$.next(false);
try {
const scanResults = yield WifiWizard2.getScanResults();
if (this._devices$) {
this._devices$.next(scanResults);
}
}
catch (err) {
// we can ignore if getScanResults has errors
}
});
}
}
class WifiComProtocolError extends Error {
constructor(code, msg, cause) {
super(msg);
this.code = code;
this.cause = cause;
}
static wifiNotEnabled(network) {
return new WifiComProtocolError(WifiComProtocolError.Code.WifiNotEnabled, `WiFi is not enabled. Cannot connect to network "${network.SSID}"`);
}
static connectFailedTimeout(network) {
return new WifiComProtocolError(WifiComProtocolError.Code.ConnectFailedTimeout, `Connection to "${network.SSID}" timeout`);
}
static cannotConnectToNetwork(network) {
return new WifiComProtocolError(WifiComProtocolError.Code.CannotConnectToNetwork, `Cannot connect Wi-Fi network "${network.SSID}"`);
}
static unknownError(err, network) {
return new WifiComProtocolError(WifiComProtocolError.Code.UnknownError, err.message || `Unknown Wi-Fi protocol error`, err);
}
}
(function (WifiComProtocolError) {
let Code;
(function (Code) {
Code["CannotConnectToNetwork"] = "WifiComProtocolErrorCannotConnectToNetwork";
Code["ConnectFailedTimeout"] = "WifiComProtocolErrorConnectFailedTimeout";
Code["UnknownError"] = "WifiComProtocolErrorUnknown";
Code["WifiNotEnabled"] = "WifiComProtocolErrorWifiNotEnabled";
})(Code = WifiComProtocolError.Code || (WifiComProtocolError.Code = {}));
})(WifiComProtocolError || (WifiComProtocolError = {}));
var __awaiter$1 = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
class WifiComProtocol extends QueueComProtocol {
constructor(wifiOptions, createSubProtocol) {
super();
this.wifiOptions = wifiOptions;
this.createSubProtocol = createSubProtocol;
}
get socketProtocol() {
if (!this._socketProtocol) {
throw new Error(`Protocol is not connected yet`); // TODO proper error code
}
return this._socketProtocol;
}
_connect(options) {
return new Observable((emitter) => {
(() => __awaiter$1(this, void 0, void 0, function* () {
try {
if (this.wifiOptions.network) {
let currentSSID = yield WifiWizard2.getConnectedSSID();
if (currentSSID !== this.wifiOptions.network.SSID) {
debug('currently connected to', currentSSID, 'expected ', this.wifiOptions.network.SSID, '=> try to connect to ', this.wifiOptions.network);
yield WifiWizard2.connect(this.wifiOptions.network.SSID, true, this.wifiOptions.network.password, this.wifiOptions.network.algorithm, this.wifiOptions.network.hidden);
currentSSID = yield WifiWizard2.getConnectedSSID();
if (currentSSID !== this.wifiOptions.network.SSID) {
emitter.error(WifiComProtocolError.cannotConnectToNetwork(this.wifiOptions.network));
return;
}
debug('now connected to SSID', currentSSID);
}
}
debug('Now creating socket protocol with options', this.wifiOptions);
this._socketProtocol = yield this.createSubProtocol(this.wifiOptions);
if (this.subProtocolConnectionStateSub)
this.subProtocolConnectionStateSub.unsubscribe();
this.subProtocolConnectionStateSub = this._socketProtocol
.onConnectionStateChange()
.subscribe((event) => {
this.setConnectionState(event.newState);
});
yield this._socketProtocol.connect().toPromise();
emitter.complete();
}
catch (err) {
if (this.wifiOptions.network) {
switch (err) {
case 'CONNECT_FAILED_TIMEOUT':
err = WifiComProtocolError.connectFailedTimeout(this.wifiOptions.network);
break;
case 'WIFI_NOT_ENABLED':
err = WifiComProtocolError.wifiNotEnabled(this.wifiOptions.network);
break;
}
}
if (typeof err === 'string') {
err = WifiComProtocolError.unknownError(new Error(err), this.wifiOptions.network);
}
if (this.subProtocolConnectionStateSub)
this.subProtocolConnectionStateSub.unsubscribe();
debug('_connect error', err);
emitter.error(err);
}
}))();
}).pipe(share());
}
_disconnect(options) {
if (this.subProtocolConnectionStateSub)
this.subProtocolConnectionStateSub.unsubscribe();
if (!this._socketProtocol) {
return of(true);
}
return this._socketProtocol.disconnect();
}
write(data) {
return this.socketProtocol.write(data);
}
read() {
return this.socketProtocol.read();
}
}
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const TAG = 'ZeroConfScannerCordova';
const DEFAULT_STOP_TIMEOUT = 10 * 1000;
class ZeroConfScannerCordova {
constructor(options = {
domain: 'local.',
type: '_tapm2m._tcp.',
}) {
this.options = options;
// _hostname: string;
this._services = [];
this._services$ = new Subject();
this._isRunning = new BehaviorSubject(false);
if (typeof cordova !== undefined && cordova && cordova.plugins) {
this.zeroconf = cordova.plugins.zeroconf;
}
else {
throw new Error(`Cordova plugin zeroconf is missing`);
}
}
get results() {
return this._services$.asObservable();
}
get scanning() {
return this._isRunning.asObservable();
}
get isScanning() {
return this._isRunning.value;
}
set type(type) {
this.options.type = type;
}
set domain(domain) {
this.options.domain = domain;
}
/**
* Start scan
*/
start(option) {
return __awaiter(this, void 0, void 0, function* () {
debug(TAG, 'start');
this._isRunning.next(true);
try {
if (this._closingProcess) {
yield this._closingProcess;
}
yield this.init();
yield this._start();
}
catch (err) {
this._isRunning.next(false);
debug('_start error', err);
throw err;
}
});
}
stop(options) {
return __awaiter(this, void 0, void 0, function* () {
if (this._closingProcess) {
yield this._closingProcess;
return;
}
try {
this._isRunning.next(false);
this._closingProcess = (() => __awaiter(this, void 0, void 0, function* () {
debug(TAG, 'close start!');
yield this.unwatch().catch((err) => { });
yield this._close(options).catch((err) => { });
debug(TAG, 'close done!');
}))();
yield this._closingProcess;
}
finally {
this._closingProcess = undefined;
}
});
}
/**
* Initialize/reinitialize scanner
*/
init() {
return __awaiter(this, void 0, void 0, function* () {
debug(TAG, 'init zero conf...');
yield new Promise((resolve, reject) => {
this.zeroconf.reInit(resolve, reject);
});
});
}
_close(options) {
return __awaiter(this, void 0, void 0, function* () {
return yield promiseTimeout((options === null || options === void 0 ? void 0 : options.timeout) || DEFAULT_STOP_TIMEOUT, new Promise((resolve, reject) => {
debug(TAG, 'stoping...', this.options);
this.zeroconf.close(() => {
debug(TAG, 'stopped');
resolve();
}, (err) => {
debug(TAG, 'stop error', err);
reject(err);
});
}));
});
}
unwatch() {
return new Promise((resolve, reject) => {
debug(TAG, 'unwatching...');
this.zeroconf.unwatch(this.options.type, this.options.domain, () => {
debug(TAG, 'unwatch stop', this.options);
resolve();
}, (err) => {
debug(TAG, 'unwatch error', this.options, err);
reject(err);
});
});
}
getHostname() {
return new Promise((resolve, reject) => {
this.zeroconf.getHostname((hostname) => {
resolve(hostname);
}, reject);
});
}
_start() {
return __awaiter(this, void 0, void 0, function* () {
// if (!this._hostname) {
// this._hostname = await this.getHostname();
// }
this._services = [];
this._services$.next(this._services);
// debug('Hostname: ', this._hostname);
debug('Zero conf watch: ', this.options);
this.zeroconf.watch(this.options.type, this.options.domain, (result) => {
debug('Zero conf result', result);
const action = result.action;
const service = result.service;
if (service) {
switch (action) {
case 'added':
break;
case 'resolved':
this._onServiceResolved(resolveHost(service));
break;
default:
this._removeService(resolveHost(service));
}
}
});
});
}
_removeService(service) {
const existsingIndex = this._findServiceIndex(service);
if (existsingIndex >= 0) {
this._services.splice(existsingIndex, 1);
}
this._services$.next(this._services);
}
_findServiceIndex(service) {
return this._services.findIndex((s2) => JSON.stringify(s2) === JSON.stringify(service));
}
_onServiceResolved(service) {
if (this._findServiceIndex(service) < 0) {
this._services.push(service);
const serviceListCopy = [...this._services];
debug('Emit new results: ', serviceListCopy);
this._services$.next(serviceListCopy);
}
}
}
function resolveHost(input) {
const host = input.ipv4Addresses && input.ipv4Addresses.length > 0
? input.ipv4Addresses[0]
: undefined;
return Object.assign(Object.assign({}, input), { host });
}
/**
* Generated bundle index. Do not edit.
*/
export { WifiComProtocol, WifiComProtocolError, WifiScanner, ZeroConfScannerCordova };
//# sourceMappingURL=iotize-device-com-wifi.cordova.js.map