iobroker.mywebui 1.42.30 → 1.42.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "mywebui",
4
- "version": "1.42.30",
4
+ "version": "1.42.32",
5
5
  "titleLang": {
6
6
  "en": "mywebui",
7
7
  "de": "mywebui",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.mywebui",
3
- "version": "1.42.30",
3
+ "version": "1.42.32",
4
4
  "description": "ioBroker mywebui - Custom edited mywebui by gokturk413 with 3D Editor",
5
5
  "type": "module",
6
6
  "main": "dist/backend/main.js",
@@ -587,19 +587,51 @@ export class IobrokerHandler {
587
587
  }
588
588
  async _getObjectFromFile(name) {
589
589
  const file = await this.connection.readFile(this.namespaceFiles, name, false);
590
+ let bytes;
590
591
  if (file.mimeType == 'application/json' || file.mimeType == 'text/javascript') {
591
592
  return JSON.parse(file.file);
593
+ } else if (file.mimeType == 'application/octet-stream' && file.file instanceof ArrayBuffer) {
594
+ bytes = new Uint8Array(file.file);
595
+ } else {
596
+ bytes = Uint8Array.from(file.file.data);
592
597
  }
593
- if (file.mimeType == "application/octet-stream" && file.file instanceof ArrayBuffer) {
594
- const dec = new TextDecoder();
595
- return JSON.parse(dec.decode(file.file));
598
+ // Gzip magic bytes 1f 8b decompress transparently
599
+ if (bytes[0] === 0x1f && bytes[1] === 0x8b && window.DecompressionStream) {
600
+ bytes = await this._gunzipBytes(bytes);
596
601
  }
597
- const dec = new TextDecoder();
598
- return JSON.parse(dec.decode(Uint8Array.from(file.file.data)));
602
+ return JSON.parse(new TextDecoder().decode(bytes));
599
603
  }
600
604
  async _saveObjectToFile(obj, name) {
601
- const enc = new TextEncoder();
602
- await this.connection.writeFile64(this.namespaceFiles, name, enc.encode(JSON.stringify(obj)));
605
+ const bytes = new TextEncoder().encode(JSON.stringify(obj));
606
+ // Compress files >512 KB to prevent WebSocket message overflow
607
+ if (bytes.length > 512 * 1024 && window.CompressionStream) {
608
+ const compressed = await this._gzipBytes(bytes);
609
+ await this.connection.writeFile64(this.namespaceFiles, name, compressed.buffer);
610
+ } else {
611
+ await this.connection.writeFile64(this.namespaceFiles, name, bytes);
612
+ }
613
+ }
614
+ async _gzipBytes(bytes) {
615
+ const cs = new CompressionStream('gzip');
616
+ const w = cs.writable.getWriter();
617
+ w.write(bytes); w.close();
618
+ const r = cs.readable.getReader();
619
+ const chunks = []; let res;
620
+ while (!(res = await r.read()).done) chunks.push(res.value);
621
+ const out = new Uint8Array(chunks.reduce((s, c) => s + c.length, 0));
622
+ let off = 0; for (const c of chunks) { out.set(c, off); off += c.length; }
623
+ return out;
624
+ }
625
+ async _gunzipBytes(bytes) {
626
+ const ds = new DecompressionStream('gzip');
627
+ const w = ds.writable.getWriter();
628
+ w.write(bytes); w.close();
629
+ const r = ds.readable.getReader();
630
+ const chunks = []; let res;
631
+ while (!(res = await r.read()).done) chunks.push(res.value);
632
+ const out = new Uint8Array(chunks.reduce((s, c) => s + c.length, 0));
633
+ let off = 0; for (const c of chunks) { out.set(c, off); off += c.length; }
634
+ return out;
603
635
  }
604
636
  async _saveBinaryToFile(binary, name) {
605
637
  await this.connection.writeFile64(this.namespaceFiles, name, await binary.arrayBuffer());
@@ -27,6 +27,7 @@ export class IobrokerWebui3DScreenViewer extends BaseCustomWebComponentConstruct
27
27
 
28
28
  disconnectedCallback() {
29
29
  this._animating = false;
30
+ if (this._cleanup) { this._cleanup(); this._cleanup = null; }
30
31
  if (this._renderer) { this._renderer.dispose(); this._renderer.domElement.remove(); this._renderer = null; }
31
32
  window.removeEventListener('resize', this._onResize);
32
33
  }
@@ -109,15 +110,49 @@ export class IobrokerWebui3DScreenViewer extends BaseCustomWebComponentConstruct
109
110
  const controls = new OrbitControls(camera, renderer.domElement);
110
111
  controls.enableDamping = true;
111
112
 
113
+ // Script context helpers
114
+ const frameCallbacks = [];
115
+ const selectCallbacks = [];
116
+ const _subscriptions = [];
117
+
118
+ const onFrame = (fn) => frameCallbacks.push(fn);
119
+ const onSelect = (fn) => selectCallbacks.push(fn);
120
+ const log = (...args) => console.log('[3D]', ...args);
121
+
122
+ const setState = (id, val) => {
123
+ try { iobrokerHandler.setState(id, val); } catch (_) {}
124
+ };
125
+ const getState = async (id) => {
126
+ try { return await iobrokerHandler.getState(id); } catch (_) { return null; }
127
+ };
128
+ const subscribe = (id, cb) => {
129
+ try {
130
+ const unsub = iobrokerHandler.subscribeState(id, cb);
131
+ _subscriptions.push(unsub);
132
+ return unsub;
133
+ } catch (_) { return () => {}; }
134
+ };
135
+
136
+ const assets = new Map();
137
+ const mixers = new Map();
138
+
112
139
  // Run scene script if present
113
140
  if (sceneData.script) {
114
141
  try {
115
- const fn = new Function('THREE', 'scene', 'camera', 'renderer', 'controls', sceneData.script);
116
- fn(THREE, scene, camera, renderer, controls);
142
+ const fn = new Function(
143
+ 'THREE', 'scene', 'camera', 'renderer', 'controls',
144
+ 'onFrame', 'onSelect', 'setState', 'getState', 'subscribe',
145
+ 'assets', 'mixers', 'log',
146
+ sceneData.script
147
+ );
148
+ fn(THREE, scene, camera, renderer, controls,
149
+ onFrame, onSelect, setState, getState, subscribe,
150
+ assets, mixers, log);
117
151
  } catch (e) { console.warn('3D scene script error:', e); }
118
152
  }
119
153
 
120
154
  this._animating = true;
155
+ this._cleanup = () => { _subscriptions.forEach(u => { try { u(); } catch (_) {} }); };
121
156
  this._onResize = () => {
122
157
  const vw = viewport.clientWidth, vh = viewport.clientHeight;
123
158
  camera.aspect = vw / vh;
@@ -126,13 +161,17 @@ export class IobrokerWebui3DScreenViewer extends BaseCustomWebComponentConstruct
126
161
  };
127
162
  window.addEventListener('resize', this._onResize);
128
163
 
129
- const animate = () => {
164
+ let _lastTime = 0;
165
+ const animate = (ts) => {
130
166
  if (!this._animating) return;
131
167
  requestAnimationFrame(animate);
132
- controls.update();
168
+ const dt = _lastTime ? (ts - _lastTime) / 1000 : 0;
169
+ _lastTime = ts;
170
+ controls.update(dt);
171
+ for (const cb of frameCallbacks) { try { cb(dt, ts / 1000); } catch (_) {} }
133
172
  renderer.render(scene, camera);
134
173
  };
135
- animate();
174
+ animate(0);
136
175
 
137
176
  } catch (err) {
138
177
  console.error('3D Viewer error:', err);