@things-factory/board-service 9.0.33 → 9.0.35
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/dist-server/controllers/headless-pdf-to-image.js +9 -7
- package/dist-server/controllers/headless-pdf-to-image.js.map +1 -1
- package/dist-server/controllers/headless-pool-for-board.d.ts +18 -1
- package/dist-server/controllers/headless-pool-for-board.js +31 -58
- package/dist-server/controllers/headless-pool-for-board.js.map +1 -1
- package/dist-server/controllers/headless-pool-for-label.d.ts +19 -1
- package/dist-server/controllers/headless-pool-for-label.js +45 -72
- package/dist-server/controllers/headless-pool-for-label.js.map +1 -1
- package/dist-server/service/board/board-mutation.js +3 -0
- package/dist-server/service/board/board-mutation.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -9
|
@@ -3,20 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.pdfToImage = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const crypto_1 = tslib_1.__importDefault(require("crypto"));
|
|
6
|
-
const
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
7
|
const { Readable } = require('stream');
|
|
8
8
|
const ejs = require('ejs');
|
|
9
9
|
const pdfToImage = async ({ pdfPath, fileName, extension = 'png', quality = 2, defaultViewport = null }) => {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
// Use headless pool instead of direct puppeteer.launch
|
|
11
|
+
const pool = (0, shell_1.getOrCreateHeadlessPool)('board-pdf', {
|
|
12
|
+
min: 1,
|
|
13
|
+
max: 3,
|
|
12
14
|
args: [
|
|
13
15
|
'--disable-web-security',
|
|
14
16
|
'--disable-features=IsolateOrigins',
|
|
15
17
|
'--disable-site-isolation-trials',
|
|
16
18
|
'--no-sandbox'
|
|
17
|
-
]
|
|
18
|
-
defaultViewport
|
|
19
|
+
]
|
|
19
20
|
});
|
|
21
|
+
const browser = await pool.acquire();
|
|
20
22
|
try {
|
|
21
23
|
const protocol = 'http';
|
|
22
24
|
const host = 'localhost';
|
|
@@ -39,7 +41,7 @@ const pdfToImage = async ({ pdfPath, fileName, extension = 'png', quality = 2, d
|
|
|
39
41
|
const stream = new Readable();
|
|
40
42
|
stream.push(screenshot);
|
|
41
43
|
stream.push(null);
|
|
42
|
-
await
|
|
44
|
+
await pool.release(browser);
|
|
43
45
|
// file upload 형태로 return
|
|
44
46
|
return {
|
|
45
47
|
filename: `${fileName}.${extension}`,
|
|
@@ -49,7 +51,7 @@ const pdfToImage = async ({ pdfPath, fileName, extension = 'png', quality = 2, d
|
|
|
49
51
|
};
|
|
50
52
|
}
|
|
51
53
|
catch (e) {
|
|
52
|
-
await
|
|
54
|
+
await pool.release(browser);
|
|
53
55
|
console.log('Error creating thumbnail', e);
|
|
54
56
|
throw new Error('Error creating thumbnail');
|
|
55
57
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless-pdf-to-image.js","sourceRoot":"","sources":["../../server/controllers/headless-pdf-to-image.ts"],"names":[],"mappings":";;;;AAAA,4DAA2B;
|
|
1
|
+
{"version":3,"file":"headless-pdf-to-image.js","sourceRoot":"","sources":["../../server/controllers/headless-pdf-to-image.ts"],"names":[],"mappings":";;;;AAAA,4DAA2B;AAC3B,iDAA+D;AAE/D,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;AACtC,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;AAEnB,MAAM,UAAU,GAAG,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,GAAG,KAAK,EAAE,OAAO,GAAG,CAAC,EAAE,eAAe,GAAG,IAAI,EAAE,EAAE,EAAE;IAChH,uDAAuD;IACvD,MAAM,IAAI,GAAG,IAAA,+BAAuB,EAAC,WAAW,EAAE;QAChD,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,CAAC;QACN,IAAI,EAAE;YACJ,wBAAwB;YACxB,mCAAmC;YACnC,iCAAiC;YACjC,cAAc;SACf;KACF,CAAC,CAAA;IAEF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;IAEpC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,CAAA;QACvB,MAAM,IAAI,GAAG,WAAW,CAAA;QACxB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAA;QAC7B,MAAM,MAAM,GAAG,GAAG,QAAQ,MAAM,IAAI,IAAI,IAAI,GAAG,OAAO,EAAE,CAAA;QAExD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;QACpC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,kBAAkB,EAAE,EAAE;YAClD,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;YACzB,KAAK,EAAE,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;SAC9C,CAAC,CAAA;QAEF,uBAAuB;QACvB,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC,CAAA;QAC1D,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAC/B,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;QACrB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YACvC,IAAI,EAAE,SAAS;YACf,cAAc,EAAE,IAAI;SACrB,CAAC,CAAA;QAEF,6CAA6C;QAC7C,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAA;QAC7B,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACvB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAEjB,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAE3B,yBAAyB;QACzB,OAAO;YACL,QAAQ,EAAE,GAAG,QAAQ,IAAI,SAAS,EAAE;YACpC,QAAQ,EAAE,SAAS,SAAS,EAAE;YAC9B,QAAQ,EAAE,MAAM;YAChB,gBAAgB,EAAE,GAAG,EAAE,CAAC,MAAM;SAC/B,CAAA;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAC3B,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,CAAC,CAAC,CAAA;QAC1C,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;IAC7C,CAAC;AACH,CAAC,CAAA;AAvDY,QAAA,UAAU,cAuDtB;AAED,SAAS,kBAAkB;IACzB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CN,CAAA;AACH,CAAC","sourcesContent":["import crypto from 'crypto'\nimport { getOrCreateHeadlessPool } from '@things-factory/shell'\n\nconst { Readable } = require('stream')\nconst ejs = require('ejs')\n\nexport const pdfToImage = async ({ pdfPath, fileName, extension = 'png', quality = 2, defaultViewport = null }) => {\n // Use headless pool instead of direct puppeteer.launch\n const pool = getOrCreateHeadlessPool('board-pdf', {\n min: 1,\n max: 3,\n args: [\n '--disable-web-security',\n '--disable-features=IsolateOrigins', \n '--disable-site-isolation-trials',\n '--no-sandbox'\n ]\n })\n\n const browser = await pool.acquire()\n\n try {\n const protocol = 'http'\n const host = 'localhost'\n const port = process.env.PORT\n const pdfUrl = `${protocol}://${host}:${port}${pdfPath}`\n\n const page = await browser.newPage()\n const html = await ejs.render(getPdfHtmlTemplate(), {\n data: { pdfUrl, quality },\n nonce: crypto.randomBytes(16).toString('hex')\n })\n\n // 페이지 로딩시 까지 기다리고 스크린샷\n await page.setContent(html, { waitUntil: 'networkidle0' })\n await page.waitForNetworkIdle()\n await page.$('#page')\n const screenshot = await page.screenshot({\n type: extension,\n omitBackground: true\n })\n\n // graphql fileupload형태로 return을 위해 stream 생성\n const stream = new Readable()\n stream.push(screenshot)\n stream.push(null)\n\n await pool.release(browser)\n\n // file upload 형태로 return\n return {\n filename: `${fileName}.${extension}`,\n mimetype: `image/${extension}`,\n encoding: '7bit',\n createReadStream: () => stream\n }\n } catch (e) {\n await pool.release(browser)\n console.log('Error creating thumbnail', e)\n throw new Error('Error creating thumbnail')\n }\n}\n\nfunction getPdfHtmlTemplate() {\n return `\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" />\n\n <style nonce=\"<%= nonce %>\">\n body {\n width: 100vw;\n height: 100vh;\n margin: 0;\n }\n #page {\n display: flex;\n width: 100%;\n height: 100%;\n }\n </style>\n\n </head>\n <body>\n <canvas id=\"page\"></canvas>\n <script src=\"https://unpkg.com/pdfjs-dist@2.0.489/build/pdf.min.js\"></script>\n <script nonce=\"<%= nonce %>\">\n ;(async () => {\n const pdf = await pdfjsLib.getDocument('<%= data.pdfUrl %>')\n const page = await pdf.getPage(1)\n const viewport = page.getViewport('<%= data.quality %>')\n const canvas = document.getElementById('page')\n const context = canvas.getContext('2d')\n\n canvas.height = viewport.height\n canvas.width = viewport.width\n\n const renderContext = {\n canvasContext: context,\n viewport: viewport\n }\n\n page.render(renderContext)\n })()\n </script>\n </body>\n </html>\n `\n}\n"]}
|
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Board Service Headless Pool
|
|
3
|
+
* Using the unified headless pool system from @things-factory/shell
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Get the board headless pool
|
|
7
|
+
* @returns Pool instance with acquire/release methods
|
|
8
|
+
*/
|
|
9
|
+
export declare function getHeadlessPool(): {
|
|
10
|
+
acquire: () => Promise<any>;
|
|
11
|
+
release: (resource: any) => Promise<void>;
|
|
12
|
+
size: number;
|
|
13
|
+
available: number;
|
|
14
|
+
borrowed: number;
|
|
15
|
+
pending: number;
|
|
16
|
+
max: number;
|
|
17
|
+
min: number;
|
|
18
|
+
};
|
|
@@ -1,64 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Board Service Headless Pool
|
|
4
|
+
* Using the unified headless pool system from @things-factory/shell
|
|
5
|
+
*/
|
|
2
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
7
|
exports.getHeadlessPool = getHeadlessPool;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const shell_1 = require("@things-factory/shell");
|
|
9
|
+
// Create the board pool instance
|
|
10
|
+
const boardPool = (0, shell_1.getOrCreateHeadlessPool)('board', {
|
|
11
|
+
min: 2,
|
|
12
|
+
max: 10,
|
|
13
|
+
args: [
|
|
14
|
+
...shell_1.HEADLESS_POOL_ARGUMENT_SETS.basic,
|
|
15
|
+
...shell_1.HEADLESS_POOL_ARGUMENT_SETS.keychain_safe
|
|
16
|
+
],
|
|
17
|
+
acquireTimeoutMillis: 15000,
|
|
18
|
+
testOnBorrow: true,
|
|
19
|
+
enableCleanup: true
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Get the board headless pool
|
|
23
|
+
* @returns Pool instance with acquire/release methods
|
|
24
|
+
*/
|
|
14
25
|
function getHeadlessPool() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//@ts-ignore
|
|
26
|
-
.version()
|
|
27
|
-
.then(_ => true)
|
|
28
|
-
.catch(_ => false)
|
|
29
|
-
]);
|
|
30
|
-
},
|
|
31
|
-
destroy(browser) {
|
|
32
|
-
//@ts-ignore
|
|
33
|
-
return browser.close();
|
|
34
|
-
}
|
|
35
|
-
}, {
|
|
36
|
-
min: 2,
|
|
37
|
-
max: 10,
|
|
38
|
-
testOnBorrow: true,
|
|
39
|
-
acquireTimeoutMillis: 15000
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return headlessPool;
|
|
43
|
-
}
|
|
44
|
-
const CHROMIUM_PATH = env_1.config.get('CHROMIUM_PATH');
|
|
45
|
-
async function initializeChromium() {
|
|
46
|
-
try {
|
|
47
|
-
if (!puppeteer) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
var launchSetting = {
|
|
51
|
-
args: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],
|
|
52
|
-
headless: 'shell'
|
|
53
|
-
};
|
|
54
|
-
if (CHROMIUM_PATH) {
|
|
55
|
-
launchSetting['executablePath'] = CHROMIUM_PATH;
|
|
56
|
-
}
|
|
57
|
-
const browser = await puppeteer.launch(launchSetting);
|
|
58
|
-
return browser;
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
env_1.logger.error(err);
|
|
62
|
-
}
|
|
26
|
+
return {
|
|
27
|
+
acquire: () => boardPool.acquire(),
|
|
28
|
+
release: (resource) => boardPool.release(resource),
|
|
29
|
+
size: 0, // These will be dynamically calculated if needed
|
|
30
|
+
available: 0,
|
|
31
|
+
borrowed: 0,
|
|
32
|
+
pending: 0,
|
|
33
|
+
max: 10,
|
|
34
|
+
min: 2
|
|
35
|
+
};
|
|
63
36
|
}
|
|
64
37
|
//# sourceMappingURL=headless-pool-for-board.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless-pool-for-board.js","sourceRoot":"","sources":["../../server/controllers/headless-pool-for-board.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"headless-pool-for-board.js","sourceRoot":"","sources":["../../server/controllers/headless-pool-for-board.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAqBH,0CAWC;AA9BD,iDAA4F;AAE5F,iCAAiC;AACjC,MAAM,SAAS,GAAG,IAAA,+BAAuB,EAAC,OAAO,EAAE;IACjD,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,EAAE;IACP,IAAI,EAAE;QACJ,GAAG,mCAA2B,CAAC,KAAK;QACpC,GAAG,mCAA2B,CAAC,aAAa;KAC7C;IACD,oBAAoB,EAAE,KAAK;IAC3B,YAAY,EAAE,IAAI;IAClB,aAAa,EAAE,IAAI;CACpB,CAAC,CAAA;AAEF;;;GAGG;AACH,SAAgB,eAAe;IAC7B,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE;QAClC,OAAO,EAAE,CAAC,QAAa,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC;QACvD,IAAI,EAAE,CAAC,EAAE,iDAAiD;QAC1D,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;QACV,GAAG,EAAE,EAAE;QACP,GAAG,EAAE,CAAC;KACP,CAAA;AACH,CAAC","sourcesContent":["/**\n * Board Service Headless Pool\n * Using the unified headless pool system from @things-factory/shell\n */\n\nimport { getOrCreateHeadlessPool, HEADLESS_POOL_ARGUMENT_SETS } from '@things-factory/shell'\n\n// Create the board pool instance\nconst boardPool = getOrCreateHeadlessPool('board', {\n min: 2,\n max: 10,\n args: [\n ...HEADLESS_POOL_ARGUMENT_SETS.basic,\n ...HEADLESS_POOL_ARGUMENT_SETS.keychain_safe\n ],\n acquireTimeoutMillis: 15000,\n testOnBorrow: true,\n enableCleanup: true\n})\n\n/**\n * Get the board headless pool\n * @returns Pool instance with acquire/release methods\n */\nexport function getHeadlessPool() {\n return {\n acquire: () => boardPool.acquire(),\n release: (resource: any) => boardPool.release(resource),\n size: 0, // These will be dynamically calculated if needed\n available: 0,\n borrowed: 0,\n pending: 0,\n max: 10,\n min: 2\n }\n}"]}
|
|
@@ -1 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Label Service Headless Pool
|
|
3
|
+
* Using the unified headless pool system from @things-factory/shell
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Get the label headless pool
|
|
7
|
+
* @returns Pool instance with acquire/release methods
|
|
8
|
+
*/
|
|
9
|
+
export declare function getHeadlessPool(): {
|
|
10
|
+
acquire: () => Promise<any>;
|
|
11
|
+
release: (resource: any) => Promise<void>;
|
|
12
|
+
size: number;
|
|
13
|
+
available: number;
|
|
14
|
+
borrowed: number;
|
|
15
|
+
pending: number;
|
|
16
|
+
max: number;
|
|
17
|
+
min: number;
|
|
18
|
+
clear: () => Promise<void>;
|
|
19
|
+
};
|
|
@@ -1,80 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Label Service Headless Pool
|
|
4
|
+
* Using the unified headless pool system from @things-factory/shell
|
|
5
|
+
*/
|
|
2
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
7
|
exports.getHeadlessPool = getHeadlessPool;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const genericPool = tslib_1.__importStar(require("generic-pool"));
|
|
6
|
-
const env_1 = require("@things-factory/env");
|
|
7
8
|
const shell_1 = require("@things-factory/shell");
|
|
9
|
+
const shell_2 = require("@things-factory/shell");
|
|
8
10
|
const fonts_js_1 = require("./fonts.js");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
catch (err) {
|
|
13
|
-
env_1.logger.error(err);
|
|
14
|
-
}
|
|
15
|
-
var headlessPool;
|
|
16
|
-
function getHeadlessPool() {
|
|
17
|
-
if (!headlessPool) {
|
|
18
|
-
headlessPool = genericPool.createPool({
|
|
19
|
-
create() {
|
|
20
|
-
console.log('headless instance in headless-pool-for-label about to create');
|
|
21
|
-
return initializeScenePage();
|
|
22
|
-
},
|
|
23
|
-
validate({ browser, page }) {
|
|
24
|
-
return Promise.race([
|
|
25
|
-
new Promise(res => setTimeout(() => res(false), 1500)),
|
|
26
|
-
browser
|
|
27
|
-
//@ts-ignore
|
|
28
|
-
.version()
|
|
29
|
-
.then(_ => true)
|
|
30
|
-
.catch(_ => false)
|
|
31
|
-
]);
|
|
32
|
-
},
|
|
33
|
-
destroy({ browser, page }) {
|
|
34
|
-
//@ts-ignore
|
|
35
|
-
return browser.close();
|
|
36
|
-
}
|
|
37
|
-
}, {
|
|
38
|
-
min: 2,
|
|
39
|
-
max: 10,
|
|
40
|
-
testOnBorrow: true,
|
|
41
|
-
acquireTimeoutMillis: 15000
|
|
42
|
-
});
|
|
43
|
-
setTimeout(async () => {
|
|
44
|
-
const eventSource = shell_1.pubsub.subscribe('notify-font-changed');
|
|
45
|
-
for await (const data of eventSource) {
|
|
46
|
-
headlessPool.clear();
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
return headlessPool;
|
|
51
|
-
}
|
|
52
|
-
const CHROMIUM_PATH = env_1.config.get('CHROMIUM_PATH');
|
|
53
|
-
async function initializeChromium() {
|
|
54
|
-
try {
|
|
55
|
-
if (!puppeteer) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
var launchSetting = {
|
|
59
|
-
args: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],
|
|
60
|
-
headless: 'shell'
|
|
61
|
-
};
|
|
62
|
-
if (CHROMIUM_PATH) {
|
|
63
|
-
launchSetting['executablePath'] = CHROMIUM_PATH;
|
|
64
|
-
}
|
|
65
|
-
const browser = await puppeteer.launch(launchSetting);
|
|
66
|
-
return browser;
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
env_1.logger.error(err);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
async function initializeScenePage() {
|
|
73
|
-
/* get brand new browser for every request */
|
|
74
|
-
const browser = await initializeChromium();
|
|
75
|
-
if (!browser) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
11
|
+
// Custom setup function for label page
|
|
12
|
+
async function setupLabelPage(browser) {
|
|
78
13
|
const protocol = 'http';
|
|
79
14
|
const host = 'localhost';
|
|
80
15
|
const path = '/internal-label-command-view';
|
|
@@ -117,4 +52,42 @@ async function initializeScenePage() {
|
|
|
117
52
|
await page.goto(url, { timeout: 0, waitUntil: 'load' });
|
|
118
53
|
return { browser, page };
|
|
119
54
|
}
|
|
55
|
+
// Create the label pool instance with custom setup
|
|
56
|
+
const labelPool = (0, shell_1.getOrCreateHeadlessPool)('label', {
|
|
57
|
+
min: 2,
|
|
58
|
+
max: 10,
|
|
59
|
+
args: [
|
|
60
|
+
...shell_1.HEADLESS_POOL_ARGUMENT_SETS.basic,
|
|
61
|
+
...shell_1.HEADLESS_POOL_ARGUMENT_SETS.keychain_safe
|
|
62
|
+
],
|
|
63
|
+
acquireTimeoutMillis: 15000,
|
|
64
|
+
testOnBorrow: true,
|
|
65
|
+
enableCleanup: true,
|
|
66
|
+
customSetup: setupLabelPage
|
|
67
|
+
});
|
|
68
|
+
// Font change event subscription
|
|
69
|
+
setTimeout(async () => {
|
|
70
|
+
const eventSource = shell_2.pubsub.subscribe('notify-font-changed');
|
|
71
|
+
for await (const data of eventSource) {
|
|
72
|
+
// Reset the pool when fonts change
|
|
73
|
+
await labelPool.reset();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Get the label headless pool
|
|
78
|
+
* @returns Pool instance with acquire/release methods
|
|
79
|
+
*/
|
|
80
|
+
function getHeadlessPool() {
|
|
81
|
+
return {
|
|
82
|
+
acquire: () => labelPool.acquire(),
|
|
83
|
+
release: (resource) => labelPool.release(resource),
|
|
84
|
+
size: 0, // These will be dynamically calculated if needed
|
|
85
|
+
available: 0,
|
|
86
|
+
borrowed: 0,
|
|
87
|
+
pending: 0,
|
|
88
|
+
max: 10,
|
|
89
|
+
min: 2,
|
|
90
|
+
clear: () => labelPool.reset() // For font change compatibility
|
|
91
|
+
};
|
|
92
|
+
}
|
|
120
93
|
//# sourceMappingURL=headless-pool-for-label.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless-pool-for-label.js","sourceRoot":"","sources":["../../server/controllers/headless-pool-for-label.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"headless-pool-for-label.js","sourceRoot":"","sources":["../../server/controllers/headless-pool-for-label.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Label Service Headless Pool\n * Using the unified headless pool system from @things-factory/shell\n */\n\nimport { getOrCreateHeadlessPool, HEADLESS_POOL_ARGUMENT_SETS } from '@things-factory/shell'\nimport { pubsub } from '@things-factory/shell'\nimport { fonts } from './fonts.js'\n\n// Custom setup function for label page\nasync function setupLabelPage(browser: any) {\n const protocol = 'http'\n const host = 'localhost'\n const path = '/internal-label-command-view'\n const port = process.env.PORT\n const url = `${protocol}://${host}:${port}${path}`\n\n const page = await browser.newPage()\n const [fontsToUse, fontStyles] = await fonts()\n\n await page.setRequestInterception(true)\n\n page.on('console', async msg => {\n console.log(`[headless ${msg.type()}] ${msg.text()}`)\n })\n\n page.on('pageerror', error => {\n console.log(`[headless pageerror] ${error.message}`)\n console.log(error.stack)\n })\n\n page.on('error', error => {\n console.log(`[headless fault] ${error}`)\n console.log(error.stack)\n })\n\n page.on('requestfailed', request => {\n console.log('Request failed:', request.url())\n })\n\n page.on('request', request => {\n if (request.url() === url) {\n request.continue({\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n postData: JSON.stringify({\n fonts: fontsToUse,\n fontStyles\n })\n })\n } else {\n request.continue()\n }\n })\n\n await page.goto(url, { timeout: 0, waitUntil: 'load' })\n\n return { browser, page }\n}\n\n// Create the label pool instance with custom setup\nconst labelPool = getOrCreateHeadlessPool('label', {\n min: 2,\n max: 10,\n args: [\n ...HEADLESS_POOL_ARGUMENT_SETS.basic,\n ...HEADLESS_POOL_ARGUMENT_SETS.keychain_safe\n ],\n acquireTimeoutMillis: 15000,\n testOnBorrow: true,\n enableCleanup: true,\n customSetup: setupLabelPage\n})\n\n// Font change event subscription\nsetTimeout(async () => {\n const eventSource = pubsub.subscribe('notify-font-changed')\n for await (const data of eventSource) {\n // Reset the pool when fonts change\n await labelPool.reset()\n }\n})\n\n/**\n * Get the label headless pool\n * @returns Pool instance with acquire/release methods\n */\nexport function getHeadlessPool() {\n return {\n acquire: () => labelPool.acquire(),\n release: (resource: any) => labelPool.release(resource),\n size: 0, // These will be dynamically calculated if needed\n available: 0,\n borrowed: 0,\n pending: 0,\n max: 10,\n min: 2,\n clear: () => labelPool.reset() // For font change compatibility\n }\n}"]}
|
|
@@ -127,6 +127,9 @@ let BoardMutation = class BoardMutation {
|
|
|
127
127
|
where: { domain: { id: domain.id }, id },
|
|
128
128
|
relations: ['creator']
|
|
129
129
|
});
|
|
130
|
+
if (!board) {
|
|
131
|
+
throw new Error('board not found');
|
|
132
|
+
}
|
|
130
133
|
if (patch.model) {
|
|
131
134
|
const thumbnailPromise = (0, thumbnail_js_1.thumbnail)({
|
|
132
135
|
model: patch.model,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"board-mutation.js","sourceRoot":"","sources":["../../../server/service/board/board-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Mutation, Resolver, Directive } from 'type-graphql'\nimport { EntityManager, In } from 'typeorm'\nimport type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\nimport { Domain, getDataSource, getRedirectSubdomainPath, getRepository } from '@things-factory/shell'\n\nimport { thumbnail } from '../../controllers/thumbnail.js'\nimport { Group } from '../group/group.js'\nimport { Board } from './board.js'\nimport { BoardHistory } from './board-history.js'\nimport { BoardPatch, NewBoard } from './board-type.js'\n\nasync function parseJSONFile(uploadedFile: FileUpload): Promise<any> {\n var { createReadStream } = await uploadedFile\n\n return new Promise((resolve, reject) => {\n const chunks: Uint8Array[] = []\n\n createReadStream()\n .on('data', (chunk: Uint8Array) => {\n chunks.push(chunk)\n })\n .on('end', () => {\n try {\n const fileContents = Buffer.concat(chunks).toString('utf-8')\n const jsonData = JSON.parse(fileContents)\n resolve(jsonData)\n } catch (error) {\n reject(error)\n }\n })\n .on('error', (error: Error) => {\n reject(error)\n })\n })\n}\n\n@Resolver(Board)\nexport class BoardMutation {\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, { description: 'Creates a new board.' })\n async createBoard(@Arg('board') board: NewBoard, @Ctx() context: ResolverContext): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n const groupRepository = getRepository(Group, tx)\n\n const oldBoard: Board = await repository.findOneBy({\n name: board.name,\n domain: { id: domain.id }\n })\n\n if (oldBoard) {\n throw new Error(context.t('error.board name is already taken', { name: board.name }))\n }\n\n const newBoard: Board = {\n ...board\n }\n\n newBoard.thumbnail ||=\n 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' /* empty thumbnail */\n\n if (board.groupId) {\n newBoard.group = await groupRepository.findOneBy({\n id: board.groupId\n })\n }\n\n const created = await repository.save({\n domain,\n ...newBoard,\n state: 'draft',\n creator: user,\n updater: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${created.name}' created`,\n body: `Board '${created.name}' created by ${user.name}\\n${created.description}`,\n url: getRedirectSubdomainPath(context, domain, `/board-viewer/${created.id}`)\n })\n\n return created\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, {\n description: 'Clones a board from an existing one, potentially into a different domain.'\n })\n async cloneBoard(\n @Arg('id') id: string,\n @Arg('patch') patch: BoardPatch,\n @Arg('targetSubdomain') targetSubdomain: string,\n @Arg('targetGroupId', { nullable: true }) targetGroupId: string,\n @Ctx() context: ResolverContext\n ): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const { t } = context\n const repository = getRepository(Board, tx)\n\n const board = await repository.findOneBy({ domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id })\n\n if (!patch.name || (patch.name == board.name && targetSubdomain == domain.subdomain)) {\n throw t('error.name must be unique from the original board', { name: patch.name })\n }\n\n if (targetSubdomain != domain.subdomain) {\n if ((await repository.count({ where: { domain: { subdomain: targetSubdomain }, name: patch.name } })) > 0) {\n throw t('error.name must be unique from the original board', { name: patch.name })\n }\n }\n\n var targetDomain = domain\n if (targetDomain && domain.subdomain != targetSubdomain) {\n targetDomain = await getRepository(Domain, tx).findOneBy({ subdomain: targetSubdomain })\n if (!targetDomain) {\n throw `given subdomain(${targetSubdomain}) not found`\n }\n }\n\n var targetGroup = null\n if (targetGroupId) {\n targetGroup = await getRepository(Group, tx).findOneBy({ domain: { id: targetDomain.id }, id: targetGroupId })\n if (!targetGroup) {\n throw `given group(${targetGroupId}) in domain(${targetSubdomain}) not found`\n }\n }\n\n const { id: excluded, ...clone } = board\n\n const cloned = await repository.save({\n domain: targetDomain,\n ...clone,\n ...patch,\n group: targetGroup,\n version: 0,\n state: 'draft',\n updater: user,\n creator: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${cloned.name}' cloned`,\n body: `Board '${cloned.name}' cloned by ${user.name}\\n${cloned.description}`,\n image: getRedirectSubdomainPath(context, targetDomain, `/thumbnail/${cloned.id}`),\n url: getRedirectSubdomainPath(context, targetDomain, `/board-viewer/${cloned.id}`)\n })\n\n return cloned\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, {\n description: 'Updates a board. If a model is provided, it also generates a new thumbnail.'\n })\n async updateBoard(\n @Arg('id') id: string,\n @Arg('patch') patch: BoardPatch,\n @Ctx() context: ResolverContext\n ): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n\n const board = await repository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['creator']\n })\n\n if (patch.model) {\n const thumbnailPromise = thumbnail({\n model: patch.model,\n context\n })\n\n try {\n const thumbnailBase64 = await Promise.race([\n thumbnailPromise,\n new Promise((_, reject) => setTimeout(() => reject(new Error('5 seconds timeout')), 5000))\n ])\n\n patch.thumbnail = 'data:image/png;base64,' + thumbnailBase64.toString('base64')\n } catch (e) {\n console.warn(`Failed to get thumbnail for '${board.name}' in first 5 seconds`)\n // 5초 안에 썸네일이 생성되지 않았으므로 모델만 저장합니다.\n patch.thumbnail =\n 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' /* empty thumbnail */\n\n Promise.race([\n thumbnailPromise,\n new Promise((_, reject) => setTimeout(() => reject(new Error('Thumbnail extended timeout')), 5000))\n ])\n .then(async thumbnailBase64 => {\n /* use new resource manager */\n await getDataSource().transaction(async (tx: EntityManager) => {\n await getRepository(Board, tx).save({\n id: updated.id,\n thumbnail: 'data:image/png;base64,' + thumbnailBase64.toString('base64')\n })\n })\n })\n .catch(error => {\n console.error(`Failed to save thumbnail for '${board.name}' even after extended time:`, error)\n })\n }\n }\n\n const { groupId, ...patched } = patch\n\n if (groupId !== undefined) {\n const groupRepository = getRepository(Group, tx)\n board.group = groupId\n ? (await groupRepository.findOneBy({\n domain: { id: domain.id },\n id: groupId\n })) || null\n : null\n }\n\n const updated = await repository.save({\n domain,\n ...board,\n ...patched,\n state: 'draft',\n updater: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${updated.name}' updated`,\n body: `Board '${updated.name}' updated by ${user.name}\\n${updated.description}`,\n image: getRedirectSubdomainPath(context, domain, `/thumbnail/${updated.id}`),\n url: getRedirectSubdomainPath(context, domain, `/board-viewer/${updated.id}`)\n })\n\n return updated\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, { description: 'Releases a board, making it public and creating a version history.' })\n async releaseBoard(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n const historyRepository = getRepository(BoardHistory, tx)\n\n const board = await repository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['creator']\n })\n\n if (!board) {\n throw `Board given id(${id}) is not found`\n }\n\n if (board.state == 'released') {\n throw `Board given id(${id}) is already released`\n }\n\n // 히스토리에서 max version 가져오기\n const maxHistory = await historyRepository\n .createQueryBuilder('history')\n .select('MAX(history.version)', 'max')\n .where('history.originalId = :id', { id: board.id })\n .getRawOne()\n\n const nextVersion = maxHistory?.max ? Number(maxHistory.max) + 1 : 1\n\n const updated = await repository.save({\n domain,\n ...board,\n version: nextVersion,\n state: 'released',\n updater: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${updated.name}' released`,\n body: `Board '${updated.name}' released by ${user.name}\\n${updated.description}`,\n image: getRedirectSubdomainPath(context, domain, `/thumbnail/${updated.id}`),\n url: getRedirectSubdomainPath(context, domain, `/board-viewer/${updated.id}`)\n })\n\n return updated\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, { description: 'Reverts a board to a specific historical version.' })\n async revertBoardVersion(\n @Arg('id') id: string,\n @Arg('version') version: number,\n @Ctx() context: ResolverContext\n ): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n\n const board = await repository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['creator']\n })\n\n if (!board) {\n throw `Board with id(${id}) is not found`\n }\n\n const historyRepository = getRepository(BoardHistory, tx)\n\n const boardHistory = await historyRepository.findOne({\n where: { domain: { id: domain.id }, originalId: id, version },\n order: { version: 'DESC' }\n })\n\n if (!boardHistory) {\n throw `Board with id:version(${id}:${version}) is not found`\n }\n\n const updated = await repository.save({\n domain,\n ...board,\n model: boardHistory.model,\n thumbnail: boardHistory.thumbnail,\n state: 'draft',\n updater: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${updated.name}' updated`,\n body: `Board '${updated.name}' updated by ${user.name}\\n${updated.description}`,\n image: getRedirectSubdomainPath(context, domain, `/thumbnail/${updated.id}`),\n url: getRedirectSubdomainPath(context, domain, `/board-viewer/${updated.id}`)\n })\n\n return updated\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, { description: 'Deletes a board.' })\n async deleteBoard(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n const board = await repository.findOneBy({ domain: { id: domain.id }, id })\n\n const deleted = await repository.softDelete(id)\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${board.name}' deleted`,\n body: `Board '${board.name}' deleted by ${user.name}\\n${board.description}`\n })\n\n return true\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Board], { description: 'Imports multiple boards from JSON files.' })\n async importBoards(\n @Arg('groupId') groupId: string,\n @Arg('files', () => [GraphQLUpload]) files: FileUpload[],\n @Arg('overwrite') overwrite: boolean,\n @Ctx() context: ResolverContext\n ): Promise<Board[]> {\n const { domain, user, notify, tx } = context.state\n const groupRepository = getRepository(Group, tx)\n const boardRepository = getRepository(Board, tx)\n const group = await groupRepository.findOneBy({ domain: { id: domain.id }, id: groupId })\n\n if (!group) {\n throw `Group with id(${groupId}) is not found`\n }\n\n const boards = []\n\n for (const file of files) {\n const { id, name, description, model, thumbnail } = await parseJSONFile(file)\n\n var sameNameBoard = await boardRepository.findOneBy({ domain: { id: domain.id }, name })\n var sameIdBoard = await boardRepository.findOneBy({ id })\n\n if (overwrite) {\n var board = {} as any\n\n if (sameIdBoard) {\n if (overwrite && sameIdBoard.domainId != domain.id) {\n throw `Board with id(${id}) is already taken in another domain`\n }\n\n board = {\n ...sameIdBoard,\n name\n }\n\n if (sameNameBoard && sameIdBoard.id != sameNameBoard.id) {\n /* 이름 충돌 회피 */\n board.name = `${board.name}(${Date.now()})`\n }\n } else {\n board = {\n id,\n name: sameNameBoard ? `${name}(${Date.now()})` : name,\n version: 0,\n creator: user\n }\n }\n } else {\n board = {\n name,\n version: 0,\n creator: user\n }\n\n /* ID가 없으면, 사용해도 됨 */\n if (!sameIdBoard) {\n board.id = id\n }\n\n /* 이름 충돌 회피 */\n if (sameNameBoard) {\n board.name = `${board.name}(${Date.now()})`\n }\n }\n\n boards.push(\n await boardRepository.save({\n ...board,\n domain,\n description,\n model: typeof model != 'string' ? JSON.stringify(model) : model,\n thumbnail,\n group,\n state: 'draft',\n updater: user\n })\n )\n }\n\n notify &&\n notify({\n mode: 'in-app',\n title: `${boards.length} Board(s) are imported`,\n body: `${boards.length} Board(s) are imported into group ${group.name} by ${user.name}`\n })\n\n return boards\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"board-mutation.js","sourceRoot":"","sources":["../../../server/service/board/board-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Mutation, Resolver, Directive } from 'type-graphql'\nimport { EntityManager, In } from 'typeorm'\nimport type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\nimport { Domain, getDataSource, getRedirectSubdomainPath, getRepository } from '@things-factory/shell'\n\nimport { thumbnail } from '../../controllers/thumbnail.js'\nimport { Group } from '../group/group.js'\nimport { Board } from './board.js'\nimport { BoardHistory } from './board-history.js'\nimport { BoardPatch, NewBoard } from './board-type.js'\n\nasync function parseJSONFile(uploadedFile: FileUpload): Promise<any> {\n var { createReadStream } = await uploadedFile\n\n return new Promise((resolve, reject) => {\n const chunks: Uint8Array[] = []\n\n createReadStream()\n .on('data', (chunk: Uint8Array) => {\n chunks.push(chunk)\n })\n .on('end', () => {\n try {\n const fileContents = Buffer.concat(chunks).toString('utf-8')\n const jsonData = JSON.parse(fileContents)\n resolve(jsonData)\n } catch (error) {\n reject(error)\n }\n })\n .on('error', (error: Error) => {\n reject(error)\n })\n })\n}\n\n@Resolver(Board)\nexport class BoardMutation {\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, { description: 'Creates a new board.' })\n async createBoard(@Arg('board') board: NewBoard, @Ctx() context: ResolverContext): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n const groupRepository = getRepository(Group, tx)\n\n const oldBoard: Board = await repository.findOneBy({\n name: board.name,\n domain: { id: domain.id }\n })\n\n if (oldBoard) {\n throw new Error(context.t('error.board name is already taken', { name: board.name }))\n }\n\n const newBoard: Board = {\n ...board\n }\n\n newBoard.thumbnail ||=\n 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' /* empty thumbnail */\n\n if (board.groupId) {\n newBoard.group = await groupRepository.findOneBy({\n id: board.groupId\n })\n }\n\n const created = await repository.save({\n domain,\n ...newBoard,\n state: 'draft',\n creator: user,\n updater: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${created.name}' created`,\n body: `Board '${created.name}' created by ${user.name}\\n${created.description}`,\n url: getRedirectSubdomainPath(context, domain, `/board-viewer/${created.id}`)\n })\n\n return created\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, {\n description: 'Clones a board from an existing one, potentially into a different domain.'\n })\n async cloneBoard(\n @Arg('id') id: string,\n @Arg('patch') patch: BoardPatch,\n @Arg('targetSubdomain') targetSubdomain: string,\n @Arg('targetGroupId', { nullable: true }) targetGroupId: string,\n @Ctx() context: ResolverContext\n ): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const { t } = context\n const repository = getRepository(Board, tx)\n\n const board = await repository.findOneBy({ domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id })\n\n if (!patch.name || (patch.name == board.name && targetSubdomain == domain.subdomain)) {\n throw t('error.name must be unique from the original board', { name: patch.name })\n }\n\n if (targetSubdomain != domain.subdomain) {\n if ((await repository.count({ where: { domain: { subdomain: targetSubdomain }, name: patch.name } })) > 0) {\n throw t('error.name must be unique from the original board', { name: patch.name })\n }\n }\n\n var targetDomain = domain\n if (targetDomain && domain.subdomain != targetSubdomain) {\n targetDomain = await getRepository(Domain, tx).findOneBy({ subdomain: targetSubdomain })\n if (!targetDomain) {\n throw `given subdomain(${targetSubdomain}) not found`\n }\n }\n\n var targetGroup = null\n if (targetGroupId) {\n targetGroup = await getRepository(Group, tx).findOneBy({ domain: { id: targetDomain.id }, id: targetGroupId })\n if (!targetGroup) {\n throw `given group(${targetGroupId}) in domain(${targetSubdomain}) not found`\n }\n }\n\n const { id: excluded, ...clone } = board\n\n const cloned = await repository.save({\n domain: targetDomain,\n ...clone,\n ...patch,\n group: targetGroup,\n version: 0,\n state: 'draft',\n updater: user,\n creator: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${cloned.name}' cloned`,\n body: `Board '${cloned.name}' cloned by ${user.name}\\n${cloned.description}`,\n image: getRedirectSubdomainPath(context, targetDomain, `/thumbnail/${cloned.id}`),\n url: getRedirectSubdomainPath(context, targetDomain, `/board-viewer/${cloned.id}`)\n })\n\n return cloned\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, {\n description: 'Updates a board. If a model is provided, it also generates a new thumbnail.'\n })\n async updateBoard(\n @Arg('id') id: string,\n @Arg('patch') patch: BoardPatch,\n @Ctx() context: ResolverContext\n ): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n\n const board = await repository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['creator']\n })\n\n if (!board) {\n throw new Error('board not found')\n }\n\n if (patch.model) {\n const thumbnailPromise = thumbnail({\n model: patch.model,\n context\n })\n\n try {\n const thumbnailBase64 = await Promise.race([\n thumbnailPromise,\n new Promise((_, reject) => setTimeout(() => reject(new Error('5 seconds timeout')), 5000))\n ])\n\n patch.thumbnail = 'data:image/png;base64,' + thumbnailBase64.toString('base64')\n } catch (e) {\n console.warn(`Failed to get thumbnail for '${board.name}' in first 5 seconds`)\n // 5초 안에 썸네일이 생성되지 않았으므로 모델만 저장합니다.\n patch.thumbnail =\n 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' /* empty thumbnail */\n\n Promise.race([\n thumbnailPromise,\n new Promise((_, reject) => setTimeout(() => reject(new Error('Thumbnail extended timeout')), 5000))\n ])\n .then(async thumbnailBase64 => {\n /* use new resource manager */\n await getDataSource().transaction(async (tx: EntityManager) => {\n await getRepository(Board, tx).save({\n id: updated.id,\n thumbnail: 'data:image/png;base64,' + thumbnailBase64.toString('base64')\n })\n })\n })\n .catch(error => {\n console.error(`Failed to save thumbnail for '${board.name}' even after extended time:`, error)\n })\n }\n }\n\n const { groupId, ...patched } = patch\n\n if (groupId !== undefined) {\n const groupRepository = getRepository(Group, tx)\n board.group = groupId\n ? (await groupRepository.findOneBy({\n domain: { id: domain.id },\n id: groupId\n })) || null\n : null\n }\n\n const updated = await repository.save({\n domain,\n ...board,\n ...patched,\n state: 'draft',\n updater: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${updated.name}' updated`,\n body: `Board '${updated.name}' updated by ${user.name}\\n${updated.description}`,\n image: getRedirectSubdomainPath(context, domain, `/thumbnail/${updated.id}`),\n url: getRedirectSubdomainPath(context, domain, `/board-viewer/${updated.id}`)\n })\n\n return updated\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, { description: 'Releases a board, making it public and creating a version history.' })\n async releaseBoard(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n const historyRepository = getRepository(BoardHistory, tx)\n\n const board = await repository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['creator']\n })\n\n if (!board) {\n throw `Board given id(${id}) is not found`\n }\n\n if (board.state == 'released') {\n throw `Board given id(${id}) is already released`\n }\n\n // 히스토리에서 max version 가져오기\n const maxHistory = await historyRepository\n .createQueryBuilder('history')\n .select('MAX(history.version)', 'max')\n .where('history.originalId = :id', { id: board.id })\n .getRawOne()\n\n const nextVersion = maxHistory?.max ? Number(maxHistory.max) + 1 : 1\n\n const updated = await repository.save({\n domain,\n ...board,\n version: nextVersion,\n state: 'released',\n updater: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${updated.name}' released`,\n body: `Board '${updated.name}' released by ${user.name}\\n${updated.description}`,\n image: getRedirectSubdomainPath(context, domain, `/thumbnail/${updated.id}`),\n url: getRedirectSubdomainPath(context, domain, `/board-viewer/${updated.id}`)\n })\n\n return updated\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Board, { description: 'Reverts a board to a specific historical version.' })\n async revertBoardVersion(\n @Arg('id') id: string,\n @Arg('version') version: number,\n @Ctx() context: ResolverContext\n ): Promise<Board> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n\n const board = await repository.findOne({\n where: { domain: { id: domain.id }, id },\n relations: ['creator']\n })\n\n if (!board) {\n throw `Board with id(${id}) is not found`\n }\n\n const historyRepository = getRepository(BoardHistory, tx)\n\n const boardHistory = await historyRepository.findOne({\n where: { domain: { id: domain.id }, originalId: id, version },\n order: { version: 'DESC' }\n })\n\n if (!boardHistory) {\n throw `Board with id:version(${id}:${version}) is not found`\n }\n\n const updated = await repository.save({\n domain,\n ...board,\n model: boardHistory.model,\n thumbnail: boardHistory.thumbnail,\n state: 'draft',\n updater: user\n })\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${updated.name}' updated`,\n body: `Board '${updated.name}' updated by ${user.name}\\n${updated.description}`,\n image: getRedirectSubdomainPath(context, domain, `/thumbnail/${updated.id}`),\n url: getRedirectSubdomainPath(context, domain, `/board-viewer/${updated.id}`)\n })\n\n return updated\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, { description: 'Deletes a board.' })\n async deleteBoard(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, user, notify, tx } = context.state\n const repository = getRepository(Board, tx)\n const board = await repository.findOneBy({ domain: { id: domain.id }, id })\n\n const deleted = await repository.softDelete(id)\n\n notify &&\n notify({\n mode: 'in-app',\n title: `Board '${board.name}' deleted`,\n body: `Board '${board.name}' deleted by ${user.name}\\n${board.description}`\n })\n\n return true\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"board\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Board], { description: 'Imports multiple boards from JSON files.' })\n async importBoards(\n @Arg('groupId') groupId: string,\n @Arg('files', () => [GraphQLUpload]) files: FileUpload[],\n @Arg('overwrite') overwrite: boolean,\n @Ctx() context: ResolverContext\n ): Promise<Board[]> {\n const { domain, user, notify, tx } = context.state\n const groupRepository = getRepository(Group, tx)\n const boardRepository = getRepository(Board, tx)\n const group = await groupRepository.findOneBy({ domain: { id: domain.id }, id: groupId })\n\n if (!group) {\n throw `Group with id(${groupId}) is not found`\n }\n\n const boards = []\n\n for (const file of files) {\n const { id, name, description, model, thumbnail } = await parseJSONFile(file)\n\n var sameNameBoard = await boardRepository.findOneBy({ domain: { id: domain.id }, name })\n var sameIdBoard = await boardRepository.findOneBy({ id })\n\n if (overwrite) {\n var board = {} as any\n\n if (sameIdBoard) {\n if (overwrite && sameIdBoard.domainId != domain.id) {\n throw `Board with id(${id}) is already taken in another domain`\n }\n\n board = {\n ...sameIdBoard,\n name\n }\n\n if (sameNameBoard && sameIdBoard.id != sameNameBoard.id) {\n /* 이름 충돌 회피 */\n board.name = `${board.name}(${Date.now()})`\n }\n } else {\n board = {\n id,\n name: sameNameBoard ? `${name}(${Date.now()})` : name,\n version: 0,\n creator: user\n }\n }\n } else {\n board = {\n name,\n version: 0,\n creator: user\n }\n\n /* ID가 없으면, 사용해도 됨 */\n if (!sameIdBoard) {\n board.id = id\n }\n\n /* 이름 충돌 회피 */\n if (sameNameBoard) {\n board.name = `${board.name}(${Date.now()})`\n }\n }\n\n boards.push(\n await boardRepository.save({\n ...board,\n domain,\n description,\n model: typeof model != 'string' ? JSON.stringify(model) : model,\n thumbnail,\n group,\n state: 'draft',\n updater: user\n })\n )\n }\n\n notify &&\n notify({\n mode: 'in-app',\n title: `${boards.length} Board(s) are imported`,\n body: `${boards.length} Board(s) are imported into group ${group.name} by ${user.name}`\n })\n\n return boards\n }\n}\n"]}
|