ble/actions: namespace actions

This way we don't have to use aliases when importing.
This commit is contained in:
David Lechner
2022-07-15 11:16:23 -05:00
parent 25e86c2f60
commit ecd32e61b9
12 changed files with 245 additions and 148 deletions
+18 -18
View File
@@ -5,17 +5,17 @@
import { createAction } from '../actions';
/**
* Creates an action that indicates connecting has been requested.
* Creates an action that initiates a connection to a hub running Pybricks firmware.
*/
export const connect = createAction(() => ({
type: 'ble.device.action.connect',
export const bleConnectPybricks = createAction(() => ({
type: 'ble.action.connectPybricks',
}));
/**
* Creates an action that indicates a device was connected.
* Response that indicates {@link bleConnectPybricks} succeeded.
*/
export const didConnect = createAction((id: string, name: string) => ({
type: 'ble.device.action.didConnect',
export const bleDidConnectPybricks = createAction((id: string, name: string) => ({
type: 'ble.device.action.didConnectPybricks',
id,
name,
}));
@@ -67,34 +67,34 @@ export type BleDeviceDidFailToConnectReason =
| BleDeviceFailToConnectUnknownReason;
/**
* Creates an action that indicates a device failed to connect.
* Response that indicates {@link bleConnectPybricks} failed.
*/
export const didFailToConnect = createAction(
export const bleDidFailToConnectPybricks = createAction(
(reason: BleDeviceDidFailToConnectReason) => ({
type: 'ble.device.action.didFailToConnect',
type: 'ble.action.didFailToConnectPybricks',
...reason,
}),
);
/**
* Creates an action that indicates disconnecting was requested.
* Creates an action to request disconnecting a hub running Pybricks firmware.
*/
export const disconnect = createAction(() => ({
type: 'ble.device.action.disconnect',
export const bleDisconnectPybricks = createAction(() => ({
type: 'ble.action.disconnectPybricks',
}));
/**
* Creates an action that indicates a device was disconnected.
* Creates an action that indicates that {@link bleDisconnectPybricks} succeeded.
*/
export const didDisconnect = createAction(() => ({
type: 'ble.device.action.didDisconnect',
export const bleDidDisconnectPybricks = createAction(() => ({
type: 'ble.action.didDisconnectPybricks',
}));
/**
* Creates an action that indicates a device failed to disconnect.
* Creates an action that indicates that {@link bleDisconnectPybricks} failed.
*/
export const didFailToDisconnect = createAction(() => ({
type: 'ble.device.action.didFailToDisconnect',
export const bleDidFailToDisconnectPybricks = createAction(() => ({
type: 'ble.action.didFailToDisconnectPybricks',
}));
/**
+31 -22
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 The Pybricks Authors
// Copyright (c) 2021-2022 The Pybricks Authors
import { AnyAction } from 'redux';
import {
@@ -12,12 +12,12 @@ import { didReceiveStatusReport } from '../ble-pybricks-service/actions';
import { Status, statusToFlag } from '../ble-pybricks-service/protocol';
import {
BleDeviceDidFailToConnectReason,
connect,
didConnect,
didDisconnect,
didFailToConnect,
didFailToDisconnect,
disconnect,
bleConnectPybricks,
bleDidConnectPybricks,
bleDidDisconnectPybricks,
bleDidFailToConnectPybricks,
bleDidFailToDisconnectPybricks,
bleDisconnectPybricks,
} from './actions';
import reducers, { BleConnectionState } from './reducers';
@@ -38,35 +38,39 @@ test('initial state', () => {
test('connection', () => {
expect(
reducers({ connection: BleConnectionState.Disconnected } as State, connect())
.connection,
reducers(
{ connection: BleConnectionState.Disconnected } as State,
bleConnectPybricks(),
).connection,
).toBe(BleConnectionState.Connecting);
expect(
reducers(
{ connection: BleConnectionState.Connecting } as State,
didConnect('test-id', 'Test Name'),
bleDidConnectPybricks('test-id', 'Test Name'),
).connection,
).toBe(BleConnectionState.Connected);
expect(
reducers(
{ connection: BleConnectionState.Connecting } as State,
didFailToConnect({} as BleDeviceDidFailToConnectReason),
bleDidFailToConnectPybricks({} as BleDeviceDidFailToConnectReason),
).connection,
).toBe(BleConnectionState.Disconnected);
expect(
reducers({ connection: BleConnectionState.Connected } as State, disconnect())
.connection,
reducers(
{ connection: BleConnectionState.Connected } as State,
bleDisconnectPybricks(),
).connection,
).toBe(BleConnectionState.Disconnecting);
expect(
reducers(
{ connection: BleConnectionState.Disconnecting } as State,
didDisconnect(),
bleDidDisconnectPybricks(),
).connection,
).toBe(BleConnectionState.Disconnected);
expect(
reducers(
{ connection: BleConnectionState.Disconnecting } as State,
didFailToDisconnect(),
bleDidFailToDisconnectPybricks(),
).connection,
).toBe(BleConnectionState.Connected);
});
@@ -76,11 +80,13 @@ test('deviceName', () => {
const testName = 'Test Name';
expect(
reducers({ deviceName: '' } as State, didConnect(testId, testName)).deviceName,
reducers({ deviceName: '' } as State, bleDidConnectPybricks(testId, testName))
.deviceName,
).toBe(testName);
expect(
reducers({ deviceName: testName } as State, didDisconnect()).deviceName,
reducers({ deviceName: testName } as State, bleDidDisconnectPybricks())
.deviceName,
).toBe('');
});
@@ -98,7 +104,8 @@ test('deviceType', () => {
).toBe('Move hub');
expect(
reducers({ deviceType: 'Move hub' } as State, didDisconnect()).deviceType,
reducers({ deviceType: 'Move hub' } as State, bleDidDisconnectPybricks())
.deviceType,
).toBe('');
});
@@ -113,8 +120,10 @@ test('deviceFirmwareVersion', () => {
).toBe(testVersion);
expect(
reducers({ deviceFirmwareVersion: testVersion } as State, didDisconnect())
.deviceFirmwareVersion,
reducers(
{ deviceFirmwareVersion: testVersion } as State,
bleDidDisconnectPybricks(),
).deviceFirmwareVersion,
).toBe('');
});
@@ -134,14 +143,14 @@ test('deviceLowBatteryWarning', () => {
).toBeFalsy();
expect(
reducers({ deviceLowBatteryWarning: true } as State, didDisconnect())
reducers({ deviceLowBatteryWarning: true } as State, bleDidDisconnectPybricks())
.deviceLowBatteryWarning,
).toBeFalsy();
});
test('deviceBatteryCharging', () => {
expect(
reducers({ deviceBatteryCharging: true } as State, didDisconnect())
reducers({ deviceBatteryCharging: true } as State, bleDidDisconnectPybricks())
.deviceBatteryCharging,
).toBeFalsy();
});
+22 -16
View File
@@ -13,12 +13,12 @@ import { getHubTypeName } from '../ble-device-info-service/protocol';
import { didReceiveStatusReport } from '../ble-pybricks-service/actions';
import { Status, statusToFlag } from '../ble-pybricks-service/protocol';
import {
connect,
didConnect,
didDisconnect,
didFailToConnect,
didFailToDisconnect,
disconnect,
bleConnectPybricks,
bleDidConnectPybricks,
bleDidDisconnectPybricks,
bleDidFailToConnectPybricks,
bleDidFailToDisconnectPybricks,
bleDisconnectPybricks,
} from './actions';
/**
@@ -47,19 +47,25 @@ const connection: Reducer<BleConnectionState> = (
state = BleConnectionState.Disconnected,
action,
) => {
if (connect.matches(action)) {
if (bleConnectPybricks.matches(action)) {
return BleConnectionState.Connecting;
}
if (didConnect.matches(action) || didFailToDisconnect.matches(action)) {
if (
bleDidConnectPybricks.matches(action) ||
bleDidFailToDisconnectPybricks.matches(action)
) {
return BleConnectionState.Connected;
}
if (disconnect.matches(action)) {
if (bleDisconnectPybricks.matches(action)) {
return BleConnectionState.Disconnecting;
}
if (didFailToConnect.matches(action) || didDisconnect.matches(action)) {
if (
bleDidFailToConnectPybricks.matches(action) ||
bleDidDisconnectPybricks.matches(action)
) {
return BleConnectionState.Disconnected;
}
@@ -67,11 +73,11 @@ const connection: Reducer<BleConnectionState> = (
};
const deviceName: Reducer<string> = (state = '', action) => {
if (didDisconnect.matches(action)) {
if (bleDidDisconnectPybricks.matches(action)) {
return '';
}
if (didConnect.matches(action)) {
if (bleDidConnectPybricks.matches(action)) {
return action.name;
}
@@ -79,7 +85,7 @@ const deviceName: Reducer<string> = (state = '', action) => {
};
const deviceType: Reducer<string> = (state = '', action) => {
if (didDisconnect.matches(action)) {
if (bleDidDisconnectPybricks.matches(action)) {
return '';
}
@@ -91,7 +97,7 @@ const deviceType: Reducer<string> = (state = '', action) => {
};
const deviceFirmwareVersion: Reducer<string> = (state = '', action) => {
if (didDisconnect.matches(action)) {
if (bleDidDisconnectPybricks.matches(action)) {
return '';
}
@@ -103,7 +109,7 @@ const deviceFirmwareVersion: Reducer<string> = (state = '', action) => {
};
const deviceLowBatteryWarning: Reducer<boolean> = (state = false, action) => {
if (didDisconnect.matches(action)) {
if (bleDidDisconnectPybricks.matches(action)) {
return false;
}
@@ -117,7 +123,7 @@ const deviceLowBatteryWarning: Reducer<boolean> = (state = false, action) => {
};
const deviceBatteryCharging: Reducer<boolean> = (state = false, action) => {
if (didDisconnect.matches(action)) {
if (bleDidDisconnectPybricks.matches(action)) {
return false;
}
+35 -33
View File
@@ -27,11 +27,11 @@ import {
} from '../ble-pybricks-service/protocol';
import {
BleDeviceFailToConnectReasonType,
connect,
didConnect,
didDisconnect,
didFailToConnect,
disconnect,
bleConnectPybricks,
bleDidConnectPybricks,
bleDidDisconnectPybricks,
bleDidFailToConnectPybricks,
bleDisconnectPybricks,
toggleBluetooth,
} from './actions';
import { BleConnectionState } from './reducers';
@@ -191,7 +191,7 @@ enum ConnectRunPoint {
* @param point The point at which to stop running.
*/
async function runConnectUntil(saga: AsyncSaga, point: ConnectRunPoint): Promise<void> {
saga.put(connect());
saga.put(bleConnectPybricks());
if (point === ConnectRunPoint.Connect) {
return;
@@ -226,7 +226,9 @@ async function runConnectUntil(saga: AsyncSaga, point: ConnectRunPoint): Promise
return;
}
await expect(saga.take()).resolves.toEqual(didConnect('test-id', 'test name'));
await expect(saga.take()).resolves.toEqual(
bleDidConnectPybricks('test-id', 'test name'),
);
}
describe('connect action is dispatched', () => {
@@ -240,7 +242,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoWebBluetooth,
}),
);
@@ -259,7 +261,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoBluetooth,
}),
);
@@ -273,7 +275,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Canceled,
}),
);
@@ -288,7 +290,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -301,7 +303,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoGatt,
}),
);
@@ -314,7 +316,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -330,7 +332,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoDeviceInfoService,
}),
);
@@ -347,7 +349,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -363,7 +365,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.Connect);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -381,7 +383,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceiveFirmwareRevision);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -397,7 +399,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceiveFirmwareRevision);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -415,7 +417,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceiveSoftwareRevision);
await expect(saga.take()).resolves.toEqual(
didConnect('test-id', 'test name'),
bleDidConnectPybricks('test-id', 'test name'),
);
});
@@ -426,7 +428,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceiveSoftwareRevision);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -444,7 +446,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoPybricksService,
}),
);
@@ -461,7 +463,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -477,7 +479,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -493,7 +495,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -511,7 +513,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
// FIXME: this is wrong error
reason: BleDeviceFailToConnectReasonType.NoPybricksService,
}),
@@ -529,7 +531,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -547,7 +549,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -563,7 +565,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -579,7 +581,7 @@ describe('connect action is dispatched', () => {
await runConnectUntil(saga, ConnectRunPoint.DidReceivePnpId);
await expect(saga.take()).resolves.toEqual(
didFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: testError,
}),
@@ -595,9 +597,9 @@ describe('connect action is dispatched', () => {
it('should handle disconnect', async () => {
await runConnectUntil(saga, ConnectRunPoint.DidConnect);
saga.put(disconnect());
saga.put(bleDisconnectPybricks());
await expect(saga.take()).resolves.toEqual(didDisconnect());
await expect(saga.take()).resolves.toEqual(bleDidDisconnectPybricks());
expect(mocks.gatt.disconnect).toHaveBeenCalled();
});
@@ -616,7 +618,7 @@ describe('toggleBluetooth action', () => {
saga.put(toggleBluetooth());
await expect(saga.take()).resolves.toEqual(connect());
await expect(saga.take()).resolves.toEqual(bleConnectPybricks());
});
it('should disconnect when connected', async () => {
@@ -626,6 +628,6 @@ describe('toggleBluetooth action', () => {
saga.put(toggleBluetooth());
await expect(saga.take()).resolves.toEqual(disconnect());
await expect(saga.take()).resolves.toEqual(bleDisconnectPybricks());
});
});
+105 -34
View File
@@ -52,11 +52,11 @@ import { RootState } from '../reducers';
import { ensureError } from '../utils';
import {
BleDeviceFailToConnectReasonType as Reason,
connect,
didConnect,
didDisconnect,
didFailToConnect,
disconnect,
bleConnectPybricks as bleConnectPybricks,
bleDidConnectPybricks,
bleDidDisconnectPybricks,
bleDidFailToConnectPybricks,
bleDisconnectPybricks,
toggleBluetooth,
} from './actions';
import { BleConnectionState } from './reducers';
@@ -99,15 +99,15 @@ function* handleWriteUart(
}
}
function* handleConnect(): Generator {
function* handleBleConnectPybricks(): Generator {
if (navigator.bluetooth === undefined) {
yield* put(didFailToConnect({ reason: Reason.NoWebBluetooth }));
yield* put(bleDidFailToConnectPybricks({ reason: Reason.NoWebBluetooth }));
return;
}
const available = yield* call(() => navigator.bluetooth.getAvailability());
if (!available) {
yield* put(didFailToConnect({ reason: Reason.NoBluetooth }));
yield* put(bleDidFailToConnectPybricks({ reason: Reason.NoBluetooth }));
return;
}
@@ -126,17 +126,20 @@ function* handleConnect(): Generator {
} catch (err) {
if (err instanceof DOMException && err.code === DOMException.NOT_FOUND_ERR) {
// this can happen if the use cancels the dialog
yield* put(didFailToConnect({ reason: Reason.Canceled }));
yield* put(bleDidFailToConnectPybricks({ reason: Reason.Canceled }));
} else {
yield* put(
didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }),
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
}
return;
}
if (device.gatt === undefined) {
yield* put(didFailToConnect({ reason: Reason.NoGatt }));
yield* put(bleDidFailToConnectPybricks({ reason: Reason.NoGatt }));
return;
}
@@ -152,11 +155,16 @@ function* handleConnect(): Generator {
server = yield* call([device.gatt, 'connect']);
} catch (err) {
disconnectChannel.close();
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
yield* takeEvery(disconnect, handleDisconnect, server);
yield* takeEvery(bleDisconnectPybricks, handleDisconnect, server);
let deviceInfoService: BluetoothRemoteGATTService;
try {
@@ -168,10 +176,15 @@ function* handleConnect(): Generator {
server.disconnect();
yield* takeMaybe(disconnectChannel);
if (err instanceof DOMException && err.code === DOMException.NOT_FOUND_ERR) {
yield* put(didFailToConnect({ reason: Reason.NoDeviceInfoService }));
yield* put(
bleDidFailToConnectPybricks({ reason: Reason.NoDeviceInfoService }),
);
} else {
yield* put(
didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }),
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
}
return;
@@ -186,7 +199,12 @@ function* handleConnect(): Generator {
} catch (err) {
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -196,7 +214,12 @@ function* handleConnect(): Generator {
} catch (err) {
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -209,7 +232,12 @@ function* handleConnect(): Generator {
} catch (err) {
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -219,7 +247,12 @@ function* handleConnect(): Generator {
} catch (err) {
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -240,7 +273,10 @@ function* handleConnect(): Generator {
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(
didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }),
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -256,10 +292,15 @@ function* handleConnect(): Generator {
server.disconnect();
yield* takeMaybe(disconnectChannel);
if (err instanceof DOMException && err.code === DOMException.NOT_FOUND_ERR) {
yield* put(didFailToConnect({ reason: Reason.NoPybricksService }));
yield* put(
bleDidFailToConnectPybricks({ reason: Reason.NoPybricksService }),
);
} else {
yield* put(
didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }),
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
}
return;
@@ -274,7 +315,12 @@ function* handleConnect(): Generator {
} catch (err) {
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -313,7 +359,12 @@ function* handleConnect(): Generator {
pybricksControlChannel.close();
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -328,10 +379,15 @@ function* handleConnect(): Generator {
server.disconnect();
yield* takeMaybe(disconnectChannel);
if (err instanceof DOMException && err.code === DOMException.NOT_FOUND_ERR) {
yield* put(didFailToConnect({ reason: Reason.NoPybricksService }));
yield* put(
bleDidFailToConnectPybricks({ reason: Reason.NoPybricksService }),
);
} else {
yield* put(
didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }),
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
}
return;
@@ -345,7 +401,12 @@ function* handleConnect(): Generator {
pybricksControlChannel.close();
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -357,7 +418,12 @@ function* handleConnect(): Generator {
pybricksControlChannel.close();
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
@@ -389,13 +455,18 @@ function* handleConnect(): Generator {
pybricksControlChannel.close();
server.disconnect();
yield* takeMaybe(disconnectChannel);
yield* put(didFailToConnect({ reason: Reason.Unknown, err: ensureError(err) }));
yield* put(
bleDidFailToConnectPybricks({
reason: Reason.Unknown,
err: ensureError(err),
}),
);
return;
}
tasks.push(yield* takeEvery(writeUart, handleWriteUart, uartRxChar));
yield* put(didConnect(device.id, device.name || ''));
yield* put(bleDidConnectPybricks(device.id, device.name || ''));
// wait for disconnection
yield* takeMaybe(disconnectChannel);
@@ -404,7 +475,7 @@ function* handleConnect(): Generator {
uartTxChannel.close();
pybricksControlChannel.close();
yield* put(didDisconnect());
yield* put(bleDidDisconnectPybricks());
}
function* handleToggleBluetooth(): Generator {
@@ -414,15 +485,15 @@ function* handleToggleBluetooth(): Generator {
switch (connectionState) {
case BleConnectionState.Connected:
yield* put(disconnect());
yield* put(bleDisconnectPybricks());
break;
case BleConnectionState.Disconnected:
yield* put(connect());
yield* put(bleConnectPybricks());
break;
}
}
export default function* (): Generator {
yield* takeEvery(connect, handleConnect);
yield* takeEvery(bleConnectPybricks, handleBleConnectPybricks);
yield* takeEvery(toggleBluetooth, handleToggleBluetooth);
}
+5 -3
View File
@@ -6,7 +6,7 @@ import { didFailToWrite } from '../ble-nordic-uart-service/actions';
import { eventProtocolError } from '../ble-pybricks-service/actions';
import {
BleDeviceFailToConnectReasonType,
didFailToConnect as bleDidFailToConnect,
bleDidFailToConnectPybricks,
} from '../ble/actions';
import {
BootloaderConnectionFailureReason,
@@ -21,12 +21,14 @@ test('bleDeviceDidFailToConnect', async () => {
console.error = jest.fn();
saga.put(
bleDidFailToConnect({ reason: BleDeviceFailToConnectReasonType.Canceled }),
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Canceled,
}),
);
expect(console.error).toHaveBeenCalledTimes(0);
saga.put(
bleDidFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: new Error('test error'),
}),
+3 -3
View File
@@ -6,7 +6,7 @@ import { didFailToWrite as bleUartDidFailToWrite } from '../ble-nordic-uart-serv
import { eventProtocolError as pybricksEventProtocolError } from '../ble-pybricks-service/actions';
import {
BleDeviceFailToConnectReasonType,
didFailToConnect as bleDeviceDidFailToConnect,
bleDidFailToConnectPybricks,
} from '../ble/actions';
import { fileStorageDidFailToStoreTextFileValue } from '../fileStorage/actions';
import {
@@ -16,7 +16,7 @@ import {
} from '../lwp3-bootloader/actions';
function handleBleDeviceDidFailToConnect(
action: ReturnType<typeof bleDeviceDidFailToConnect>,
action: ReturnType<typeof bleDidFailToConnectPybricks>,
): void {
if (action.reason === BleDeviceFailToConnectReasonType.Unknown) {
console.error(action.err);
@@ -54,7 +54,7 @@ function handleFileStorageDidFailToStoreTextFileValue(
}
export default function* (): Generator {
yield* takeEvery(bleDeviceDidFailToConnect, handleBleDeviceDidFailToConnect);
yield* takeEvery(bleDidFailToConnectPybricks, handleBleDeviceDidFailToConnect);
yield* takeEvery(pybricksEventProtocolError, handlePybricksEventProtocolError);
yield* takeEvery(bleUartDidFailToWrite, handleBleUartDidFailToWrite);
yield* takeEvery(bootloaderDidFailToConnect, handleBootloaderDidFailToConnect);
+4 -3
View File
@@ -4,7 +4,7 @@
import { AnyAction } from 'redux';
import { didReceiveStatusReport } from '../ble-pybricks-service/actions';
import { Status, statusToFlag } from '../ble-pybricks-service/protocol';
import { didConnect, didDisconnect } from '../ble/actions';
import { bleDidConnectPybricks, bleDidDisconnectPybricks } from '../ble/actions';
import {
didFailToFinishDownload,
didFinishDownload,
@@ -30,7 +30,7 @@ describe('runtime', () => {
expect(
reducers(
{ runtime: HubRuntimeState.Disconnected } as State,
didConnect('test-id', 'Test Name'),
bleDidConnectPybricks('test-id', 'Test Name'),
).runtime,
).toBe(HubRuntimeState.Unknown);
});
@@ -38,7 +38,8 @@ describe('runtime', () => {
test.each(Object.values(HubRuntimeState))('didDisconnect', (startingState) => {
// all states are overridden by disconnect
expect(
reducers({ runtime: startingState } as State, didDisconnect()).runtime,
reducers({ runtime: startingState } as State, bleDidDisconnectPybricks())
.runtime,
).toBe(HubRuntimeState.Disconnected);
});
+3 -3
View File
@@ -6,7 +6,7 @@ import * as semver from 'semver';
import { bleDIServiceDidReceiveFirmwareRevision } from '../ble-device-info-service/actions';
import { didReceiveStatusReport } from '../ble-pybricks-service/actions';
import { Status, statusToFlag } from '../ble-pybricks-service/protocol';
import { didConnect, didDisconnect } from '../ble/actions';
import { bleDidConnectPybricks, bleDidDisconnectPybricks } from '../ble/actions';
import { pythonVersionToSemver } from '../utils/version';
import {
didFailToFinishDownload,
@@ -49,11 +49,11 @@ const runtime: Reducer<HubRuntimeState> = (
state = HubRuntimeState.Disconnected,
action,
) => {
if (didConnect.matches(action)) {
if (bleDidConnectPybricks.matches(action)) {
return HubRuntimeState.Unknown;
}
if (didDisconnect.matches(action)) {
if (bleDidDisconnectPybricks.matches(action)) {
return HubRuntimeState.Disconnected;
}
+2 -2
View File
@@ -18,7 +18,7 @@ import {
didSendCommand,
sendStopUserProgramCommand,
} from '../ble-pybricks-service/actions';
import { didConnect } from '../ble/actions';
import { bleDidConnectPybricks } from '../ble/actions';
import { editorGetValue } from '../editor/sagas';
import { compile, didCompile, didFailToCompile } from '../mpy/actions';
import { defined } from '../utils';
@@ -190,5 +190,5 @@ export default function* (): Generator {
yield* takeEvery(repl, handleRepl);
yield* takeEvery(stop, handleStop);
// calling stop right after connecting should get the hub into a known state
yield* takeEvery(didConnect, handleStop);
yield* takeEvery(bleDidConnectPybricks, handleStop);
}
+14 -8
View File
@@ -14,7 +14,7 @@ import { appDidCheckForUpdate } from '../app/actions';
import { bleDIServiceDidReceiveFirmwareRevision } from '../ble-device-info-service/actions';
import {
BleDeviceFailToConnectReasonType,
didFailToConnect as bleDidFailToConnect,
bleDidFailToConnectPybricks,
} from '../ble/actions';
import { editorDidFailToOpenFile } from '../editor/actions';
import { EditorError } from '../editor/error';
@@ -61,14 +61,20 @@ function createTestToasterSaga(): { toaster: IToaster; saga: AsyncSaga } {
}
test.each([
bleDidFailToConnect({ reason: BleDeviceFailToConnectReasonType.NoWebBluetooth }),
bleDidFailToConnect({ reason: BleDeviceFailToConnectReasonType.NoBluetooth }),
bleDidFailToConnect({ reason: BleDeviceFailToConnectReasonType.NoGatt }),
bleDidFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoWebBluetooth,
}),
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoBluetooth,
}),
bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.NoGatt }),
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoDeviceInfoService,
}),
bleDidFailToConnect({ reason: BleDeviceFailToConnectReasonType.NoPybricksService }),
bleDidFailToConnect({
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.NoPybricksService,
}),
bleDidFailToConnectPybricks({
reason: BleDeviceFailToConnectReasonType.Unknown,
err: { name: 'test', message: 'unknown' },
}),
@@ -129,7 +135,7 @@ test.each([
});
test.each([
bleDidFailToConnect({ reason: BleDeviceFailToConnectReasonType.Canceled }),
bleDidFailToConnectPybricks({ reason: BleDeviceFailToConnectReasonType.Canceled }),
bootloaderDidFailToConnect(BootloaderConnectionFailureReason.Canceled),
didFailToFinish(FailToFinishReasonType.FailedToConnect),
serviceWorkerDidSucceed(),
+3 -3
View File
@@ -16,7 +16,7 @@ import { appName } from '../app/constants';
import { bleDIServiceDidReceiveFirmwareRevision } from '../ble-device-info-service/actions';
import {
BleDeviceFailToConnectReasonType,
didFailToConnect as bleDeviceDidFailToConnect,
bleDidFailToConnectPybricks,
} from '../ble/actions';
import { editorDidFailToOpenFile } from '../editor/actions';
import { EditorError } from '../editor/error';
@@ -171,7 +171,7 @@ function* showUnexpectedError(messageId: I18nId, error: Error): Generator {
}
function* showBleDeviceDidFailToConnectError(
action: ReturnType<typeof bleDeviceDidFailToConnect>,
action: ReturnType<typeof bleDidFailToConnectPybricks>,
): Generator {
switch (action.reason) {
case BleDeviceFailToConnectReasonType.NoGatt:
@@ -454,7 +454,7 @@ function* showExplorerFailToDelete(
}
export default function* (): Generator {
yield* takeEvery(bleDeviceDidFailToConnect, showBleDeviceDidFailToConnectError);
yield* takeEvery(bleDidFailToConnectPybricks, showBleDeviceDidFailToConnectError);
yield* takeEvery(bootloaderDidFailToConnect, showBootloaderDidFailToConnectError);
yield* takeEvery(didFailToFinish, showFlashFirmwareError);
yield* takeEvery(didCompile, dismissCompilerError);