@things-factory/board-service 8.0.5 → 9.0.0-beta.12

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.
Files changed (66) hide show
  1. package/dist-server/controllers/headless-pdf-to-image.js +7 -2
  2. package/dist-server/controllers/headless-pdf-to-image.js.map +1 -1
  3. package/dist-server/tsconfig.tsbuildinfo +1 -1
  4. package/package.json +7 -7
  5. package/views/internal-board-full-feature-view.html +1 -2
  6. package/views/internal-board-player-view.html +0 -1
  7. package/views/internal-board-service-view.html +0 -1
  8. package/server/constants/error-code.ts +0 -2
  9. package/server/controllers/analyzer/analyze-integration.ts +0 -142
  10. package/server/controllers/fonts.ts +0 -83
  11. package/server/controllers/headless-model.ts +0 -53
  12. package/server/controllers/headless-pdf-to-image.ts +0 -103
  13. package/server/controllers/headless-playlist.ts +0 -71
  14. package/server/controllers/headless-pool-for-board.ts +0 -71
  15. package/server/controllers/headless-pool-for-label.ts +0 -141
  16. package/server/controllers/index.ts +0 -11
  17. package/server/controllers/label-command.ts +0 -62
  18. package/server/controllers/pdf.ts +0 -132
  19. package/server/controllers/screenshot.ts +0 -127
  20. package/server/controllers/thumbnail.ts +0 -18
  21. package/server/errors/index.ts +0 -1
  22. package/server/errors/license-error.ts +0 -21
  23. package/server/index.ts +0 -36
  24. package/server/migrations/1556862253000-SeedGroup.ts +0 -51
  25. package/server/migrations/index.ts +0 -9
  26. package/server/routers/internal-board-view-router.ts +0 -33
  27. package/server/routers/standalone-board-service-router.ts +0 -326
  28. package/server/routes.ts +0 -25
  29. package/server/service/analysis/analysis-query.ts +0 -13
  30. package/server/service/analysis/index.ts +0 -3
  31. package/server/service/board/board-history.ts +0 -137
  32. package/server/service/board/board-mutation.ts +0 -446
  33. package/server/service/board/board-query.ts +0 -180
  34. package/server/service/board/board-subscription.ts +0 -43
  35. package/server/service/board/board-type.ts +0 -58
  36. package/server/service/board/board.ts +0 -125
  37. package/server/service/board/event-subscriber.ts +0 -68
  38. package/server/service/board/index.ts +0 -10
  39. package/server/service/board-favorite/board-favorite-query.ts +0 -53
  40. package/server/service/board-favorite/board-favorite-type.ts +0 -18
  41. package/server/service/board-favorite/index.ts +0 -4
  42. package/server/service/board-template/board-template-mutation.ts +0 -161
  43. package/server/service/board-template/board-template-query.ts +0 -121
  44. package/server/service/board-template/board-template-type.ts +0 -53
  45. package/server/service/board-template/board-template.ts +0 -114
  46. package/server/service/board-template/index.ts +0 -7
  47. package/server/service/group/group-mutation.ts +0 -82
  48. package/server/service/group/group-query.ts +0 -58
  49. package/server/service/group/group-type.ts +0 -30
  50. package/server/service/group/group.ts +0 -69
  51. package/server/service/group/index.ts +0 -6
  52. package/server/service/index.ts +0 -56
  53. package/server/service/permission/domain-permission-subscriber.ts +0 -27
  54. package/server/service/permission/index.ts +0 -3
  55. package/server/service/play-group/event-subscriber.ts +0 -58
  56. package/server/service/play-group/index.ts +0 -9
  57. package/server/service/play-group/play-group-mutation.ts +0 -148
  58. package/server/service/play-group/play-group-query.ts +0 -92
  59. package/server/service/play-group/play-group-subscription.ts +0 -43
  60. package/server/service/play-group/play-group-type.ts +0 -30
  61. package/server/service/play-group/play-group.ts +0 -74
  62. package/server/service/theme/index.ts +0 -7
  63. package/server/service/theme/theme-mutation.ts +0 -128
  64. package/server/service/theme/theme-query.ts +0 -48
  65. package/server/service/theme/theme-type.ts +0 -55
  66. package/server/service/theme/theme.ts +0 -97
