1
0
Fork 0

Fix plugin upgrade

Correctly decache all plugin paths
This commit is contained in:
Chocobozzz 2021-12-03 09:52:03 +01:00
parent 8406a9e8ee
commit ca87d95bcb
No known key found for this signature in database
GPG key ID: 583A612D890159BE
6 changed files with 85 additions and 19 deletions

View file

@ -155,6 +155,7 @@ search:
federation: federation:
videos: videos:
federate_unlisted: true federate_unlisted: true
cleanup_remote_interactions: false
views: views:
videos: videos:

View file

@ -90,7 +90,6 @@
"cookie-parser": "^1.4.3", "cookie-parser": "^1.4.3",
"cors": "^2.8.1", "cors": "^2.8.1",
"create-torrent": "^5.0.0", "create-torrent": "^5.0.0",
"decache": "^4.6.0",
"deep-object-diff": "^1.1.0", "deep-object-diff": "^1.1.0",
"email-templates": "^8.0.3", "email-templates": "^8.0.3",
"execa": "^5.1.1", "execa": "^5.1.1",

78
server/helpers/decache.ts Normal file
View file

@ -0,0 +1,78 @@
// Thanks: https://github.com/dwyl/decache
// We reuse this file to also uncache plugin base path
import { extname } from 'path'
function decachePlugin (pluginPath: string, libraryPath: string) {
const moduleName = find(libraryPath)
if (!moduleName) return
searchCache(moduleName, function (mod) {
delete require.cache[mod.id]
})
removeCachedPath(pluginPath)
}
function decacheModule (name: string) {
const moduleName = find(name)
if (!moduleName) return
searchCache(moduleName, function (mod) {
delete require.cache[mod.id]
})
removeCachedPath(moduleName)
}
// ---------------------------------------------------------------------------
export {
decacheModule,
decachePlugin
}
// ---------------------------------------------------------------------------
function find (moduleName: string) {
try {
return require.resolve(moduleName)
} catch {
return ''
}
}
function searchCache (moduleName: string, callback: (current: NodeModule) => void) {
const resolvedModule = require.resolve(moduleName)
let mod: NodeModule
const visited = {}
if (resolvedModule && ((mod = require.cache[resolvedModule]) !== undefined)) {
// Recursively go over the results
(function run (current) {
visited[current.id] = true
current.children.forEach(function (child) {
if (extname(child.filename) !== '.node' && !visited[child.id]) {
run(child)
}
})
// Call the specified callback providing the
// found module
callback(current)
})(mod)
}
};
function removeCachedPath (pluginPath: string) {
const pathCache = (module.constructor as any)._pathCache
Object.keys(pathCache).forEach(function (cacheKey) {
if (cacheKey.includes(pluginPath)) {
delete pathCache[cacheKey]
}
})
}

View file

@ -1,7 +1,7 @@
import bytes from 'bytes' import bytes from 'bytes'
import { IConfig } from 'config' import { IConfig } from 'config'
import decache from 'decache'
import { dirname, join } from 'path' import { dirname, join } from 'path'
import { decacheModule } from '@server/helpers/decache'
import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type' import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type'
import { BroadcastMessageLevel } from '@shared/models/server' import { BroadcastMessageLevel } from '@shared/models/server'
import { VideosRedundancyStrategy } from '../../shared/models' import { VideosRedundancyStrategy } from '../../shared/models'
@ -497,7 +497,7 @@ export function reloadConfig () {
delete require.cache[fileName] delete require.cache[fileName]
} }
decache('config') decacheModule('config')
} }
purge() purge()

View file

@ -1,8 +1,8 @@
import decache from 'decache'
import express from 'express' import express from 'express'
import { createReadStream, createWriteStream } from 'fs' import { createReadStream, createWriteStream } from 'fs'
import { ensureDir, outputFile, readJSON } from 'fs-extra' import { ensureDir, outputFile, readJSON } from 'fs-extra'
import { basename, join } from 'path' import { basename, join } from 'path'
import { decachePlugin } from '@server/helpers/decache'
import { MOAuthTokenUser, MUser } from '@server/types/models' import { MOAuthTokenUser, MUser } from '@server/types/models'
import { getCompleteLocale } from '@shared/core-utils' import { getCompleteLocale } from '@shared/core-utils'
import { ClientScript, PluginPackageJson, PluginTranslation, PluginTranslationPaths, RegisterServerHookOptions } from '@shared/models' import { ClientScript, PluginPackageJson, PluginTranslation, PluginTranslationPaths, RegisterServerHookOptions } from '@shared/models'
@ -312,12 +312,12 @@ export class PluginManager implements ServerHook {
logger.error('Cannot install plugin %s, removing it...', toInstall, { err: rootErr }) logger.error('Cannot install plugin %s, removing it...', toInstall, { err: rootErr })
try { try {
await this.uninstall(npmName) // await this.uninstall(npmName)
} catch (err) { } catch (err) {
logger.error('Cannot uninstall plugin %s after failed installation.', toInstall, { err }) logger.error('Cannot uninstall plugin %s after failed installation.', toInstall, { err })
try { try {
await removeNpmPlugin(npmName) // await removeNpmPlugin(npmName)
} catch (err) { } catch (err) {
logger.error('Cannot remove plugin %s after failed installation.', toInstall, { err }) logger.error('Cannot remove plugin %s after failed installation.', toInstall, { err })
} }
@ -420,7 +420,7 @@ export class PluginManager implements ServerHook {
// Delete cache if needed // Delete cache if needed
const modulePath = join(pluginPath, packageJSON.library) const modulePath = join(pluginPath, packageJSON.library)
decache(modulePath) decachePlugin(pluginPath, modulePath)
const library: PluginLibrary = require(modulePath) const library: PluginLibrary = require(modulePath)
if (!isLibraryCodeValid(library)) { if (!isLibraryCodeValid(library)) {

View file

@ -2613,11 +2613,6 @@ call-me-maybe@^1.0.1:
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
callsite@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
callsites@^3.0.0: callsites@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@ -3229,13 +3224,6 @@ debuglog@^1.0.0:
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
decache@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/decache/-/decache-4.6.0.tgz#87026bc6e696759e82d57a3841c4e251a30356e8"
integrity sha512-PppOuLiz+DFeaUvFXEYZjLxAkKiMYH/do/b/MxpDe/8AgKBi5GhZxridoVIbBq72GDbL36e4p0Ce2jTGUwwU+w==
dependencies:
callsite "^1.0.0"
decamelize@^1.2.0: decamelize@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"