Skip to content

Commit cfb0f4a

Browse files
Create external api
1 parent 999316f commit cfb0f4a

File tree

4 files changed

+122
-2
lines changed

4 files changed

+122
-2
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"serve": "vite preview",
2020
"test:ci": "vitest --coverage --run",
2121
"test:unit": "vitest",
22-
"typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false"
22+
"typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
23+
"build:lib": "BUILD_MODE=library vite build"
2324
},
2425
"dependencies": {
2526
"@fortawesome/fontawesome-svg-core": "^6.4.0",

src/libs/external-api/api.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { CallbackRateLimiter } from './callback-rate-limiter'
2+
3+
/**
4+
* Current version of the Cockpit Widget API
5+
*/
6+
export const COCKPIT_WIDGET_API_VERSION = '0.0.0'
7+
8+
/**
9+
* Listens to updates for a specific datalake variable.
10+
* This function sets up a message listener that receives updates from the parent window
11+
* and forwards them to the callback function, respecting the specified rate limit.
12+
* @param {string} variable - The name of the datalake variable to listen to
13+
* @param {Function} callback - The function to call when the variable is updated
14+
* @param {number} maxRateHz - The maximum rate (in Hz) at which updates should be received. Default is 10 Hz
15+
* @example
16+
* ```typescript
17+
* // Listen to updates at 5Hz
18+
* listenToDatalakeVariable('temperature', (value) => {
19+
* console.log('Temperature:', value);
20+
* }, 5);
21+
* ```
22+
*/
23+
export function listenToDatalakeVariable(variable: string, callback: (data: any) => void, maxRateHz = 10): void {
24+
// Convert Hz to minimum interval in milliseconds
25+
const minIntervalMs = 1000 / maxRateHz
26+
const rateLimiter = new CallbackRateLimiter(minIntervalMs)
27+
28+
const message = {
29+
type: 'cockpit:listenToDatalakeVariables',
30+
variable: variable,
31+
maxRateHz: maxRateHz,
32+
}
33+
window.parent.postMessage(message, '*')
34+
35+
window.addEventListener('message', function handler(event) {
36+
if (event.data.type === 'cockpit:datalakeVariable' && event.data.variable === variable) {
37+
// Only call callback if we haven't exceeded the rate limit
38+
if (rateLimiter.canCall(variable)) {
39+
callback(event.data.value)
40+
}
41+
}
42+
})
43+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* A simple rate limiter for callbacks that ensures a minimum time interval between calls
3+
*/
4+
export class CallbackRateLimiter {
5+
private lastCallTimes = new Map<string, number>()
6+
7+
/**
8+
* Creates a new CallbackRateLimiter
9+
* @param {number} minIntervalMs - The minimum time (in milliseconds) that must pass between calls
10+
*/
11+
constructor(private minIntervalMs: number) {}
12+
13+
/**
14+
* Checks if enough time has passed to allow another call
15+
* @param {string} key - Unique identifier for the callback being rate limited
16+
* @returns {boolean} true if enough time has passed since the last call, false otherwise
17+
*/
18+
public canCall(key: string): boolean {
19+
const now = Date.now()
20+
const lastCall = this.lastCallTimes.get(key) || 0
21+
const timeSinceLastCall = now - lastCall
22+
23+
if (timeSinceLastCall >= this.minIntervalMs) {
24+
this.lastCallTimes.set(key, now)
25+
return true
26+
}
27+
28+
return false
29+
}
30+
}

vite.config.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import { getVersion } from './src/libs/non-browser-utils'
1010
// Check if we're running in Electron mode or building the application
1111
const isElectron = process.env.ELECTRON === 'true'
1212
const isBuilding = process.argv.includes('build')
13+
const isLibrary = process.env.BUILD_MODE === 'library'
1314

14-
export default defineConfig({
15+
// Base configuration that will be merged
16+
const baseConfig = {
1517
plugins: [
1618
(isElectron || isBuilding) &&
1719
electron([
@@ -70,4 +72,48 @@ export default defineConfig({
7072
server: {
7173
host: '0.0.0.0',
7274
},
75+
}
76+
77+
// Library-specific configuration
78+
const libraryConfig = {
79+
build: {
80+
lib: {
81+
entry: path.resolve(__dirname, 'src/libs/external-api/api.ts'),
82+
name: 'CockpitAPI',
83+
formats: ['es', 'umd', 'iife'],
84+
fileName: (format: string) => {
85+
switch (format) {
86+
case 'iife':
87+
return 'cockpit-external-api.browser.js'
88+
case 'umd':
89+
return 'cockpit-external-api.umd.js'
90+
default:
91+
return `cockpit-external-api.${format}.js`
92+
}
93+
},
94+
},
95+
rollupOptions: {
96+
external: ['vue', 'vuetify'],
97+
output: {
98+
globals: {
99+
vue: 'Vue',
100+
vuetify: 'Vuetify',
101+
},
102+
},
103+
},
104+
outDir: 'dist/lib', // Separate output directory for library builds
105+
minify: false, // Disable minification for now
106+
},
107+
}
108+
109+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
110+
export default defineConfig((_configEnv) => {
111+
if (isLibrary) {
112+
// For library builds, merge the base config with library-specific settings
113+
return {
114+
...baseConfig,
115+
...libraryConfig,
116+
} as any
117+
}
118+
return baseConfig as any
73119
})

0 commit comments

Comments
 (0)