Google Chat Bot. Properties
Перед вами новий пост і знов піде мова про розробку ботів для Google Chat’ів. Сьогодні ми навчимося додавати статистику використання до нашого бота. Відразу невеликий спойлер — ми будемо вести статистику в боті, не виходячи за межі нашого коду та не використовуючи інші сервіси. Ми познайомимось з таким функціоналом як Properties. Спочатку я хочу розповісти … Continue reading Google Chat Bot. Properties
Перед вами новий пост і знов піде мова про розробку ботів для Google Chat’ів. Сьогодні ми навчимося додавати статистику використання до нашого бота.
Відразу невеликий спойлер — ми будемо вести статистику в боті, не виходячи за межі нашого коду та не використовуючи інші сервіси. Ми познайомимось з таким функціоналом як Properties.
Спочатку я хочу розповісти що я хочу отримати у якості результату. За моїм задумом, бот буде рахувати скільки та які команди використовувалася, а також віддавати цю статистику за спеціальним запитом до бота, крім цього, я хочу щоб користувачі могли теж отримувати свою статистику використання бота.
Тож ось вам перелік даних які будемо збирати, не питайте чому саме ці дані, бо у самурая немає цілі, є лише шлях:
- основні події: повідомлення, кліки, додавання та вилучення зі спейсу
- виклик slash-команд – які команди використовували та скільки разів
- виклик функцій, які прив’язані до кнопок на картках
Збір та організація статистики
Перше питання, звідкіля брати потрібну інформацію? Вся інформація про події в нас доступна у об’єкті event
який нам приходить до 4-х ключових функцій які в нас лежать у файлі Code.gs
:
/** * Responds to a MESSAGE event in Google Chat. * * @param {Object} event the event object from Google Chat */ function onMessage(event) { // ... } /** * Responds to a CARD_CLICKED event in Google Chat. * * @param {Object} event the event object from Google Chat */ function onCardClick(event) { // ... } /** * Responds to an ADDED_TO_SPACE event in Google Chat. * * @param {Object} event the event object from Google Chat */ function onAddToSpace(event) { // ... } /** * Responds to a REMOVED_FROM_SPACE event in Google Chat. * * @param {Object} event the event object from Google Chat */ function onRemoveFromSpace(event) { // ... }
Щоб зібрати дані для статистики нам треба лише вбудувати виклик функції, яка і буде збирати дані:
/** * Responds to a MESSAGE event in Google Chat. * * @param {Object} event the event object from Google Chat */ function onMessage(event) { collectStatisticData(event) // ... } /** * Responds to a CARD_CLICKED event in Google Chat. * * @param {Object} event the event object from Google Chat */ function onCardClick(event) { collectStatisticData(event) // ... } /** * Responds to an ADDED_TO_SPACE event in Google Chat. * * @param {Object} event the event object from Google Chat */ function onAddToSpace(event) { collectStatisticData(event) // ... } /** * Responds to a REMOVED_FROM_SPACE event in Google Chat. * * @param {Object} event the event object from Google Chat */ function onRemoveFromSpace(event) { collectStatisticData(event) // ... }
А ось саму функцію треба ще написати, вона повинна аналізувати наступні дані:
/** * Collect event data and count statistics for functions and commands * * @param {Object} event the event object from Google Chat */ function collectStatisticData(event) { // MESSAGE or CARD_CLICKED or ADDED_TO_SPACE or REMOVED_FROM_SPACE event.type // if user used a slash command event.message.slashCommand.commandId // if user clicked something on the card and call function event.common.invokedFunction }
Тож наче все зрозуміло, тепер нам би розібратися де зберігати цю інформацію, і нам в цьому допоможуть Properties
Робота з Properties
Apps Script мають можливість використовувати 3 типи сховищ для службових даних:
ScriptProperties
— сховище даних вашого додатку, воно потрібно щоб зберігати загальні налаштування скрипта на кшталт ключів доступу, кредів, тощоUserProperties
— сховище даних поточного користувача, воно прив’язано до вашого додатку, його використовують щоб зберігати налаштування користувача відносно вашого додатку, наприклад — вибір метричної системи або якоїсь іншоїDocumentProperties
— це сховище пов’язане з відкритим документом, це не наш випадок, але і не розповісти про цього я не міг
При використанні слід пам’ятити про обмеження при використанні Properties Service — це 9KB на значення, та 500KB загалом на сховище. Також слід врахувати, що є обмеження на кількість read/write операцій — 50 000 на день для gmail акаунтів там 500 000 для Google Workspace.
Для реалізації мого задуму нам знадобляться наступні методи:
PropertiesService.getScriptProperties()
— сховище даних вашого додатку, тут будемо зберігати загальну статистику використанняPropertiesService.getUserProperties()
— сховище даних поточного користувача, тут будемо зберігати статистику користувача
Це key-value сховища, для роботи з якими є декілька методів, серед яких нам наразі потрібні лише getProperty(key)
та setProperty(key, value)
.
Давайте додамо використання сховища ScriptProperties
до нашої функції collectStatisticData(event)
:
/** * Collect event data and count statistics for functions and commands * * @param {Object} event the event object from Google Chat */ function collectStatisticData(event) { const scriptProperties = PropertiesService.getScriptProperties(); let eventCounter = scriptProperties.getProperty(event.type) || 0; scriptProperties.setProperty(event.type, parseInt(eventCounter) + 1); // Increment slash command counter if applicable if (event.message && event.message.slashCommand) { let slashCommandCounter = scriptProperties.getProperty('SLASH_' + event.message.slashCommand.commandId) || 0 scriptProperties.setProperty('SLASH_' + event.message.slashCommand.commandId, parseInt(slashCommandCounter) + 1) } // Increment invoked function counter if applicable if (event.common && event.common.invokedFunction) { let functionCounter = scriptProperties.getProperty('FNC_' + event.common.invokedFunction) || 0 scriptProperties.setProperty('FNC_' + event.common.invokedFunction, parseInt(functionCounter) + 1) } }
Виглядає досить «дивно», та ми ще повернемося до цього функціоналу, давайте подивимось де ми можемо подивитися на дані які ми зберігаємо. Для цього треба перейти до вкладки Project Settings
, і проскроліть до розділу Script Properties
:
А тепер трошки оптимізуємо наявний спосіб збереження, я пропоную зберігати дані у JSON форматі:
{ events: { MESSAGE: 0, CARD_CLICKED: 0, ADDED_TO_SPACE: 0, REMOVED_FROM_SPACE: 0, }, commands: {}, functions: {}, }
Тепер внесемо зміни до функції збору статистики:
/** * Collect event data and count statistics for functions and commands * * @param {Object} event the event object from Google Chat */ function collectStatisticData(event) { const scriptProperties = PropertiesService.getScriptProperties(); let statistics = scriptProperties.getProperty('STATS'); if (statistics) { statistics = JSON.parse(statistics) } else { statistics = { events: { MESSAGE: 0, CARD_CLICKED: 0, ADDED_TO_SPACE: 0, REMOVED_FROM_SPACE: 0, }, commands: {}, functions: {}, } } statistics[event.type]++ // Increment slash command counter if applicable if (event.message && event.message.slashCommand) { const { commandId } = event.message.slashCommand statistics.commands[commandId] = (statistics.commands[commandId] || 0) + 1 } // Increment invoked function counter if applicable if (event.common && event.common.invokedFunction) { const functionName = event.common.invokedFunction statistics.functions[functionName] = (statistics.functions[functionName] || 0) + 1 } scriptProperties.setProperty('STATS', JSON.stringify(statistics)) }
Зверніть увагу в цьому прикладі, що дані які ми отримуємо зі сховища то є текст, і нам ще треба його розпарсити. Звісно перед зберіганням треба JSON знов перетворити на текст. І це ще досить непогано, бо у попередній версії цієї функції нам треба була кожного разу парсити текст, щоб працювати з цифрами