@@ -1,141 +0,0 @@
1
- import * as genericPool from 'generic-pool'
2
-
3
- import { config, logger } from '@things-factory/env'
4
- import { pubsub } from '@things-factory/shell'
5
-
6
- import { fonts } from './fonts'
7
-
8
- try {
9
- var puppeteer = require('puppeteer')
10
- } catch (err) {
11
- logger.error(err)
12
- }
13
-
14
- var headlessPool
15
-
16
- export function getHeadlessPool() {
17
- if (!headlessPool) {
18
- headlessPool = genericPool.createPool(
19
- {
20
- create() {
21
- console.log('headless instance in headless-pool-for-label about to create')
22
- return initializeScenePage()
23
- },
24
- validate({ browser, page }) {
25
- return Promise.race([
26
- new Promise(res => setTimeout(() => res(false), 1500)),
27
- browser
28
- //@ts-ignore
29
- .version()
30
- .then(_ => true)
31
- .catch(_ => false)
32
- ])
33
- },
34
- destroy({ browser, page }) {
35
- //@ts-ignore
36
- return browser.close()
37
- }
38
- },
39
- {
40
- min: 2,
41
- max: 10,
42
- testOnBorrow: true,
43
- acquireTimeoutMillis: 15000
44
- }
45
- )
46
-
47
- setTimeout(async () => {
48
- const eventSource = pubsub.subscribe('notify-font-changed')
49
- for await (const data of eventSource) {
50
- headlessPool.clear()
51
- }
52
- })
53
- }
54
-
55
- return headlessPool
56
- }
57
-
58
- const CHROMIUM_PATH = config.get('CHROMIUM_PATH')
59
-
60
- async function initializeChromium() {
61
- try {
62
- if (!puppeteer) {
63
- return
64
- }
65
-
66
- var launchSetting = {
67
- args: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],
68
- headless: 'shell'
69
- }
70
-
71
- if (CHROMIUM_PATH) {
72
- launchSetting['executablePath'] = CHROMIUM_PATH
73
- }
74
-
75
- const browser = await puppeteer.launch(launchSetting)
76
-
77
- return browser
78
- } catch (err) {
79
- logger.error(err)
80
- }
81
- }
82
-
83
- async function initializeScenePage() {
84
- /* get brand new browser for every request */
85
- const browser = await initializeChromium()
86
-
87
- if (!browser) {
88
- return
89
- }
90
-
91
- const protocol = 'http'
92
- const host = 'localhost'
93
- const path = '/internal-label-command-view'
94
-
95
- const port = process.env.PORT
96
- const url = `${protocol}://${host}:${port}${path}`
97
-
98
- const page = await browser.newPage()
99
- const [fontsToUse, fontStyles] = await fonts()
100
-
101
- await page.setRequestInterception(true)
102
-
103
- page.on('console', async msg => {
104
- console.log(`[headless ${msg.type()}] ${msg.text()}`)
105
- })
106
-
107
- page.on('pageerror', error => {
108
- console.log(`[headless pageerror] ${error.message}`)
109
- console.log(error.stack)
110
- })
111
-
112
- page.on('error', error => {
113
- console.log(`[headless fault] ${error}`)
114
- console.log(error.stack)
115
- })
116
-
117
- page.on('requestfailed', request => {
118
- console.log('Request failed:', request.url())
119
- })
120
-
121
- page.on('request', request => {
122
- if (request.url() === url) {
123
- request.continue({
124
- method: 'POST',
125
- headers: {
126
- 'Content-Type': 'application/json'
127
- },
128
- postData: JSON.stringify({
129
- fonts: fontsToUse,
130
- fontStyles
131
- })
132
- })
133
- } else {
134
- request.continue()
135
- }
136
- })
137
-
138
- await page.goto(url, { timeout: 0, waitUntil: 'load' })
139
-
140
- return { browser, page }
141
- }
@@ -1,11 +0,0 @@
1
- import { labelcommand as boardToZpl } from './label-command'
2
- import { pdf as boardToPdf } from './pdf'
3
- import { headlessModel } from './headless-model'
4
- import { fonts } from './fonts'
5
-
6
- export const BoardFunc = {
7
- boardToZpl,
8
- boardToPdf,
9
- headlessModel,
10
- fonts
11
- }
@@ -1,62 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import { getHeadlessPool } from './headless-pool-for-label'
6
- import { headlessModel } from './headless-model'
7
-
8
- /**
9
- * 라벨 출력
10
- *
11
- * @param {String} id 모델 ID
12
- * @param {Object} data 매핑할 데이터
13
- * @param {String} orientation (시계방향) N: 0, R: 90, I: 180, B: 270
14
- * @param {boolean} mirror 좌우반전
15
- * @param {boolean} upsideDown 상하반전
16
- */
17
- export const labelcommand = async ({ id, model, data, orientation, mirror = false, upsideDown = false, context, draft = false }) => {
18
- const { domain } = context.state
19
-
20
- const browser = (await getHeadlessPool().acquire()) as any
21
- if (!browser) {
22
- return
23
- }
24
-
25
- const { page } = browser
26
-
27
- var { model } = await headlessModel({ domain, model, id }, draft)
28
-
29
- const grf = await page.evaluate(
30
- async (model, data, orientation, mirror, upsideDown) => {
31
- //@ts-ignore
32
- let s = createScene(model)
33
- if (data) {
34
- s.data = data
35
- }
36
- return new Promise(resolve => {
37
- // @ts-ignore
38
- requestAnimationFrame(() => {
39
- // @ts-ignore
40
- let grf = imageDataToGrf(s, model, orientation, mirror, upsideDown)
41
- resolve(grf)
42
- // @ts-ignore
43
- sceneContainer.removeChild(s.target)
44
- s.dispose()
45
- })
46
- })
47
- },
48
- model,
49
- data,
50
- orientation,
51
- mirror,
52
- upsideDown
53
- )
54
-
55
- getHeadlessPool().release(browser)
56
-
57
- return `
58
- ^XA
59
- ^GFA,${grf}
60
- ^FS
61
- ^XZ`
62
- }
@@ -1,132 +0,0 @@
1
- import { fonts } from './fonts'
2
- import { getHeadlessPool } from './headless-pool-for-board'
3
- import { headlessModel } from './headless-model'
4
-
5
- const protocol = 'http'
6
- const host = 'localhost'
7
- const path = '/internal-board-service-view'
8
-
9
- export const pdf = async ({
10
- id = '',
11
- model = null,
12
- data = null,
13
- width: w = 0,
14
- height: h = 0,
15
- options = {} as any,
16
- context = {} as any
17
- } = {}) => {
18
- const browser = (await getHeadlessPool().acquire()) as any
19
-
20
- if (!browser) {
21
- return
22
- }
23
-
24
- const { domain, user } = context.state
25
-
26
- var { model, base } = await headlessModel({ domain, id, model })
27
- const [fontsToUse, fontStyles] = await fonts(domain)
28
-
29
- model.fonts = fontsToUse
30
- model.fontStyles = fontStyles
31
-
32
- let { width, height } = model
33
-
34
- width = Number(width)
35
- height = Number(height)
36
-
37
- if (!w) {
38
- w = width
39
- }
40
- if (!h) {
41
- h = height
42
- }
43
-
44
- let ratio = Math.min(w / width, h / height)
45
-
46
- width = Math.floor(width * ratio)
47
- height = Math.floor(height * ratio)
48
-
49
- const port = process.env.PORT ? `:${process.env.PORT}` : ''
50
- const url = `${protocol}://${host}${port}${path}`
51
- const page = await browser.newPage()
52
-
53
- try {
54
- /* @remember-me width, height should be a integer */
55
- await page.setViewport({ width, height })
56
- await page.setRequestInterception(true)
57
-
58
- page.on('console', async msg => {
59
- console.log(`[headless ${msg.type()}] ${msg.text()}`)
60
- })
61
-
62
- page.on('pageerror', error => {
63
- console.log(`[headless pageerror] ${error.message}`)
64
- console.log(error.stack)
65
- })
66
-
67
- page.on('error', error => {
68
- console.log(`[headless fault] ${error}`)
69
- console.log(error.stack)
70
- })
71
-
72
- page.on('requestfailed', request => {
73
- console.log('Request failed:', request.url())
74
- })
75
-
76
- const token = await user?.sign() // TODO improve performance
77
-
78
- page.on('request', request => {
79
- if (request.url() === url) {
80
- request.continue({
81
- method: 'POST',
82
- headers: {
83
- 'Content-Type': 'application/json',
84
- 'x-things-factory-domain': domain?.subdomain,
85
- Authorization: 'Bearer ' + token
86
- },
87
- postData: JSON.stringify({
88
- model,
89
- base
90
- })
91
- })
92
- } else if (request.url().startsWith(`${protocol}://${host}${port}`)) {
93
- request.continue({
94
- headers: {
95
- ...request.headers(),
96
- 'x-things-factory-domain': domain?.subdomain,
97
- Authorization: 'Bearer ' + token
98
- }
99
- })
100
- } else {
101
- request.continue()
102
- }
103
- })
104
-
105
- await page.goto(url)
106
-
107
- await page.evaluate(async data => {
108
- if (data) {
109
- // @ts-ignore
110
- s.data = data
111
- }
112
-
113
- // data 주입 후 강제 지연시킴.
114
- return new Promise(resolve => {
115
- // @ts-ignore
116
- requestAnimationFrame(() => resolve())
117
- })
118
- }, data)
119
-
120
- const pdf = await page.pdf({
121
- format: 'A4',
122
- ...options
123
- })
124
- } catch (error) {
125
- console.log(error)
126
- } finally {
127
- page.close()
128
- getHeadlessPool().release(browser)
129
- }
130
-
131
- return pdf
132
- }
@@ -1,127 +0,0 @@
1
- import { fonts } from './fonts'
2
- import { getHeadlessPool } from './headless-pool-for-board'
3
- import { headlessModel } from './headless-model'
4
-
5
- const protocol = 'http'
6
- const host = 'localhost'
7
- const path = '/internal-board-service-view'
8
-
9
- export const screenshot = async ({
10
- id = '',
11
- model = null,
12
- data = null,
13
- width: w = 0,
14
- height: h = 0,
15
- options = { encoding: 'base64' } as any,
16
- isThumbnail = false,
17
- context = {} as any,
18
- draft = false
19
- } = {}) => {
20
- const browser = (await getHeadlessPool().acquire()) as any
21
- var screenshot = null
22
-
23
- if (!browser) {
24
- return
25
- }
26
- const { domain, user } = context.state
27
-
28
- var { model, base } = await headlessModel({ domain, id, model }, draft)
29
- const [fontsToUse, fontStyles] = await fonts(domain)
30
-
31
- model.fonts = fontsToUse
32
- model.fontStyles = fontStyles
33
-
34
- var { width, height } = model
35
-
36
- if (isThumbnail) {
37
- var widthRatio = 400 / width,
38
- heightRatio = 300 / height
39
- var ratio = widthRatio < heightRatio ? widthRatio : heightRatio
40
- width = width * ratio
41
- height = height * ratio
42
- }
43
- width = Math.floor(w || Number(width))
44
- height = Math.floor(h || Number(height))
45
-
46
- const port = process.env.PORT ? `:${process.env.PORT}` : ''
47
- const url = `${protocol}://${host}${port}${path}`
48
-
49
- var page = await browser.newPage()
50
-
51
- try {
52
- /* @remember-me width, height should be a integer */
53
- await page.setViewport({ width, height })
54
- await page.setRequestInterception(true)
55
- await page.setDefaultTimeout(10000)
56
-
57
- page.on('console', async msg => {
58
- console.log(`[headless ${msg.type()}] ${msg.text()}`)
59
- })
60
-
61
- page.on('pageerror', error => {
62
- console.log(`[headless pageerror] ${error.message}`)
63
- console.log(error.stack)
64
- })
65
-
66
- page.on('error', error => {
67
- console.log(`[headless fault] ${error}`)
68
- console.log(error.stack)
69
- })
70
-
71
- page.on('requestfailed', request => {
72
- console.log('Request failed:', request.url())
73
- })
74
-
75
- const token = await user?.sign() // TODO improve performance
76
-
77
- page.on('request', request => {
78
- if (request.url() === url) {
79
- request.continue({
80
- method: 'POST',
81
- headers: {
82
- 'Content-Type': 'application/json',
83
- 'x-things-factory-domain': domain?.subdomain,
84
- Authorization: 'Bearer ' + token
85
- },
86
- postData: JSON.stringify({
87
- model,
88
- base
89
- })
90
- })
91
- } else if (request.url().startsWith(`${protocol}://${host}${port}`)) {
92
- request.continue({
93
- headers: {
94
- ...request.headers(),
95
- 'x-things-factory-domain': domain?.subdomain,
96
- Authorization: 'Bearer ' + token
97
- }
98
- })
99
- } else {
100
- request.continue()
101
- }
102
- })
103
- await page.goto(url)
104
-
105
- await page.evaluate(async data => {
106
- if (data) {
107
- // @ts-ignore
108
- s.data = data
109
- }
110
-
111
- // data 주입 후 강제 지연시킴.
112
- return new Promise(resolve => {
113
- // @ts-ignore
114
- requestAnimationFrame(() => resolve())
115
- })
116
- }, data)
117
-
118
- screenshot = await page.screenshot(options)
119
- } catch (error) {
120
- console.log(error)
121
- } finally {
122
- page.close()
123
- getHeadlessPool().release(browser)
124
- }
125
-
126
- return screenshot
127
- }
@@ -1,18 +0,0 @@
1
- import { screenshot } from './screenshot'
2
-
3
- export const thumbnail = async ({
4
- id = '',
5
- model = null,
6
- data = null,
7
- options = { encoding: 'base64', type: 'png' } as any,
8
- context = {}
9
- } = {}) => {
10
- return await screenshot({
11
- id,
12
- model,
13
- data,
14
- options,
15
- isThumbnail: true,
16
- context
17
- })
18
- }
@@ -1 +0,0 @@
1
- export * from './license-error'
@@ -1,21 +0,0 @@
1
- import * as ERROR_CODES from '../constants/error-code'
2
-
3
- type LicenseErrorArgument = {
4
- errorCode: string
5
- detail?: Object
6
- }
7
- export class LicenseError extends Error {
8
- static get ERROR_CODES(): any {
9
- return {
10
- ...ERROR_CODES
11
- }
12
- }
13
- errorCode: any
14
- detail: Object
15
- constructor({ errorCode, detail }: LicenseErrorArgument) {
16
- super(errorCode)
17
- this.name = 'license-error'
18
- this.errorCode = errorCode
19
- this.detail = detail
20
- }
21
- }
package/server/index.ts DELETED
@@ -1,36 +0,0 @@
1
- export * from './service'
2
- export * from './migrations'
3
- export * from './controllers'
4
-
5
- import './routes'
6
-
7
- import { getPermission } from '@things-factory/operato-license-checker'
8
-
9
- export function initMiddlewares(app) {
10
- const licensedPermissions = (getPermission('Permissions For Board Usage') || 'Modeller, Viewer')
11
- .split(',')
12
- .map(p => p.trim())
13
-
14
- const prohibited = !licensedPermissions.includes('Modeller') && [
15
- {
16
- privilege: 'mutation',
17
- category: 'board'
18
- },
19
- {
20
- privilege: 'mutation',
21
- category: 'board-template'
22
- }
23
- ]
24
-
25
- /*
26
- * board-permission을 prohibitedPrivileges에 반영한다.
27
- */
28
- app.use(async (context, next) => {
29
- if (prohibited) {
30
- const { prohibitedPrivileges } = context.state
31
-
32
- context.state.prohibitedPrivileges = [...(prohibitedPrivileges || []), ...prohibited]
33
- }
34
- await next()
35
- })
36
- }
@@ -1,51 +0,0 @@
1
- import { MigrationInterface, QueryRunner } from 'typeorm'
2
-
3
- import { logger } from '@things-factory/env'
4
- import { Domain, getRepository } from '@things-factory/shell'
5
-
6
- import { Group } from '../service/group/group'
7
-
8
- const SEED_GROUP = [
9
- {
10
- name: 'DASHBOARD',
11
- description: 'Dashboard'
12
- }
13
- ]
14
-
15
- export class SeedGroup1556862253000 implements MigrationInterface {
16
- public async up(queryRunner: QueryRunner): Promise<any> {
17
- const repository = getRepository(Group)
18
- const domainRepository = getRepository(Domain)
19
- const domain = await domainRepository.findOneBy({ name: 'SYSTEM' })
20
-
21
- try {
22
- return await Promise.all(
23
- SEED_GROUP.map(async group => {
24
- await repository.save({
25
- ...group,
26
- domain
27
- })
28
- })
29
- )
30
- } catch (e) {
31
- logger.error(e)
32
- }
33
- }
34
-
35
- public async down(queryRunner: QueryRunner): Promise<any> {
36
- const repository = getRepository(Group)
37
- const domainRepository = getRepository(Domain)
38
- const domain = await domainRepository.findOneBy({ name: 'SYSTEM' })
39
-
40
- SEED_GROUP.reverse().forEach(async group => {
41
- let record = await repository.findOne({
42
- where: {
43
- domain: { id: domain.id },
44
- name: group.name
45
- }
46
- })
47
-
48
- await repository.remove(record)
49
- })
50
- }
51
- }
@@ -1,9 +0,0 @@
1
- const glob = require('glob')
2
- const path = require('path')
3
-
4
- export var migrations = []
5
-
6
- glob.sync(path.resolve(__dirname, '.', '**', '*.js')).forEach(function(file) {
7
- if (file.indexOf('index.js') !== -1) return
8
- migrations = migrations.concat(Object.values(require(path.resolve(file))) || [])
9
- })
@@ -1,33 +0,0 @@
1
- import Router from 'koa-router'
2
-
3
- export const internalBoardViewRouter = new Router()
4
-
5
- function parseQuery(query) {
6
- for (const key in query) {
7
- if (query.hasOwnProperty(key)) {
8
- try {
9
- query[key] = JSON.parse(query[key])
10
- } catch (error) {
11
- // do nothing
12
- }
13
- }
14
- }
15
-
16
- return query
17
- }
18
-
19
- // should be used only for building label command by headless chrome internally
20
- internalBoardViewRouter.post('/internal-label-command-view', async (context, next) => {
21
- let model = context.request.body
22
- let data = context.query
23
-
24
- await context.render('internal-label-command-view', { model, data })
25
- })
26
-
27
- // should be used only for building board service by headless chrome internally
28
- internalBoardViewRouter.post('/internal-board-service-view', async (context, next) => {
29
- let { id, model, base } = context.request.body
30
- const data = parseQuery({ ...context.query })
31
-
32
- await context.render('internal-board-service-view', { id, model, data, base })
33
- })