Skip to content
This repository has been archived by the owner on Jul 9, 2024. It is now read-only.

Commit

Permalink
feat: migrate signalR functions
Browse files Browse the repository at this point in the history
  • Loading branch information
pudkrong committed Oct 30, 2023
1 parent 3ecde56 commit 2e6c6bd
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 142 deletions.
25 changes: 0 additions & 25 deletions getSignalRConnectionInfo/function.json

This file was deleted.

21 changes: 10 additions & 11 deletions getSignalRConnectionInfo/getSignalRConnectionInfo.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { AzureFunction, Context, HttpRequest } from '@azure/functions'
import type { FunctionInput, HttpHandler } from '@azure/functions'
import { result } from '../lib/http.js'

const getSignalRConnectionInfo: AzureFunction = async (
context: Context,
_: HttpRequest,
connectionInfo: {
url: string
accessToken: string
},
): Promise<void> => {
context.res = result(context)(connectionInfo)
}
const getSignalRConnectionInfo =
(signalRConnectionInfo: FunctionInput): HttpHandler =>
async (_, context) => {
const connectionInfo = context.extraInputs.get(signalRConnectionInfo) as {
url: string
accessToken: string
}
return result(context)(connectionInfo)
}

export default getSignalRConnectionInfo
2 changes: 0 additions & 2 deletions getSignalRConnectionInfo/handler.mjs

This file was deleted.

16 changes: 16 additions & 0 deletions getSignalRConnectionInfo/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { app, input } from '@azure/functions'
import handler from './getSignalRConnectionInfo.js'

const connectionInfo = input.generic({
type: 'signalRConnectionInfo',
hubName: 'deviceUpdates',
connectionStringSetting: 'SignalRConnectionString',
})

app.http('getSignalRConnectionInfo', {
methods: ['GET'],
route: 'signalRConnectionInfo',
authLevel: 'anonymous',
extraInputs: [connectionInfo],
handler: handler(connectionInfo),
})
21 changes: 0 additions & 21 deletions publishDeviceUpdatesToSignalR/function.json

This file was deleted.

2 changes: 0 additions & 2 deletions publishDeviceUpdatesToSignalR/handler.mjs

This file was deleted.

17 changes: 17 additions & 0 deletions publishDeviceUpdatesToSignalR/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { app, output } from '@azure/functions'
import handler from './publishDeviceUpdatesToSignalR.js'

const signalROutput = output.generic({
type: 'signalR',
hubName: 'deviceUpdates',
connectionStringSetting: 'SignalRConnectionString',
})

app.eventHub('publishDeviceUpdatesToSignalR', {
cardinality: 'many',
eventHubName: '%IOTHUB_EVENTS_EVENT_HUB_NAME%',
connection: 'IOTHUB_EVENTS_CONNECTION_STRING',
consumerGroup: 'publishdeviceupdates',
extraOutputs: [signalROutput],
handler: handler(signalROutput),
})
164 changes: 88 additions & 76 deletions publishDeviceUpdatesToSignalR/publishDeviceUpdatesToSignalR.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1,107 @@
import { AzureFunction, Context } from '@azure/functions'
import type { EventHubHandler, FunctionOutput } from '@azure/functions'
import { DeviceUpdate, TwinChangeEvent } from '../lib/iotMessages.js'
import { log } from '../lib/log.js'

