From 556be706cd07c4ab13ebe3f23e32890aa9a615e8 Mon Sep 17 00:00:00 2001 From: Elsie Ju Date: Mon, 12 Sep 2022 15:55:18 -0700 Subject: [PATCH 1/2] Update cloudtodevice from sdk to api --- public/constants.ts | 1 - public/electron.ts | 2 -- public/handlers/deviceHandler.ts | 19 +--------- src/app/api/services/devicesService.spec.ts | 37 ++++++++++++------- src/app/api/services/devicesService.ts | 39 ++++++++++++++------- src/app/devices/deviceEvents/reducers.ts | 2 +- 6 files changed, 54 insertions(+), 46 deletions(-) diff --git a/public/constants.ts b/public/constants.ts index f9307a6e8..348d48080 100644 --- a/public/constants.ts +++ b/public/constants.ts @@ -7,7 +7,6 @@ export const PLATFORMS = { }; export const MESSAGE_CHANNELS = { - DEVICE_SEND_MESSAGE: 'device_sendMessage', DIRECTORY_GET_DIRECTORIES: 'directory_getDirectories', EVENTHUB_START_MONITORING: 'eventhub_startMonitoring', EVENTHUB_STOP_MONITORING: 'eventhub_stopMonitoring', diff --git a/public/electron.ts b/public/electron.ts index eefa9c95f..4db01fd68 100644 --- a/public/electron.ts +++ b/public/electron.ts @@ -10,7 +10,6 @@ import { PLATFORMS, MESSAGE_CHANNELS } from './constants'; import { onSettingsHighContrast } from './handlers/settingsHandler'; import { onGetInterfaceDefinition } from './handlers/modelRepositoryHandler'; import { onGetDirectories } from './handlers/directoryHandler'; -import { onSendMessageToDevice } from './handlers/deviceHandler'; import { onStartMonitoring, onStopMonitoring } from './handlers/eventHubHandler'; import { formatError } from './utils/errorHelper'; import '../dist/server/serverElectron'; @@ -32,7 +31,6 @@ class Main { Main.registerHandler(MESSAGE_CHANNELS.SETTING_HIGH_CONTRAST, onSettingsHighContrast); Main.registerHandler(MESSAGE_CHANNELS.MODEL_REPOSITORY_GET_DEFINITION, onGetInterfaceDefinition); Main.registerHandler(MESSAGE_CHANNELS.DIRECTORY_GET_DIRECTORIES, onGetDirectories); - Main.registerHandler(MESSAGE_CHANNELS.DEVICE_SEND_MESSAGE, onSendMessageToDevice); Main.registerHandler(MESSAGE_CHANNELS.EVENTHUB_START_MONITORING, onStartMonitoring); Main.registerHandler(MESSAGE_CHANNELS.EVENTHUB_STOP_MONITORING, onStopMonitoring); } diff --git a/public/handlers/deviceHandler.ts b/public/handlers/deviceHandler.ts index 474b3a0b3..ed2e3f8bd 100644 --- a/public/handlers/deviceHandler.ts +++ b/public/handlers/deviceHandler.ts @@ -2,25 +2,8 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License **********************************************************/ -import { IpcMainInvokeEvent } from 'electron'; -import { Client } from 'azure-iothub'; import { Message as CloudToDeviceMessage } from 'azure-iot-common'; -import { SendMessageToDeviceParameters, MessageProperty } from '../interfaces/deviceInterface'; - -export const onSendMessageToDevice = async (event: IpcMainInvokeEvent, params: SendMessageToDeviceParameters): Promise => { - const { deviceId, messageProperties, messageBody, connectionString } = params; - const hubClient = Client.fromConnectionString(connectionString); - - try { - const message = new CloudToDeviceMessage(messageBody); - addPropertiesToCloudToDeviceMessage(message, messageProperties || []); - - await hubClient.open(); - await hubClient.send(deviceId, message); - } finally { - await hubClient.close(); - } -}; +import { MessageProperty } from '../interfaces/deviceInterface'; // tslint:disable-next-line:cyclomatic-complexity export const addPropertiesToCloudToDeviceMessage = (message: CloudToDeviceMessage, properties: MessageProperty[]) => { diff --git a/src/app/api/services/devicesService.spec.ts b/src/app/api/services/devicesService.spec.ts index 37195178b..7c3dd86ab 100644 --- a/src/app/api/services/devicesService.spec.ts +++ b/src/app/api/services/devicesService.spec.ts @@ -82,7 +82,7 @@ describe('deviceTwinService', () => { const connectionInformation = mockDataPlaneConnectionHelper(); const dataPlaneRequest: DataplaneService.DataPlaneRequest = { - apiVersion: HUB_DATA_PLANE_API_VERSION, + apiVersion: HUB_DATA_PLANE_API_VERSION, hostName: connectionInformation.connectionInfo.hostName, httpMethod: HTTP_OPERATION_TYPES.Get, path: `twins/${deviceId}`, @@ -242,18 +242,31 @@ describe('deviceTwinService', () => { }; it('calls sendMessageToDevice with expected parameters', async () => { - const sendMessageToDevice = jest.fn(); - jest.spyOn(interfaceUtils, 'getDeviceInterface').mockReturnValue({ - sendMessageToDevice - }); + + jest.spyOn(DataplaneService, 'dataPlaneConnectionHelper').mockResolvedValue({ + connectionInfo, connectionString, sasToken}); + + const fetch = jest.spyOn(window, "fetch").mockResolvedValue({ + json: () => { + return {}; + }, + ok: true, + } as any); await DevicesService.cloudToDeviceMessage(parameters); - expect(sendMessageToDevice).toBeCalledWith({ - connectionString, - deviceId: 'deviceId', - messageBody: 'body', - messageProperties: [] - }); + + const resourceUrl = `https://test-string.azure-devices.net/devices/deviceId/messages/deviceBound?api-version=2020-06-30-preview`; + const serviceRequestParams = { + body: 'body', + cache: 'no-cache', + headers: { + 'authorization': `testSasToken`, + ['Content-Encoding']: 'utf-8' + }, + method: HTTP_OPERATION_TYPES.Post + }; + + expect(fetch).toHaveBeenLastCalledWith(resourceUrl, serviceRequestParams); }); }); @@ -290,7 +303,7 @@ describe('deviceTwinService', () => { const connectionInformation = mockDataPlaneConnectionHelper(); const dataPlaneRequest: DataplaneService.DataPlaneRequest = { - apiVersion: HUB_DATA_PLANE_API_VERSION, + apiVersion: HUB_DATA_PLANE_API_VERSION, body: JSON.stringify(deviceIdentity), hostName: connectionInformation.connectionInfo.hostName, httpMethod: HTTP_OPERATION_TYPES.Put, diff --git a/src/app/api/services/devicesService.ts b/src/app/api/services/devicesService.ts index 8519387fb..83e820c1d 100644 --- a/src/app/api/services/devicesService.ts +++ b/src/app/api/services/devicesService.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License **********************************************************/ import { + CloudToDeviceMessageParameters, FetchDeviceTwinParameters, InvokeMethodParameters, FetchDevicesParameters, @@ -10,8 +11,7 @@ import { FetchDeviceParameters, DeleteDevicesParameters, AddDeviceParameters, - UpdateDeviceParameters, - CloudToDeviceMessageParameters + UpdateDeviceParameters } from '../parameters/deviceParameters'; import { HEADERS, @@ -23,8 +23,9 @@ import { Message } from '../models/messages'; import { Twin, Device, DataPlaneResponse } from '../models/device'; import { DeviceIdentity } from '../models/deviceIdentity'; import { dataPlaneConnectionHelper, dataPlaneResponseHelper, request, DATAPLANE_CONTROLLER_ENDPOINT, DataPlaneRequest } from './dataplaneServiceHelper'; -import { getDeviceInterface, getEventHubInterface } from '../shared/interfaceUtils'; +import { getEventHubInterface } from '../shared/interfaceUtils'; import { parseEventHubMessage } from './eventHubMessageHelper'; +import { HttpError } from '../models/httpError'; const PAGE_SIZE = 100; @@ -99,16 +100,30 @@ export const invokeDirectMethod = async (parameters: InvokeMethodParameters): Pr return result && result.body; }; -export const cloudToDeviceMessage = async (parameters: CloudToDeviceMessageParameters) => { +export const cloudToDeviceMessage = async (params: CloudToDeviceMessageParameters) => { + const { deviceId, body, properties } = params; const connectionInfo = await dataPlaneConnectionHelper(); - const api = getDeviceInterface(); - - await api.sendMessageToDevice({ - connectionString: connectionInfo.connectionString, - deviceId: parameters.deviceId, - messageBody: parameters.body, - messageProperties: parameters.properties - }); + const authorization = connectionInfo.sasToken; + const uri = `https://${connectionInfo.connectionInfo.hostName}/devices/${encodeURIComponent(deviceId)}/messages/deviceBound?api-version=${HUB_DATA_PLANE_API_VERSION}`; + + const formattedProperties: Record = {}; + properties.forEach(s => formattedProperties[`iothub-app-${s.key}`] = s.value); + + const requestParams: RequestInit = { + body, + cache: 'no-cache', + headers: { + ...formattedProperties, + authorization, + ['Content-Encoding']: 'utf-8' + }, + method: HTTP_OPERATION_TYPES.Post + }; + + const response = await fetch(uri, requestParams); + if (!response.ok) { + throw new HttpError(response.status); + } }; export const addDevice = async (parameters: AddDeviceParameters): Promise => { diff --git a/src/app/devices/deviceEvents/reducers.ts b/src/app/devices/deviceEvents/reducers.ts index 8be23a42d..03d0cd191 100644 --- a/src/app/devices/deviceEvents/reducers.ts +++ b/src/app/devices/deviceEvents/reducers.ts @@ -55,4 +55,4 @@ export const deviceEventsReducer = reducerWithInitialState Date: Mon, 12 Sep 2022 19:23:16 -0700 Subject: [PATCH 2/2] update --- public/contextBridge.ts | 2 -- public/factories/deviceInterfaceFactory.ts | 15 --------------- 2 files changed, 17 deletions(-) delete mode 100644 public/factories/deviceInterfaceFactory.ts diff --git a/public/contextBridge.ts b/public/contextBridge.ts index d7d483137..6d072980e 100644 --- a/public/contextBridge.ts +++ b/public/contextBridge.ts @@ -6,12 +6,10 @@ import { contextBridge } from 'electron'; import { generateSettingsInterface } from './factories/settingsInterfaceFactory'; import { generateDirectoryInterface } from './factories/directoryInterfaceFactory'; import { generateModelRepositoryInterface } from './factories/modelRepositoryInterfaceFactory'; -import { generateDeviceInterface } from './factories/deviceInterfaceFactory'; import { generateEventHubInterface } from './factories/eventHubInterfaceFactory'; import { generateAuthenticationInterface } from './factories/authenticationInterfaceFactory'; import { API_INTERFACES } from './constants'; -contextBridge.exposeInMainWorld(API_INTERFACES.DEVICE, generateDeviceInterface()); contextBridge.exposeInMainWorld(API_INTERFACES.DIRECTORY, generateDirectoryInterface()); contextBridge.exposeInMainWorld(API_INTERFACES.EVENTHUB, generateEventHubInterface()); contextBridge.exposeInMainWorld(API_INTERFACES.MODEL_DEFINITION, generateModelRepositoryInterface()); diff --git a/public/factories/deviceInterfaceFactory.ts b/public/factories/deviceInterfaceFactory.ts deleted file mode 100644 index b28338ddf..000000000 --- a/public/factories/deviceInterfaceFactory.ts +++ /dev/null @@ -1,15 +0,0 @@ -/*********************************************************** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License - **********************************************************/ -import { MESSAGE_CHANNELS } from '../constants'; -import { DeviceInterface, SendMessageToDeviceParameters } from '../interfaces/deviceInterface'; -import { invokeInMainWorld } from '../utils/invokeHelper'; - -export const generateDeviceInterface = (): DeviceInterface => { - return { - sendMessageToDevice: async (params: SendMessageToDeviceParameters): Promise => { - return invokeInMainWorld(MESSAGE_CHANNELS.DEVICE_SEND_MESSAGE, params); - }, - }; -};