Add `/.well-known/matrix/client` for Matrix clients
[gitter.git] / scripts / utils / migrate-plumbed-matrix-rooms.js
blob772f3391988ef58858a5aff249f3bfdf9f177c5b
1 #!/usr/bin/env node
2 'use strict';
4 process.env.DISABLE_API_LISTEN = '1';
6 const path = require('path');
7 const fs = require('fs');
8 const yargs = require('yargs');
9 const LineByLineReader = require('line-by-line');
10 const shutdown = require('shutdown');
11 const persistence = require('gitter-web-persistence');
12 const troupeService = require('gitter-web-rooms/lib/troupe-service');
14 const installBridge = require('gitter-web-matrix-bridge');
15 const matrixBridge = require('gitter-web-matrix-bridge/lib/matrix-bridge');
16 const MatrixUtils = require('gitter-web-matrix-bridge/lib/matrix-utils');
18 const matrixUtils = new MatrixUtils(matrixBridge);
20 const opts = yargs
21   .option('room-store-file', {
22     required: true,
23     description: 'path to the room store file (room-store.db)',
24     string: true
25   })
26   .option('delay', {
27     alias: 'd',
28     type: 'number',
29     required: true,
30     default: 2000,
31     description: 'Delay(in milliseconds) between rooms to update to not overwhelm the homeserver'
32   })
33   .option('dry-run', {
34     description: 'Dry-run. Do not execute, just print',
35     type: 'boolean',
36     default: false
37   })
38   .help('help')
39   .alias('help', 'h').argv;
41 async function migrateRoom(roomEntry) {
42   console.log('Migrating roomEntry', roomEntry);
44   if (!opts.dryRun) {
45     const matrixRoomId = roomEntry.matrix_id;
46     const gitterRoomUri = roomEntry.remote_id;
48     const gitterRoom = await troupeService.findByUri(gitterRoomUri);
50     const bridgeIntent = matrixBridge.getIntent();
51     await bridgeIntent.join(matrixRoomId, ['matrix.org']);
53     const existingPortalBridgeEntry = await persistence.MatrixBridgedRoom.findOne({
54       troupeId: gitterRoom.id
55     });
57     if (existingPortalBridgeEntry) {
58       console.log(
59         `Found portal room that already exists as well ${existingPortalBridgeEntry.matrixRoomId}`
60       );
61       const matrixContent = {
62         body: `This room is being migrated, you can use [\`/join ${matrixRoomId} matrix.org\`](https://matrix.to/#/${matrixRoomId}?via=matrix.org) to get to the new room`,
63         formatted_body: `This room is being migrated, you can use <a href="https://matrix.to/#/${matrixRoomId}?via=matrix.org"><code>/join ${matrixRoomId} matrix.org</code></a> to get to the new room`,
64         format: 'org.matrix.custom.html',
65         msgtype: 'm.notice'
66       };
67       const intent = matrixBridge.getIntent();
68       await intent.sendMessage(existingPortalBridgeEntry.matrixRoomId, matrixContent);
69     }
71     await persistence.MatrixBridgedRoom.update(
72       { troupeId: gitterRoom.id },
73       {
74         $set: {
75           matrixRoomId
76         }
77       }
78     );
80     await matrixUtils.ensureRoomAliasesForGitterRoom(matrixRoomId, gitterRoom);
81   }
84 const FAILED_LOG_PATH = path.resolve('/tmp/failed-migrated-plumbed-matrix-rooms.db');
86 async function processLine(line) {
87   const roomEntry = JSON.parse(line);
89   console.log('Processing roomEntry', roomEntry);
91   if (!roomEntry.matrix_id || !roomEntry.remote_id) {
92     return;
93   }
94   // We're only looking for plumbed rooms
95   if (roomEntry && roomEntry.data && roomEntry.data.portal) {
96     return;
97   }
99   try {
100     await migrateRoom(roomEntry);
101   } catch (err) {
102     console.error('Error migrating room', err, err.stack);
103     fs.appendFileSync(FAILED_LOG_PATH, JSON.stringify(roomEntry) + '\n');
104   }
106   // Put a delay between each time we process a room
107   // to avoid overwhelming and hitting the rate-limits on the Matrix homeserver
108   if (opts.delay > 0) {
109     await new Promise(resolve => {
110       setTimeout(resolve, opts.delay);
111     });
112   }
115 async function run() {
116   try {
117     fs.writeFileSync(FAILED_LOG_PATH, '');
118   } catch (err) {
119     console.log('Failed to create the log file for failed rooms');
120     throw err;
121   }
123   try {
124     console.log('Setting up Matrix bridge');
125     await installBridge();
127     const lr = new LineByLineReader(opts.roomStoreFile);
129     lr.on('error', err => {
130       console.error('Error while reading lines', err);
131       shutdown.shutdownGracefully(1);
132     });
134     lr.on('line', async line => {
135       lr.pause();
137       try {
138         await processLine(line);
139       } catch (err) {
140         console.error(err, err.stack);
141       }
143       lr.resume();
144     });
146     lr.on('end', () => {
147       console.log('All lines processed');
149       shutdown.shutdownGracefully();
150     });
151   } catch (err) {
152     console.error(err, err.stack);
153     shutdown.shutdownGracefully(1);
154   }
157 run();