import CustomSimpleBotRecord from "./models/CustomSimpleBotRecord"; import { Cache, CACHE_SIMPLE_BOTS } from "../MemoryCache"; import { MatrixLiteClient } from "../matrix/MatrixLiteClient"; import config from "../config"; import * as randomString from "random-string"; import { LogService } from "matrix-js-snippets"; export interface CachedSimpleBot extends SimpleBotTemplate { id: number; type: string; } export interface SimpleBotTemplate { name: string; avatarUrl: string; description: string; isEnabled: boolean; isPublic: boolean; userId: string; accessToken: string; } export interface CachedProfile { userId: string; displayName: string; avatarMxc: string; } export class BotStore { public static readonly TYPE_PREFIX = "custom_"; public static async createCustom(template: SimpleBotTemplate): Promise { const newType = `${BotStore.TYPE_PREFIX}${randomString({length: 32})}`; const bot = await CustomSimpleBotRecord.create({...template, type: newType}); return BotStore.mapAndCacheCustom(bot); } public static async updateCustom(id: number, template: SimpleBotTemplate): Promise { const record = await CustomSimpleBotRecord.findByPk(id); if (!record) return null; record.name = template.name; record.avatarUrl = template.avatarUrl; record.description = template.description; record.isEnabled = template.isEnabled; record.isPublic = template.isPublic; record.userId = template.userId; record.accessToken = template.accessToken; await record.save(); return BotStore.mapAndCacheCustom(record); } public static async deleteCustom(id: number): Promise { const record = await CustomSimpleBotRecord.findByPk(id); if (!record) return null; await record.destroy(); Cache.for(CACHE_SIMPLE_BOTS).del("bots"); return true; } public static async removeCustomByTypeFromRoom(type: string, roomId: string): Promise { const record = await CustomSimpleBotRecord.findOne({where: {type: type}}); if (!record) return null; try { const client = new MatrixLiteClient(record.accessToken); await client.leaveRoom(roomId); } catch (e) { LogService.error("BotStore", "Error leaving room " + roomId + " for integration type " + type); LogService.error("BotStore", e); throw new Error("Error leaving room"); } } public static async getCustomBot(id: number): Promise { const bots = await BotStore.getCustomBots(); return bots.find(b => b.id === id); } public static async getCustomBots(): Promise { if (!Cache.for(CACHE_SIMPLE_BOTS).get("bots")) { const bots = await CustomSimpleBotRecord.findAll(); const cached = []; await Promise.all(bots.map(async (b) => { cached.push(await BotStore.mapAndCacheCustom(b)); return Promise.resolve(); })); Cache.for(CACHE_SIMPLE_BOTS).put("bots", cached); } return Cache.for(CACHE_SIMPLE_BOTS).get("bots").map(b => BotStore.cloneBot(b)); } public static async getProfile(userId: string): Promise { const key = "profile_" + userId; if (!Cache.for(CACHE_SIMPLE_BOTS).get(key)) { const client = new MatrixLiteClient(config.homeserver.accessToken); const profile = await client.getProfile(userId); const cached = {userId, displayName: profile.displayname, avatarMxc: profile.avatar_url}; Cache.for(CACHE_SIMPLE_BOTS).put(key, cached); } return Cache.for(CACHE_SIMPLE_BOTS).get(key); } private static async mapAndCacheCustom(bot: CustomSimpleBotRecord): Promise { Cache.for(CACHE_SIMPLE_BOTS).del("bots"); return { id: bot.id, type: bot.type, name: bot.name, avatarUrl: bot.avatarUrl, description: bot.description, isEnabled: bot.isEnabled, isPublic: bot.isPublic, userId: bot.userId, accessToken: bot.accessToken, }; } private static cloneBot(bot: CachedSimpleBot): CachedSimpleBot { return { id: bot.id, type: bot.type, name: bot.name, avatarUrl: bot.avatarUrl, description: bot.description, isEnabled: bot.isEnabled, isPublic: bot.isPublic, userId: bot.userId, accessToken: bot.accessToken, }; } private constructor() { } }