Baphomet is the dedicated bot for nulloctet matrix
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
7.4 KiB

  1. let fs = require('fs');
  2. let sdk = require('matrix-js-sdk');
  3. let message = require('./message');
  4. let utility = require('./utility');
  5. let { logger } = require('./logging');
  6. class Bot {
  7. constructor(config, buildInfo) {
  8. this.config = config;
  9. this.buildInfo = buildInfo;
  10. this.connected = false;
  11. }
  12. /**
  13. * Initialize the bot connection
  14. */
  15. init(messageCallback) {
  16. logger.info("Creating Matrix Client")
  17. this.client = sdk.createClient({
  18. baseUrl: this.config.baseUrl,
  19. userId: this.config.userId
  20. });
  21. this.client.on("sync", async (state, previousState, data) => {
  22. switch (state) {
  23. case "PREPARED":
  24. this.connected = true;
  25. await this.sendStatusStartup();
  26. await this.updateAvatar(process.env.NODE_PATH + '/assets/avatar.jpg');
  27. this.client.getJoinedRooms()
  28. .done((rooms) => {
  29. logger.info("Connected to: %o", rooms)
  30. });
  31. break;
  32. case "SYNCING":
  33. logger.debug("Syncing")
  34. break;
  35. case "RECONNECTING":
  36. logger.debug("Reconnecting");
  37. break;
  38. default:
  39. logger.error("Unexpected sync state: %s", state);
  40. process.exit(1);
  41. }
  42. });
  43. this.client.on("RoomMember.membership", (event, member) => {
  44. if (member.membership === "invite"
  45. && this.config.admin.indexOf(ember.userId) >= 0) {
  46. this.client.joinRoom(member.roomId).done(() => {
  47. logger.info("Auto-joined %s", member.roomId);
  48. });
  49. }
  50. });
  51. this.client.on("Room.timeline", messageCallback);
  52. return this;
  53. }
  54. async connect() {
  55. // logger.info("Initializing Crypto");
  56. // await bot.client.initCrypto();
  57. let botClient = this.client;
  58. let botConfig = this.config;
  59. let startServerConnection = () => {
  60. logger.info("Starting Matrix SDK Client");
  61. return this.client.startClient({
  62. initialSyncLimit: 0
  63. });
  64. }
  65. let attemptPasswordLogin = (botClient, botConfig) => {
  66. return botClient.loginWithPassword(botConfig.userId, botConfig.userPassword)
  67. .then((data) => {
  68. logger.info("Successfully authenticated with password %o", data);
  69. return startServerConnection();
  70. }, (err) => {
  71. logger.error("Failed to authenticate with password %o", err);
  72. });
  73. }
  74. logger.info("Authenticating With Server");
  75. if (typeof botConfig.accessToken !== 'undefined') {
  76. await botClient.loginWithToken(this.config.accessToken)
  77. .then((data) => {
  78. logger.info("Successfully authenticated with access token %o", data);
  79. return startServerConnection();
  80. }, (err) => {
  81. logger.error("Failed to authenticate with access token %o", err);
  82. if (typeof botConfig.userPassword !== 'undefined') {
  83. return attemptPasswordLogin(botClient, botConfig);
  84. } else {
  85. logger.error("No fallback password provided!");
  86. }
  87. });
  88. } else if (typeof botConfig.userPassword !== 'undefined') {
  89. await attemptPasswordLogin(botClient, botConfig);
  90. } else {
  91. logger.error("No authentication credentials available!");
  92. process.exit(1);
  93. }
  94. }
  95. updateAvatar(avatarFile, overwrite = false) {
  96. let matrixClient = this.client;
  97. let botConfig = this.config;
  98. let promises = [Promise.resolve(true)];
  99. if (this.connected) {
  100. promises.push(this.client.getProfileInfo(this.config.userId, "avatar_url")
  101. .then((existingAvatarUrl) => {
  102. logger.info("Recieved avatar_url: %o", existingAvatarUrl);
  103. if (typeof existingAvatarUrl !== 'undefined' && typeof existingAvatarUrl == 'object'
  104. && existingAvatarUrl.constructor === Object && Object.keys(existingAvatarUrl).length !== 0
  105. && !overwrite) {
  106. logger.info("Avatar already set");
  107. } else {
  108. logger.info("Setting avatar content from %s", avatarFile);
  109. let avatarFileBuffer = fs.readFileSync(avatarFile);
  110. logger.debug("Avatar Image Data %o", avatarFileBuffer);
  111. matrixClient.uploadContent(avatarFileBuffer, {
  112. name: botConfig.userId + " avatar",
  113. type: "image/jpeg",
  114. rawResponse: false
  115. }).then((uploadedAvatar) => {
  116. logger.info("Uploaded avatar %o", uploadedAvatar);
  117. matrixClient.setAvatarUrl(uploadedAvatar.content_uri)
  118. .then(() => {
  119. logger.info("Updated %s avatar to %s", botConfig.userId, uploadedAvatar.content_uri);
  120. return true;
  121. });
  122. });
  123. }
  124. }));
  125. } else {
  126. logger.warn("Attempting to update avatar while disconnected");
  127. }
  128. return Promise.all(promises);
  129. }
  130. sendStatusStartup() {
  131. let promises = [Promise.resolve(true)]
  132. if (this.connected) {
  133. this.config.statusRooms.forEach(roomId => {
  134. logger.debug("Notifying %s of startup", roomId);
  135. promises.push(this.client.sendMessage(
  136. roomId, message.createBasic("Started with version: " + this.buildInfo, message.types.NOTICE)
  137. ).then(() => {
  138. logger.debug("Notified %s of startup", roomId);
  139. }, (err) => {
  140. logger.error("Unable to send message to room %s because %s", roomId, err.errcode);
  141. }));
  142. });
  143. } else {
  144. logger.warn("Attempting to send startup message while disconnected");
  145. }
  146. return Promise.all(promises);
  147. }
  148. sendStatusShutdown() {
  149. let promises = [Promise.resolve(true)]
  150. if (this.connected) {
  151. this.config.statusRooms.forEach(roomId => {
  152. logger.debug("Notifying %s of shutdown", roomId);
  153. promises.push(this.client.sendMessage(
  154. roomId, message.createBasic("Shutting down", message.types.NOTICE)
  155. ).then(() => {
  156. logger.debug("Notified %s of shutdown", roomId);
  157. }, (err) => {
  158. logger.error("Unable to send message to room %s because %s", roomId, err.errcode);
  159. }));
  160. });
  161. } else {
  162. logger.warn("Attempting to send shutdown message while disconnected");
  163. }
  164. return Promise.all(promises);
  165. }
  166. }
  167. function create(config) {
  168. let buildInfo = utility.getBuildInfo();
  169. logger.info("Running version: %s", buildInfo);
  170. return new Bot(config, buildInfo);
  171. }
  172. exports.create = create;