You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			195 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
| const { isString, last } = require('lodash');
 | |
| 
 | |
| const { runMigrations } = require('./run_migrations');
 | |
| const Migration18 = require('./18');
 | |
| 
 | |
| // IMPORTANT: The migrations below are run on a database that may be very large
 | |
| // due to attachments being directly stored inside the database. Please avoid
 | |
| // any expensive operations, e.g. modifying all messages / attachments, etc., as
 | |
| // it may cause out-of-memory errors for users with long histories:
 | |
| // https://github.com/signalapp/Signal-Desktop/issues/2163
 | |
| const migrations = [
 | |
|   {
 | |
|     version: '12.0',
 | |
|     migrate(transaction, next) {
 | |
|       console.log('Migration 12');
 | |
|       console.log('creating object stores');
 | |
|       const messages = transaction.db.createObjectStore('messages');
 | |
|       messages.createIndex('conversation', ['conversationId', 'received_at'], {
 | |
|         unique: false,
 | |
|       });
 | |
|       messages.createIndex('receipt', 'sent_at', { unique: false });
 | |
|       messages.createIndex('unread', ['conversationId', 'unread'], {
 | |
|         unique: false,
 | |
|       });
 | |
|       messages.createIndex('expires_at', 'expires_at', { unique: false });
 | |
| 
 | |
|       const conversations = transaction.db.createObjectStore('conversations');
 | |
|       conversations.createIndex('inbox', 'active_at', { unique: false });
 | |
|       conversations.createIndex('group', 'members', {
 | |
|         unique: false,
 | |
|         multiEntry: true,
 | |
|       });
 | |
|       conversations.createIndex('type', 'type', {
 | |
|         unique: false,
 | |
|       });
 | |
|       conversations.createIndex('search', 'tokens', {
 | |
|         unique: false,
 | |
|         multiEntry: true,
 | |
|       });
 | |
| 
 | |
|       transaction.db.createObjectStore('groups');
 | |
| 
 | |
|       transaction.db.createObjectStore('sessions');
 | |
|       transaction.db.createObjectStore('identityKeys');
 | |
|       transaction.db.createObjectStore('preKeys');
 | |
|       transaction.db.createObjectStore('signedPreKeys');
 | |
|       transaction.db.createObjectStore('items');
 | |
| 
 | |
|       console.log('creating debug log');
 | |
|       transaction.db.createObjectStore('debug');
 | |
| 
 | |
|       next();
 | |
|     },
 | |
|   },
 | |
|   {
 | |
|     version: '13.0',
 | |
|     migrate(transaction, next) {
 | |
|       console.log('Migration 13');
 | |
|       console.log('Adding fields to identity keys');
 | |
|       const identityKeys = transaction.objectStore('identityKeys');
 | |
|       const request = identityKeys.openCursor();
 | |
|       const promises = [];
 | |
|       request.onsuccess = event => {
 | |
|         const cursor = event.target.result;
 | |
|         if (cursor) {
 | |
|           const attributes = cursor.value;
 | |
|           attributes.timestamp = 0;
 | |
|           attributes.firstUse = false;
 | |
|           attributes.nonblockingApproval = false;
 | |
|           attributes.verified = 0;
 | |
|           promises.push(
 | |
|             new Promise((resolve, reject) => {
 | |
|               const putRequest = identityKeys.put(attributes, attributes.id);
 | |
|               putRequest.onsuccess = resolve;
 | |
|               putRequest.onerror = e => {
 | |
|                 console.log(e);
 | |
|                 reject(e);
 | |
|               };
 | |
|             })
 | |
|           );
 | |
|           cursor.continue();
 | |
|         } else {
 | |
|           // no more results
 | |
|           // eslint-disable-next-line more/no-then
 | |
|           Promise.all(promises).then(() => {
 | |
|             next();
 | |
|           });
 | |
|         }
 | |
|       };
 | |
|       request.onerror = event => {
 | |
|         console.log(event);
 | |
|       };
 | |
|     },
 | |
|   },
 | |
|   {
 | |
|     version: '14.0',
 | |
|     migrate(transaction, next) {
 | |
|       console.log('Migration 14');
 | |
|       console.log('Adding unprocessed message store');
 | |
|       const unprocessed = transaction.db.createObjectStore('unprocessed');
 | |
|       unprocessed.createIndex('received', 'timestamp', { unique: false });
 | |
|       next();
 | |
|     },
 | |
|   },
 | |
|   {
 | |
|     version: '15.0',
 | |
|     migrate(transaction, next) {
 | |
|       console.log('Migration 15');
 | |
|       console.log('Adding messages index for de-duplication');
 | |
|       const messages = transaction.objectStore('messages');
 | |
|       messages.createIndex('unique', ['source', 'sourceDevice', 'sent_at'], {
 | |
|         unique: true,
 | |
|       });
 | |
|       next();
 | |
|     },
 | |
|   },
 | |
|   {
 | |
|     version: '16.0',
 | |
|     migrate(transaction, next) {
 | |
|       console.log('Migration 16');
 | |
|       console.log('Dropping log table, since we now log to disk');
 | |
|       transaction.db.deleteObjectStore('debug');
 | |
|       next();
 | |
|     },
 | |
|   },
 | |
|   {
 | |
|     version: 17,
 | |
|     async migrate(transaction, next) {
 | |
|       console.log('Migration 17');
 | |
| 
 | |
|       const start = Date.now();
 | |
| 
 | |
|       const messagesStore = transaction.objectStore('messages');
 | |
|       console.log('Create index from attachment schema version to attachment');
 | |
|       messagesStore.createIndex('schemaVersion', 'schemaVersion', {
 | |
|         unique: false,
 | |
|       });
 | |
| 
 | |
|       const duration = Date.now() - start;
 | |
| 
 | |
|       console.log(
 | |
|         'Complete migration to database version 17',
 | |
|         `Duration: ${duration}ms`
 | |
|       );
 | |
|       next();
 | |
|     },
 | |
|   },
 | |
|   {
 | |
|     version: 18,
 | |
|     migrate(transaction, next) {
 | |
|       console.log('Migration 18');
 | |
| 
 | |
|       const start = Date.now();
 | |
|       Migration18.run(transaction);
 | |
|       const duration = Date.now() - start;
 | |
| 
 | |
|       console.log(
 | |
|         'Complete migration to database version 18',
 | |
|         `Duration: ${duration}ms`
 | |
|       );
 | |
|       next();
 | |
|     },
 | |
|   },
 | |
| ];
 | |
| 
 | |
| const database = {
 | |
|   id: 'signal',
 | |
|   nolog: true,
 | |
|   migrations,
 | |
| };
 | |
| 
 | |
| exports.run = ({ Backbone, databaseName } = {}) =>
 | |
|   runMigrations({
 | |
|     Backbone,
 | |
|     database: Object.assign(
 | |
|       {},
 | |
|       database,
 | |
|       isString(databaseName) ? { id: databaseName } : {}
 | |
|     ),
 | |
|   });
 | |
| 
 | |
| exports.getDatabase = () => ({
 | |
|   name: database.id,
 | |
|   version: exports.getLatestVersion(),
 | |
| });
 | |
| 
 | |
| exports.getLatestVersion = () => {
 | |
|   const lastMigration = last(migrations);
 | |
|   if (!lastMigration) {
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   return lastMigration.version;
 | |
| };
 |