Passed
Push — trunk ( 762d62...45f6d1 )
by Christian
15:06 queued 12s
created

worker.init.ts ➔ enableAdminWorker   B

Complexity

Conditions 6

Size

Total Lines 42
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 32
dl 0
loc 42
rs 8.1786
c 0
b 0
f 0
1
import AdminWorker from 'src/core/worker/admin-worker.worker';
2
import WorkerNotificationListener from 'src/core/worker/worker-notification-listener';
3
import AdminNotificationWorker from 'src/core/worker/admin-notification-worker';
4
import getRefreshTokenHelper from 'src/core/helper/refresh-token.helper';
5
import type { ApiContext } from '@shopware-ag/admin-extension-sdk/es/data/_internals/EntityCollection';
6
import type Vue from 'vue';
7
import type { LoginService } from '../../core/service/login.service';
8
import type { ContextState } from '../state/context.store';
9
import type {
10
    NotificationConfig,
11
    NotificationService,
12
    NotificationWorkerOptions,
13
} from '../../core/factory/worker-notification.factory';
14
import type WorkerNotificationFactory from '../../core/factory/worker-notification.factory';
15
16
let enabled = false;
17
let enabledNotification = false;
18
19
/**
20
 * @package admin
21
 *
22
 * Starts the worker
23
 */
