first commit

This commit is contained in:
Suherdy Yacob 2026-06-02 20:27:43 +07:00
commit 68b9860855
5 changed files with 126 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.pyc
*.pyo
*~
__pycache__/

10
README.md Normal file
View File

@ -0,0 +1,10 @@
POS IndexedDB Patch
===================
This module patches Odoo's bus Logger to avoid IndexedDB connection crashes.
Features
--------
- Automatically recreates database connection if closing or closed.
- Adds error safety handlers to log writes and reads.
- Works in both browser thread and shared/web worker threads.

2
__init__.py Normal file
View File

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

26
__manifest__.py Normal file
View File

@ -0,0 +1,26 @@
{
'name': 'POS IndexedDB Patch',
'version': '19.0.1.0.0',
'category': 'Technical',
'summary': 'Patches IndexedDB Logger connection issues in bus worker and main thread',
'description': """
This module patches the Logger class inside the bus module to handle IndexedDB connection closures gracefully, preventing POS crashes when the browser suspends/hibernates database connections.
""",
'author': 'Suherdy Yacob',
'depends': ['bus', 'point_of_sale'],
'data': [],
'assets': {
'web.assets_backend': [
'pos_indexeddb_patch/static/src/workers/patch_logger.js',
],
'web.assets_frontend': [
'pos_indexeddb_patch/static/src/workers/patch_logger.js',
],
'bus.websocket_worker_assets': [
'pos_indexeddb_patch/static/src/workers/patch_logger.js',
],
},
'installable': True,
'auto_install': False,
'license': 'LGPL-3',
}

View File

@ -0,0 +1,84 @@
import { Logger } from "@bus/workers/bus_worker_utils";
function patchLogger(LoggerClass) {
if (!LoggerClass || LoggerClass.prototype._patchedByIndexedDbPatch) {
return;
}
LoggerClass.prototype._patchedByIndexedDbPatch = true;
LoggerClass.prototype._ensureDatabaseAvailable = async function() {
if (this._db) {
try {
this._db.transaction("logs", "readonly");
} catch (e) {
this._db = null;
}
}
if (this._db) {
return;
}
return new Promise((res, rej) => {
const request = indexedDB.open(this._name, 1);
request.onsuccess = (event) => {
this._db = event.target.result;
this._db.onversionchange = () => {
this._db.close();
this._db = null;
};
this._db.onclose = () => {
this._db = null;
};
res();
};
request.onupgradeneeded = (event) => {
if (!event.target.result.objectStoreNames.contains("logs")) {
const store = event.target.result.createObjectStore("logs", {
autoIncrement: true,
});
store.createIndex("timestamp", "timestamp", { unique: false });
}
};
request.onerror = rej;
});
};
LoggerClass.prototype.log = async function(message) {
try {
await this._ensureDatabaseAvailable();
if (!this._db) {
return;
}
const transaction = this._db.transaction("logs", "readwrite");
const store = transaction.objectStore("logs");
const addRequest = store.add({ timestamp: Date.now(), message });
return new Promise((res, rej) => {
addRequest.onsuccess = res;
addRequest.onerror = rej;
});
} catch (error) {
console.error("Failed to write log to IndexedDB:", error);
}
};
LoggerClass.prototype.getLogs = async function() {
try {
await LoggerClass.gcOutdatedLogs();
await this._ensureDatabaseAvailable();
if (!this._db) {
return [];
}
const transaction = this._db.transaction("logs", "readonly");
const store = transaction.objectStore("logs");
const request = store.getAll();
return new Promise((res, rej) => {
request.onsuccess = (ev) => res(ev.target.result.map(({ message }) => message));
request.onerror = rej;
});
} catch (error) {
console.error("Failed to retrieve logs from IndexedDB:", error);
return [];
}
};
}
patchLogger(Logger);