import intel from 'intel'; import get from 'lodash.get'; import { SitespeedioPlugin } from '@sitespeed.io/plugin'; import send from './send.js'; import { throwIfMissing } from '../../support/util.js'; const log = intel.getLogger('sitespeedio.plugin.matrix'); function getBrowserData(data) { return data && data.browser ? `${data.browser.name} ${data.browser.version} ${get( data, 'android.model', '' )} ${get(data, 'android.androidVersion', '')} ${get( data, 'android.id', '' )} ` : ''; } export default class MatrixPlugin extends SitespeedioPlugin { constructor(options, context, queue) { super({ name: 'matrix', options, context, queue }); } open(context, options = {}) { this.matrixOptions = options.matrix || {}; this.options = options; log.info('Starting the matrix plugin'); throwIfMissing(options.matrix, ['accessToken', 'host', 'room'], 'matrix'); this.resultUrls = context.resultUrls; this.errorTexts = ''; this.waitForUpload = false; this.alias = {}; } async processMessage(message) { const options = this.matrixOptions; switch (message.type) { case 'browsertime.browser': { this.browserData = message.data; break; } case 'gcs.setup': case 'ftp.setup': case 's3.setup': { this.waitForUpload = true; break; } case 'browsertime.alias': { this.alias[message.url] = message.data; break; } case 'sitespeedio.render': { if (this.errorTexts !== '') { const room = get(options, 'rooms.error', options.room); try { const answer = await send( options.host, room, options.accessToken, this.errorTexts ); log.debug('Got %j from the matrix server', answer); } catch { // TODO what todo? } } break; } case 'browsertime.config': { if (message.data.screenshot === true) { this.screenshotType = message.data.screenshotType; } break; } case 'error': { // We can send too many messages to Matrix and get 429 so instead // we bulk send them all one time if (options.messages.includes('error')) { this.errorTexts += `⚠️ Error from ${ message.source } testing ${message.url || ''}
${message.data}
`; } break; } case 'budget.result': { if (options.messages.includes('budget')) { let text = ''; // We have failing URLs in the budget if (Object.keys(message.data.failing).length > 0) { const failingURLs = Object.keys(message.data.failing); text += `

⚠️ Budget failing (${failingURLs.length} URLs)

`; text += `

${ get(this.options, 'name', '') + ' ' }${getBrowserData(this.browserData)}

`; for (let url of failingURLs) { text += `
❌ ${url}`; text += this.resultUrls.hasBaseUrl() ? ` (result - screenshot)
` : ''; text += '`; } } if (Object.keys(message.data.error).length > 0) { const errorURLs = Object.keys(message.data.error); text += `

⚠️ Budget errors testing ${errorURLs.length} URLs

`; for (let url of errorURLs) { text += `
❌ ${url}
`; text += `
${message.data.error[url]}
`; } } if ( Object.keys(message.data.error).length === 0 && Object.keys(message.data.failing).length === 0 ) { text += `

🎉 All (${ Object.keys(message.data.working).length }) URLs passed the budget.

`; text += `

${ get(this.options, 'name', '') + ' ' }${getBrowserData(this.browserData)}

`; } if (this.waitForUpload) { this.budgetText = text; } else { const room = get(options, 'rooms.budget', options.room); await send(options.host, room, options.accessToken, text); } } break; } case 'gcs.finished': case 'scp.finished': case 'ftp.finished': case 's3.finished': { if (this.waitForUpload && options.messages.includes('budget')) { const room = get(options, 'rooms.budget', options.room); await send(options.host, room, options.accessToken, this.budgetText); } break; } } } } export function messageTypes() { return ['error', 'budget']; }