hubot-stackstorm
Version:
A hubot plugin for integrating with StackStorm event-driven infrastructure automation platform.
226 lines (194 loc) • 8.02 kB
JavaScript
// Copyright 2019 Extreme Networks, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
;
var utils = require('./utils.js');
// NOTE: This is being reused between the Slack adapter and the Mattermost
// adapter. If we need to tweak it for Mattermost, we should refactor it
// into a class, then inherit from it and override specific methods in
// Mattermost adapter.
var buildMessagesWithChunkedFieldValue = function (msg) {
var msgs;
if (JSON.stringify(msg).length <= utils.SLACK_MAX_MESSAGE_SIZE) {
msgs = [msg];
} else {
// Cry loudly
var error_msg = utils.constructFromAttrs(msg, ['icon_emoji', 'username']);
error_msg.text = "ERROR: Could not complete request because there was too much data to send";
msgs = [error_msg];
}
return msgs;
};
var buildMessagesWithSingleFieldInAttachment = function (msg) {
var msgs = [], msg_length = JSON.stringify(msg).length;
if (msg_length <= utils.SLACK_MAX_MESSAGE_SIZE) {
msgs = [msg];
} else {
// Chunk up the field value
var msg_meta_length = msg_length - msg.attachments[0].fields[0].value.length;
var field_chunk_size = utils.SLACK_MAX_MESSAGE_SIZE - msg_meta_length;
// If the fields cause the meta length to be larger than
// utils.SLACK_MAX_MESSAGE_SIZE, then text_chunk_size will be negative.
// This simply means that we don't need to chunk up the attachment text,
// so set text_chunk_size back to utils.SLACK_MAX_MESSAGE_SIZE.
if (field_chunk_size < 0) { field_chunk_size = utils.SLACK_MAX_MESSAGE_SIZE; }
var field_value_chunks = utils.getTextChunks(msg.attachments[0].fields[0].value, field_chunk_size);
field_value_chunks.forEach(function (value_chunk) {
var field = Object.assign({}, msg.attachments[0].fields[0]);
var msg_attachment_field_value = Object.assign({}, msg, {attachments: [{fields: [field]}]});
msg_attachment_field_value.attachments[0].fields[0].value = value_chunk;
msgs = msgs.concat(buildMessagesWithChunkedFieldValue(msg_attachment_field_value));
});
}
return msgs;
};
var buildMessagesWithChunkedAttachmentText = function (msg) {
var msgs = [];
if (JSON.stringify(msg).length <= utils.SLACK_MAX_MESSAGE_SIZE) {
msgs = [msg];
} else {
// Send each field individually
msg.attachments[0].fields.forEach(function (field) {
var msg_attachment_single_field = Object.assign({}, msg, {attachments: [{fields: [field]}]});
msgs = msgs.concat(buildMessagesWithSingleFieldInAttachment(msg_attachment_single_field));
});
}
return msgs;
};
var buildMessagesWithSingleAttachment = function (msg) {
var msgs = [], msg_length = JSON.stringify(msg).length;
if (msg_length <= utils.SLACK_MAX_MESSAGE_SIZE) {
msgs = [msg];
} else {
// Chunk up the attachment text
// NOTE: In order to do this properly, we will need to break up text into
// <4K chunks and send them individually. However, once we have
// broken one attachment into many chunks, we should only send some
// attributes on the first chunk or the last chunk.
//
// send every message:
// icon_emoji
// username
// color
//
// sent in the first message:
// fallback
// pretext
// author_name
// author_link
// author_icon
// title
// title_link
// image_url
// thumb_url
//
// sent in the last message:
// fields
// footer
// footer_icon
// ts (timestamp)
//
// This should simulate a single attachment as best we can:
//
// username APP 0:00 PM
// [icon_emoji] |
// | [author_icon] author_name
// | title
// | text
// |
//
// username APP 0:00 PM
// [icon_emoji] |
// | text
//
// username APP 0:00 PM
// [icon_emoji] |
// | text
//
// username APP 0:00 PM
// [icon_emoji] |
// | fields.1.title
// | fields.1.value
// |
// | [footer_icon] footer | ts
var msg_meta_length = msg_length - msg.attachments[0].text.length;
var text_chunk_size = utils.SLACK_MAX_MESSAGE_SIZE - msg_meta_length;
// If the fields cause the meta length to be larger than
// utils.SLACK_MAX_MESSAGE_SIZE, then text_chunk_size will be negative.
// This simply means that we don't need to chunk up the attachment text,
// so set text_chunk_size back to utils.SLACK_MAX_MESSAGE_SIZE.
if (text_chunk_size < 0) { text_chunk_size = utils.SLACK_MAX_MESSAGE_SIZE; }
var text_chunks = utils.getTextChunks(msg.attachments[0].text, text_chunk_size);
var first_data_to_send, last_data_to_send;
first_data_to_send = Object.assign({}, msg);
first_data_to_send.attachments = [
utils.constructFromAttrs(msg.attachments[0], [
'fallback', 'pretext', 'author_name', 'author_link', 'author_icon',
'title', 'title_link', 'image_url', 'thumb_url'
])
];
first_data_to_send.attachments[0].text = text_chunks[0];
last_data_to_send = Object.assign({}, msg);
last_data_to_send.attachments = [
utils.constructFromAttrs(msg.attachments[0], [
'fields', 'footer', 'footer_icon', 'ts'
])
];
if (last_data_to_send.text) { delete last_data_to_send.text; }
if (text_chunks.length > 1) {
last_data_to_send.attachments[0].text = text_chunks[text_chunks.length-1];
}
msgs = msgs.concat(buildMessagesWithChunkedAttachmentText(first_data_to_send));
text_chunks.forEach(function (text_chunk, i) {
if (i === 0 || i === text_chunks.length-1) { return; }
var data_to_send = Object.assign({}, msg, {attachments: [{text: text_chunk}]});
if (data_to_send.text) { delete data_to_send.text; }
msgs = msgs.concat(buildMessagesWithChunkedAttachmentText(data_to_send));
});
msgs = msgs.concat(buildMessagesWithChunkedAttachmentText(last_data_to_send));
}
return msgs;
};
var buildMessagesChunkedText = function (msg) {
var msgs = [], msg_length = JSON.stringify(msg).length;
if (msg_length <= utils.SLACK_MAX_MESSAGE_SIZE) {
msgs = [msg];
} else {
// Don't try to chunk up each attachment yet, just send them all
// individually
msg.attachments.forEach(function (attachment, i) {
var msg_with_single_attachment = Object.assign({}, msg, {attachments: [attachment]});
msgs = msgs.concat(buildMessagesWithSingleAttachment(msg_with_single_attachment));
});
}
return msgs;
};
var buildMessages = function (msg) {
var msgs = [], msg_length = JSON.stringify(msg).length;
if (msg_length <= utils.SLACK_MAX_MESSAGE_SIZE) {
msgs = [msg];
} else if (msg.text) {
var msg_meta_length = msg_length - msg.text.length - JSON.stringify(msg.attachments).length;
var text_chunk_size = utils.SLACK_MAX_MESSAGE_SIZE - msg_meta_length;
var text_chunks = utils.getTextChunks(msg.text, text_chunk_size);
text_chunks.forEach(function (text_chunk, i) {
var msg_with_text_chunk = Object.assign({}, msg, {text: text_chunk});
if (i !== text_chunks.length-1) { delete msg_with_text_chunk.attachments; }
msgs = msgs.concat(buildMessagesChunkedText(msg_with_text_chunk));
});
} else {
msgs = msgs.concat(buildMessagesChunkedText(msg));
}
return msgs;
};
exports.buildMessages = buildMessages;