24
// eslint-disable-next-line sw-deprecation-rules/private-feature-declarations
25
export default function initializeWorker() {
26
    const loginService = Shopware.Service('loginService');
27
    const context = Shopware.Context.app;
28
    const workerNotificationFactory = Shopware.Application.getContainer('factory').workerNotification;
29
    const configService = Shopware.Service('configService');
30
31
    registerThumbnailMiddleware(workerNotificationFactory);
32
33
    function getConfig() {
34
        return configService.getConfig().then((response) => {
35
            Object.entries(response as { [key: string]: unknown}).forEach(([key, value]) => {
36
                Shopware.State.commit('context/addAppConfigValue', { key, value });
37
            });
38
39
            // Enable worker notification listener regardless of the config
40
            enableWorkerNotificationListener(
41
                loginService,
42
                Shopware.Context.api,
43
            );
44
45
            // Enable worker notification listener regardless of the config
46
            if (!enabledNotification) {
47
                enableNotificationWorker(loginService);
48
            }
49
50
            if (context.config.adminWorker?.enableAdminWorker && !enabled) {
51
                enableAdminWorker(loginService, Shopware.Context.api, context.config.adminWorker);
52
            }
53
        });
54
    }
55
56
    if (loginService.isLoggedIn()) {
57
        return getConfig().catch();
58
    }
59
60
    return loginService.addOnLoginListener(getConfig);
61
}
62
63
function enableAdminWorker(
64
    loginService: LoginService,
65
    context: ApiContext,
66
    config: ContextState['app']['config']['adminWorker'],
67
) {
68
    // @ts-expect-error
69
    // eslint-disable-next-line max-len,@typescript-eslint/no-unsafe-member-access
70
    const transports = (window._features_?.vue3 ? JSON.parse(JSON.stringify(config))?.transports || [] : config?.transports || []) as string[];
71
72
    const getMessage = () => {
73
        return {
74
            context: {
75
                languageId: context.languageId,
76
                apiResourcePath: context.apiResourcePath,
77
            },
78
            bearerAuth: loginService.getBearerAuthentication(),
79
            host: window.location.origin,
80
            // Quick fix to lose the reference to the config object, this was causing issues with the worker
81
            transports,
82
        };
83
    };
84
85
    if (loginService.isLoggedIn()) {
86
        getWorker().postMessage(getMessage());
87
    }
88
89
    loginService.addOnTokenChangedListener((auth) => {
90
        getWorker().postMessage({ ...getMessage(), ...{ bearerAuth: auth } });
91
    });
92
93
    loginService.addOnLogoutListener(() => {
94
        getWorker().postMessage({ type: 'logout' });
95
    });
96
97
    const importExportService = Shopware.Service('importExport');
98
99
    importExportService.addOnProgressStartedListener(() => {
100
        getWorker().postMessage({ ...getMessage(), ...{ type: 'consumeReset' } });
101
    });
102
103
    enabled = true;
104
}
105
106
// singleton instance of worker
107
let worker: Worker;
108
109
/* istanbul ignore next */
110
function getWorker() : Worker {
111
    if (worker) {
112
        return worker;
113
    }
114
115
    // The webpack worker plugin generates a valid worker file therefore we can use it here
116
    // @ts-expect-error
117
    worker = new AdminWorker() as Worker;
118
119
    worker.onmessage = () => {
120
        const tokenHandler = getRefreshTokenHelper();
121
122
        if (!tokenHandler.isRefreshing) {
123
            void tokenHandler.fireRefreshTokenRequest();
124
        }
125
    };
126
127
    return worker;
128
}
129
130
function enableWorkerNotificationListener(loginService: LoginService, context: ContextState['api']) {
131
    let workerNotificationListener = new WorkerNotificationListener(context);
132
133
    if (loginService.isLoggedIn()) {
134
        workerNotificationListener.start();
135
    }
136
137
    loginService.addOnTokenChangedListener(() => {
138
        workerNotificationListener.terminate();
139
        workerNotificationListener = new WorkerNotificationListener(context);
140
        workerNotificationListener.start();
141
    });
142
143
    loginService.addOnLogoutListener(() => {
144
        workerNotificationListener.terminate();
145
        workerNotificationListener = new WorkerNotificationListener(context);
146
    });
147
}
148
149
function enableNotificationWorker(loginService: LoginService) {
150
    let notificationWorker = new AdminNotificationWorker();
151
152
    if (loginService.isLoggedIn()) {
153
        notificationWorker.start();
154
    }
155
156
    loginService.addOnTokenChangedListener(() => {
157
        notificationWorker.terminate();
158
        notificationWorker = new AdminNotificationWorker();
159
        notificationWorker.start();
160
    });
161
162
    loginService.addOnLogoutListener(() => {
163
        notificationWorker.terminate();
164
        notificationWorker = new AdminNotificationWorker();
165
    });
166
167
    enabledNotification = true;
168
}
169
170
function registerThumbnailMiddleware(factory: typeof WorkerNotificationFactory) {
171
    const ids = {};
172
    factory.register('DalIndexingMessage', {
173
        name: 'Shopware\\Core\\Framework\\DataAbstractionLayer\\Indexing\\MessageQueue\\IndexerMessage',
174
        fn: function middleware(next, { entry, $root, notification }) {
175
            messageQueueNotification('dalIndexing', ids, next, entry, $root, notification, {
176
                title: 'global.default.success',
177
                message: 'global.notification-center.worker-listener.dalIndexing.message',
178
                success: 'global.notification-center.worker-listener.dalIndexing.messageSuccess',
179
                foregroundSuccessMessage: 'sw-settings-cache.notifications.index.success',
180
            });
181
        },
182
    });
183
184
    factory.register('WarmupIndexingMessage', {
185
        name: 'Shopware\\Storefront\\Framework\\Cache\\CacheWarmer\\WarmUpMessage',
186
        fn: function middleware(next, { entry, $root, notification }) {
187
            messageQueueNotification('warmupMessage', ids, next, entry, $root, notification, {
188
                title: 'global.default.success',
189
                message: 'global.notification-center.worker-listener.warmupIndexing.message',
190
                success: 'global.notification-center.worker-listener.warmupIndexing.messageSuccess',
191
                foregroundSuccessMessage: 'sw-settings-cache.notifications.clearCacheAndWarmup.success',
192
            }, 10);
193
        },
194
    });
195
196
    factory.register('EsIndexingMessage', {
197
        name: 'Shopware\\Elasticsearch\\Framework\\Indexing\\IndexingMessage',
198
        fn: function middleware(next, { entry, $root, notification }) {
199
            messageQueueNotification('esIndexing', ids, next, entry, $root, notification, {
200
                title: 'global.default.success',
201
                message: 'global.notification-center.worker-listener.esIndexing.message',
202
                success: 'global.notification-center.worker-listener.esIndexing.messageSuccess',
203
            });
204
        },
205
    });
206
207
    factory.register('generateThumbnailsMessage', {
208
        name: 'Shopware\\Core\\Content\\Media\\Message\\GenerateThumbnailsMessage',
209
        fn: function middleware(next, { entry, $root, notification }) {
210
            messageQueueNotification('thumbnails', ids, next, entry, $root, notification, {
211
                title: 'global.notification-center.worker-listener.thumbnailGeneration.title',
212
                message: 'global.notification-center.worker-listener.thumbnailGeneration.message',
213
                success: 'global.notification-center.worker-listener.thumbnailGeneration.messageSuccess',
214
            });
215
        },
216
    });
217
218
    factory.register('PromotionIndexingMessage', {
219
        name: 'Shopware\\Core\\Checkout\\Promotion\\DataAbstractionLayer\\PromotionIndexingMessage',
220
        fn: function middleware(next, { entry, $root, notification }) {
221
            messageQueueNotification('promotion', ids, next, entry, $root, notification, {
222
                title: 'global.notification-center.worker-listener.promotion.title',
223
                message: 'global.notification-center.worker-listener.promotion.message',
224
                success: 'global.notification-center.worker-listener.promotion.messageSuccess',
225
            }, 50);
226
        },
227
    });
228
229
    factory.register('ProductStreamIndexingMessage', {
230
        name: 'Shopware\\Core\\Content\\ProductStream\\DataAbstractionLayer\\ProductStreamIndexingMessage',
231
        fn: function middleware(next, { entry, $root, notification }) {
232
            messageQueueNotification('productStream', ids, next, entry, $root, notification, {
233
                title: 'global.notification-center.worker-listener.productStream.title',
234
                message: 'global.notification-center.worker-listener.productStream.message',
235
                success: 'global.notification-center.worker-listener.productStream.messageSuccess',
236
            }, 50);
237
        },
238
    });
239
240
    factory.register('CategoryIndexingMessage', {
241
        name: 'Shopware\\Core\\Content\\Category\\DataAbstractionLayer\\CategoryIndexingMessage',
242
        fn: function middleware(next, { entry, $root, notification }) {
243
            messageQueueNotification('category', ids, next, entry, $root, notification, {
244
                title: 'global.notification-center.worker-listener.category.title',
245
                message: 'global.notification-center.worker-listener.category.message',
246
                success: 'global.notification-center.worker-listener.category.messageSuccess',
247
            }, 50);
248
        },
249
    });
250
251
    factory.register('MediaIndexingMessage', {
252
        name: 'Shopware\\Core\\Content\\Media\\DataAbstractionLayer\\MediaIndexingMessage',
253
        fn: function middleware(next, { entry, $root, notification }) {
254
            messageQueueNotification('media', ids, next, entry, $root, notification, {
255
                title: 'global.notification-center.worker-listener.media.title',
256
                message: 'global.notification-center.worker-listener.media.message',
257
                success: 'global.notification-center.worker-listener.media.messageSuccess',
258
            }, 50);
259
        },
260
    });
261
262
    factory.register('SalesChannelIndexingMessage', {
263
        name: 'Shopware\\Core\\System\\SalesChannel\\DataAbstractionLayer\\SalesChannelIndexingMessage',
264
        fn: function middleware(next, { entry, $root, notification }) {
265
            messageQueueNotification('salesChannel', ids, next, entry, $root, notification, {
266
                title: 'global.notification-center.worker-listener.salesChannel.title',
267
                message: 'global.notification-center.worker-listener.salesChannel.message',
268
                success: 'global.notification-center.worker-listener.salesChannel.messageSuccess',
269
            }, 50);
270
        },
271
    });
272
273
    factory.register('RuleIndexingMessage', {
274
        name: 'Shopware\\Core\\Content\\Rule\\DataAbstractionLayer\\RuleIndexingMessage',
275
        fn: function middleware(next, { entry, $root, notification }) {
276
            messageQueueNotification('rule', ids, next, entry, $root, notification, {
277
                title: 'global.notification-center.worker-listener.rule.title',
278
                message: 'global.notification-center.worker-listener.rule.message',
279
                success: 'global.notification-center.worker-listener.rule.messageSuccess',
280
            }, 50);
281
        },
282
    });
283
284
    factory.register('ProductIndexingMessage', {
285
        name: 'Shopware\\Core\\Content\\Product\\DataAbstractionLayer\\ProductIndexingMessage',
286
        fn: function middleware(next, { entry, $root, notification }) {
287
            messageQueueNotification('product', ids, next, entry, $root, notification, {
288
                title: 'global.notification-center.worker-listener.product.title',
289
                message: 'global.notification-center.worker-listener.product.message',
290
                success: 'global.notification-center.worker-listener.product.messageSuccess',
291
            }, 50);
292
        },
293
    });
294
295
    factory.register('ElasticSearchIndexingMessage', {
296
        name: 'Shopware\\Elasticsearch\\Framework\\Indexing\\ElasticsearchIndexingMessage',
297
        fn: function middleware(next, { entry, $root, notification }) {
298
            messageQueueNotification('esIndexing', ids, next, entry, $root, notification, {
299
                title: 'global.default.success',
300
                message: 'global.notification-center.worker-listener.esIndexing.message',
301
                success: 'global.notification-center.worker-listener.esIndexing.messageSuccess',
302
            }, 50);
303
        },
304
    });
305
306
    factory.register('ImportExportMessage', {
307
        name: 'Shopware\\Core\\Content\\ImportExport\\Message\\ImportExportMessage',
308
        fn: function middleware(next, { entry, $root, notification }) {
309
            messageQueueNotification('importExport', ids, next, entry, $root, notification, {
310
                title: 'global.notification-center.worker-listener.importExport.title',
311
                message: 'global.notification-center.worker-listener.importExport.message',
312
                success: 'global.notification-center.worker-listener.importExport.messageSuccess',
313
            });
314
        },
315
    });
316
317
    factory.register('FlowIndexingMessage', {
318
        name: 'Shopware\\Core\\Content\\Flow\\Indexing\\FlowIndexingMessage',
319
        fn: function middleware(next, { entry, $root, notification }) {
320
            messageQueueNotification('flow', ids, next, entry, $root, notification, {
321
                title: 'global.notification-center.worker-listener.flow.title',
322
                message: 'global.notification-center.worker-listener.flow.message',
323
                success: 'global.notification-center.worker-listener.flow.messageSuccess',
324
            });
325
        },
326
    });
327
328
    factory.register('NewsletterRecipientIndexingMessage', {
329
        name: 'Shopware\\Core\\Content\\Newsletter\\DataAbstractionLayer\\NewsletterRecipientIndexingMessage',
330
        fn: function middleware(next, { entry, $root, notification }) {
331
            messageQueueNotification('newsletterRecipient', ids, next, entry, $root, notification, {
332
                title: 'global.notification-center.worker-listener.newsletterRecipient.title',
333
                message: 'global.notification-center.worker-listener.newsletterRecipient.message',
334
                success: 'global.notification-center.worker-listener.newsletterRecipient.messageSuccess',
335
            });
336
        },
337
    });
338
339
    return true;
340
}
341
342
function messageQueueNotification(
343
    key: string,
344
    ids: { [key: string]: { notificationId: string, didSendForegroundMessage: boolean}},
345
    next: (name?: string, opts?: NotificationWorkerOptions) => unknown,
346
    entry: { size: number },
347
    $root: Vue,
348
    notification: NotificationService,
349
    messages: { title: string, message: string, success: string, foregroundSuccessMessage?: string },
350
    multiplier = 1,
351
) {
352
    let notificationId = null;
353
    let didSendForegroundMessage = false;
354
355
    if (ids.hasOwnProperty((key))) {
356
        notificationId = ids[key].notificationId;
357
        didSendForegroundMessage = ids[key].didSendForegroundMessage;
358
    }
359
360
    if (entry.size) {
361
        entry.size *= multiplier;
362
    }
363
364
365
    const config: NotificationConfig = {
366
        title: $root.$tc(messages.title),
367
        message: $root.$tc(messages.message, entry.size),
368
        variant: 'info',
369
        metadata: {
370
            size: entry.size,
371
        },
372
        growl: false,
373
        isLoading: true,
374
    };
375
376
    // Create new notification
377
    if (entry.size && notificationId === null) {
378
        void notification.create(config).then((uuid) => {
379
            notificationId = uuid;
380
381
            ids[key] = {
382
                notificationId,
383
                didSendForegroundMessage: false,
384
            };
385
        });
386
        next();
387
    }
388
389
    // Update existing notification
390
    if (notificationId !== null) {
391
        config.uuid = notificationId;
392
393
        if (entry.size === 0) {
394
            config.title = $root.$tc(messages.title);
395
            config.message = $root.$t(messages.success) as string;
396
            config.isLoading = false;
397
398
            if (messages.foregroundSuccessMessage && !didSendForegroundMessage) {
399
                const foreground = { ...config };
400
                foreground.message = $root.$t(messages.foregroundSuccessMessage) as string;
401
                delete foreground.uuid;
402
                delete foreground.isLoading;
403
                foreground.growl = true;
404
                foreground.variant = 'success';
405
                void notification.create(foreground);
406
407
                ids[key] = {
408
                    notificationId,
409
                    didSendForegroundMessage: true,
410
                };
411
            }
412
413
            delete ids[key];
414
        }
415
        void notification.update(config);
416
    }
417
    next();
418
}
419