Skip to content

Commit

Permalink
feat(core): add script execution functionality with uvm integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Red-Asuka committed Jan 6, 2025
1 parent 8bc9b30 commit a9a9a6f
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 5 deletions.
3 changes: 3 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
"test:dev": "vitest"
},
"dependencies": {
"buffer": "^6.0.3",
"uuid": "^11.0.3",
"uvm": "^4.0.0",
"vitest": "^2.1.4"
},
"devDependencies": {
"@types/mqttx": "workspace:^",
"@types/uuid": "^10.0.0",
"@vitest/coverage-istanbul": "^2.1.4",
"typescript": "~5.6.3"
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './getMessageId'
export * from './sandbox'
49 changes: 49 additions & 0 deletions packages/core/src/utils/sandbox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { MessageType } from 'mqttx'
// eslint-disable-next-line unicorn/prefer-node-protocol
import { Buffer } from 'buffer'
// @ts-expect-error uvm is not defined
import uvm from 'uvm'

export function executeScript(opts: {
script: string
payload: string
messageType: MessageType
index?: number
}): Promise<Buffer> {
return new Promise((resolve, reject) => {
uvm.spawn(
{
bootCode: `
bridge.on('runScript', function ({ script, payload, messageType, index }) {
try {
function execute(callback) {
return callback(payload, messageType, index);
};
bridge.dispatch(
'scriptResult',
Function('execute', 'payload', 'messageType', 'index', script)(execute, payload, messageType, index)
);
} catch (error) {
bridge.dispatch('scriptError', error.message);
}
});
`,
bootTimeout: 1000,
dispatchTimeout: 1000,
},
(err: any, context: any) => {
if (err) reject(err)

context.on('scriptResult', (result: any) => {
resolve(Buffer.from(result?.toString() ?? ''))
})

context.on('scriptError', (error?: string) => {
reject(new Error(error))
})

context.dispatch('runScript', opts)
},
)
})
}
4 changes: 4 additions & 0 deletions packages/types/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export type Protocol = 'mqtt' | 'mqtts'

export type QoS = 0 | 1 | 2

export type PayloadType = 'Plaintext' | 'Base64' | 'JSON' | 'Hex' | 'CBOR' | 'MsgPack'

export type MessageType = 'all' | 'received' | 'publish'

export type Lang = 'en' | 'zh' | 'ja' | 'hu' | 'tr'

export type Theme = 'light' | 'dark' | 'night'
Expand Down
32 changes: 27 additions & 5 deletions packages/ui/src/components/script/TabFunction.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import type { ScriptFunction } from 'mqttx'
import { executeScript } from '@mqttx/core'
import { useScriptFunctionStore } from '../../stores'
const { scriptFunctions } = storeToRefs(useScriptFunctionStore())
Expand Down Expand Up @@ -31,18 +32,39 @@ const defaultFunction: Record<string, { input: string, content: string }> = {
input: JSON.stringify({ msg: 'hello' }, null, 2),
content: `/**
* @description: default script
* @param {any} value - Payload
* @param {string} msgType - Message type, value is 'received' or 'publish'
* @param {string} message - Message payload
* @param {string} messageType - Message type, value is 'received' or 'publish'
* @param {number} index - Index of the message, valid only when script is used in the publish message and timed message is enabled
* @return {any} - Payload after script processing
*/
function handlePayload(value, msgType, index) {
return value.msg
function handlePayload(message, messageType, index) {
const payload = JSON.parse(message)
return payload.msg
}
execute(handlePayload)`,
return execute(handlePayload)`,
},
}
onMounted(async () => {
await executeScript({
script: defaultFunction[currentLang.value].content,
payload: defaultFunction[currentLang.value].input,
messageType: 'received',
index: 0,
})
.then((result) => {
console.log(result)
})
.catch((error) => {
if (error instanceof Error) {
ElMessage({
message: error.toString(),
type: 'error',
plain: true,
})
}
})
})
const functionContent = ref('')
watch([currentLang, currentFunction], () => {
functionContent.value = currentFunction.value ? currentFunction.value.content : defaultFunction[currentLang.value].content
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a9a9a6f

Please sign in to comment.