/**
* Publishes Device Twin Update to SignalR so the web application can receive real-time notifications
*/
const publishDeviceUpdatesToSignalR: AzureFunction = async (
context: Context,
updates: DeviceUpdate[],
): Promise<void> => {
log(context)({
messages: updates,
systemPropertiesArray: context.bindingData.systemPropertiesArray,
propertiesArray: context.bindingData.propertiesArray,
})
const publishDeviceUpdatesToSignalR =
(signalROutput: FunctionOutput): EventHubHandler =>
async (eventMessages, context) => {
const updates = eventMessages as DeviceUpdate[]

const signalRMessages = []

const addProperties = (message: DeviceUpdate, k: number) => ({
message,
systemProperties: context.bindingData.systemPropertiesArray[k],
propertiesArray: context.bindingData.propertiesArray[k],
})

const reportedUpdates = updates
.map(addProperties)
.filter(
({ systemProperties }) =>
systemProperties['iothub-message-source'] === 'twinChangeEvents',
const systemPropertiesArray = Array.isArray(
context.triggerMetadata?.systemPropertiesArray,
)
.filter(
({ message }) =>
(message as TwinChangeEvent)?.properties?.reported ??
(message as TwinChangeEvent)?.properties?.desired,
? context.triggerMetadata?.systemPropertiesArray
: []
const propertiesArray = Array.isArray(
context.triggerMetadata?.propertiesArray,
)
.map(({ message, systemProperties }) => ({
deviceId: systemProperties['iothub-connection-device-id'],
state: {
reported: (message as TwinChangeEvent)?.properties?.reported,
desired: (message as TwinChangeEvent)?.properties?.desired,
},
}))
? context.triggerMetadata?.propertiesArray
: []

if (reportedUpdates.length) {
signalRMessages.push(
...reportedUpdates.map((update) =>
// Send to a per-device "topic", so clients can subscribe to updates for a specific device
({
target: `deviceState:${update.deviceId}`,
arguments: [update],
}),
),
)
}
log(context)({
messages: updates,
systemPropertiesArray,
propertiesArray,
})

const messages = updates
.map(addProperties)
.filter(
({ systemProperties }) =>
systemProperties['iothub-message-source'] === 'Telemetry',
)
.map(({ message, systemProperties, propertiesArray }) => ({
deviceId: systemProperties['iothub-connection-device-id'],
const signalRMessages: Record<string, unknown>[] = []

const addProperties = (message: DeviceUpdate, k: number) => ({
message,
propertiesArray,
}))
systemProperties: systemPropertiesArray?.[k],
propertiesArray: propertiesArray?.[k],
})

if (messages.length) {
signalRMessages.push(
...messages.map((message) =>
// Send to a per-device "topic", so clients can subscribe to updates for a specific device
({
target: `deviceMessage:${message.deviceId}`,
arguments: [message],
}),
),
)
messages.forEach((message) => {
// Send to a per-action "topic", so clients can subscribe to updates for a specific action
const reportedUpdates = updates
.map(addProperties)
.filter(
({ systemProperties }) =>
systemProperties['iothub-message-source'] === 'twinChangeEvents',
)
.filter(
({ message }) =>
(message as TwinChangeEvent)?.properties?.reported ??
(message as TwinChangeEvent)?.properties?.desired,
)
.map(({ message, systemProperties }) => ({
deviceId: systemProperties['iothub-connection-device-id'],
state: {
reported: (message as TwinChangeEvent)?.properties?.reported,
desired: (message as TwinChangeEvent)?.properties?.desired,
},
}))

if (reportedUpdates.length) {
signalRMessages.push(
...Object.keys(message.message).map((key) => ({
target: `deviceMessage:${key}`,
arguments: [message],
})),
...reportedUpdates.map((update) =>
// Send to a per-device "topic", so clients can subscribe to updates for a specific device
({
target: `deviceState:${update.deviceId}`,
arguments: [update],
}),
),
)
})
}
}

log(context)({ signalRMessages })
const messages = updates
.map(addProperties)
.filter(
({ systemProperties }) =>
systemProperties['iothub-message-source'] === 'Telemetry',
)
.map(({ message, systemProperties, propertiesArray }) => ({
deviceId: systemProperties['iothub-connection-device-id'],
message,
propertiesArray,
}))

context.bindings.signalRMessages = signalRMessages
}
if (messages.length) {
signalRMessages.push(
...messages.map((message) =>
// Send to a per-device "topic", so clients can subscribe to updates for a specific device
({
target: `deviceMessage:${message.deviceId}`,
arguments: [message],
}),
),
)
messages.forEach((message) => {
// Send to a per-action "topic", so clients can subscribe to updates for a specific action
signalRMessages.push(
...Object.keys(message.message).map((key) => ({
target: `deviceMessage:${key}`,
arguments: [message],
})),
)
})
}

log(context)({ signalRMessages })

context.extraOutputs.set(signalROutput, signalRMessages)
}

export default publishDeviceUpdatesToSignalR
6 changes: 1 addition & 5 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
{
"extends": "@nordicsemiconductor/asset-tracker-cloud-code-style/tsconfig.json",
"include": ["**/*.ts"],
"exclude": [
"dist",
"getSignalRConnectionInfo",
"publishDeviceUpdatesToSignalR"
],
"exclude": ["dist"],
"compilerOptions": {
"outDir": "dist/",
"moduleResolution": "node",
Expand Down

0 comments on commit 2e6c6bd

Please sign in to comment.