-
Notifications
You must be signed in to change notification settings - Fork 14
feat(cozy-pouch-link): Handle shared drive recipients' files #1632
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
0468550
2d81ae7
0566aa7
3099ef5
ac5fb47
5cc7370
ca031ae
c14c598
c6c1552
c6de1b6
8c76e4f
ee06202
3a11e12
7228d02
78ff1b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,4 @@ | ||
import fromPairs from 'lodash/fromPairs' | ||
import forEach from 'lodash/forEach' | ||
import get from 'lodash/get' | ||
import { isMobileApp } from 'cozy-device-helper' | ||
|
||
import { PouchLocalStorage } from './localStorage' | ||
|
@@ -55,44 +53,26 @@ class PouchManager { | |
} | ||
|
||
async init() { | ||
const pouchPlugins = get(this.options, 'pouch.plugins', []) | ||
const pouchOptions = get(this.options, 'pouch.options', {}) | ||
const pouchPlugins = this.options?.pouch?.plugins ?? [] | ||
const pouchOptions = this.options?.pouch?.options ?? {} | ||
if (!pouchOptions.view_update_changes_batch_size) { | ||
pouchOptions.view_update_changes_batch_size = DEFAULT_VIEW_UPDATE_BATCH | ||
} | ||
|
||
forEach(pouchPlugins, plugin => this.PouchDB.plugin(plugin)) | ||
this.pouches = fromPairs( | ||
this.doctypes.map(doctype => { | ||
const dbName = getDatabaseName(this.options.prefix, doctype) | ||
const pouch = new this.PouchDB( | ||
getDatabaseName(this.options.prefix, doctype), | ||
pouchOptions | ||
) | ||
|
||
return [dbName, pouch] | ||
}) | ||
) | ||
|
||
const dbNames = Object.keys(this.pouches) | ||
dbNames.forEach(dbName => { | ||
// Set query engine for all databases | ||
const doctype = getDoctypeFromDatabaseName(dbName) | ||
this.setQueryEngine(dbName, doctype) | ||
}) | ||
this.pouches = {} | ||
this.doctypesReplicationOptions = | ||
this.options.doctypesReplicationOptions || {} | ||
for (const doctype of this.doctypes) { | ||
this.addDoctype(doctype, this.doctypesReplicationOptions[doctype]) | ||
} | ||
|
||
// Persist db names for old browsers not supporting indexeddb.databases() | ||
// This is useful for cleanup. | ||
// Note PouchDB adds itself the _pouch_ prefix | ||
const pouchDbNames = dbNames.map(dbName => `_pouch_${dbName}`) | ||
await this.storage.persistDatabasesNames(pouchDbNames) | ||
await this.persistDatabasesNames() | ||
|
||
/** @type {Record<string, import('./types').SyncInfo>} - Stores synchronization info per doctype */ | ||
this.syncedDoctypes = await this.storage.getPersistedSyncedDoctypes() | ||
this.warmedUpQueries = await this.storage.getPersistedWarmedUpQueries() | ||
this.getReplicationURL = this.options.getReplicationURL | ||
this.doctypesReplicationOptions = | ||
this.options.doctypesReplicationOptions || {} | ||
this.listenerLaunched = false | ||
|
||
// We must ensure databases exist on the remote before | ||
|
@@ -358,6 +338,65 @@ class PouchManager { | |
this.warmedUpQueries = {} | ||
await this.storage.destroyWarmedUpQueries() | ||
} | ||
|
||
/** | ||
* Adds a new doctype to the list of managed doctypes, sets its replication options, | ||
* creates a new PouchDB instance for it, and sets up the query engine. | ||
* | ||
* @param {string} doctype - The name of the doctype to add. | ||
* @param {Object} replicationOptions - The replication options for the doctype. | ||
*/ | ||
async addDoctype(doctype, replicationOptions) { | ||
if (!this.options?.doctypesReplicationOptions) { | ||
this.options.doctypesReplicationOptions = {} | ||
} | ||
this.options.doctypesReplicationOptions[doctype] = replicationOptions | ||
const pouchOptions = this.options?.pouch?.options ?? {} | ||
if (!pouchOptions.view_update_changes_batch_size) { | ||
pouchOptions.view_update_changes_batch_size = DEFAULT_VIEW_UPDATE_BATCH | ||
} | ||
|
||
const dbName = getDatabaseName(this.options.prefix, doctype) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @paultranvan will it works with #1633 ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, good catch.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
this.pouches[dbName] = new this.PouchDB( | ||
getDatabaseName(this.options.prefix, doctype), | ||
pouchOptions | ||
) | ||
await this.persistDatabasesNames() | ||
|
||
this.setQueryEngine(dbName, getDoctypeFromDatabaseName(dbName)) | ||
} | ||
|
||
/** | ||
* Removes a doctype from the list of managed doctypes, deletes its replication options, | ||
* destroys its PouchDB instance, and removes it from the pouches. | ||
* | ||
* @param {string} doctype - The name of the doctype to remove. | ||
*/ | ||
async removeDoctype(doctype) { | ||
this.doctypes = this.doctypes.filter(d => d !== doctype) | ||
delete this.options?.doctypesReplicationOptions?.[doctype] | ||
|
||
const dbName = getDatabaseName(this.options.prefix, doctype) | ||
this.pouches[dbName].destroy() | ||
delete this.pouches[dbName] | ||
await this.persistDatabasesNames() | ||
} | ||
|
||
/** | ||
* Persists the names of the PouchDB databases. | ||
* | ||
* This method is primarily used to ensure that database names are saved for | ||
* old browsers that do not support `indexeddb.databases()`. This persistence | ||
* facilitates cleanup processes. Note that PouchDB automatically adds the | ||
* `_pouch_` prefix to database names. | ||
* | ||
* @returns {Promise<void>} | ||
*/ | ||
async persistDatabasesNames() { | ||
const dbNames = Object.keys(this.pouches) | ||
const pouchDbNames = dbNames.map(dbName => `_pouch_${dbName}`) | ||
await this.storage.persistDatabasesNames(pouchDbNames) | ||
} | ||
} | ||
|
||
export default PouchManager |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
import fromPairs from 'lodash/fromPairs' | ||
import get from 'lodash/get' | ||
import map from 'lodash/map' | ||
import startsWith from 'lodash/startsWith' | ||
import zip from 'lodash/zip' | ||
|
@@ -33,30 +32,30 @@ export const replicateOnce = async pouchManager => { | |
pouchManager.pouches, | ||
async (pouch, dbName) => { | ||
const doctype = getDoctypeFromDatabaseName(dbName) | ||
// Use optional chaining and nullish coalescing instead of get | ||
const replicationOptions = | ||
pouchManager.doctypesReplicationOptions?.[doctype] ?? {} | ||
logger.info('PouchManager: Starting replication for ' + doctype) | ||
|
||
const getReplicationURL = () => pouchManager.getReplicationURL(doctype) | ||
const getReplicationURL = () => | ||
pouchManager.getReplicationURL(doctype, replicationOptions) | ||
|
||
const initialReplication = | ||
pouchManager.getSyncStatus(doctype) !== 'synced' | ||
const replicationFilter = doc => { | ||
return !startsWith(doc._id, '_design') | ||
} | ||
const isSharedDrive = Boolean(replicationOptions.driveId) | ||
let seq = '' | ||
if (initialReplication) { | ||
if (initialReplication && !isSharedDrive) { | ||
// Before the first replication, get the last remote sequence, | ||
// which will be used as a checkpoint for the next replication | ||
const lastSeq = await fetchRemoteLastSequence(getReplicationURL()) | ||
doubleface marked this conversation as resolved.
Show resolved
Hide resolved
|
||
await pouchManager.storage.persistDoctypeLastSequence(doctype, lastSeq) | ||
} else { | ||
seq = await pouchManager.storage.getDoctypeLastSequence(doctype) | ||
seq = (await pouchManager.storage.getDoctypeLastSequence(doctype)) || '' | ||
} | ||
|
||
const replicationOptions = get( | ||
pouchManager.doctypesReplicationOptions, | ||
doctype, | ||
{} | ||
) | ||
replicationOptions.initialReplication = initialReplication | ||
replicationOptions.filter = replicationFilter | ||
replicationOptions.since = seq | ||
|
@@ -69,11 +68,12 @@ export const replicateOnce = async pouchManager => { | |
pouch, | ||
replicationOptions, | ||
getReplicationURL, | ||
pouchManager.storage | ||
pouchManager.storage, | ||
pouchManager.client | ||
) | ||
if (seq) { | ||
// We only need the sequence for the second replication, as PouchDB | ||
// will use a local checkpoint for the next runs. | ||
if (seq && !isSharedDrive) { | ||
// For shared drives, we always need to keep the last sequence since replication is handled manually, not by PouchDB. | ||
// For standard PouchDB replications, the last sequence is only needed for the initial sync; subsequent runs use PouchDB's internal checkpointing. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But, for "standard replication", we now save the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But I did not change that. the Yes, it means that there is no point at destroying it here but what I don't know is if there is a need to avoid to use the lastSeq in localStorage. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Well, no, that's you who added the save on each completed replication 😄 ac5fb47#diff-6f9271f35894bccd13c05f69ba8e460d9cae55ed63666aa0b2038a5b4bc5a328 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes sorry. At this point, I think I just should revert There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This time, with 0468550, we have exactly the same behaviour as before for non shared drive doctypes : fetch last sequence from client only on initial replication and removing it after. |
||
await pouchManager.storage.destroyDoctypeLastSequence(doctype) | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.