2021-12-14 08:00:35 -05:00
|
|
|
const logger = require('@overleaf/logger')
|
2021-07-12 12:47:19 -04:00
|
|
|
const Settings = require('@overleaf/settings')
|
2019-12-23 08:36:12 -05:00
|
|
|
const fs = require('fs')
|
|
|
|
const Path = require('path')
|
|
|
|
const { promisify } = require('util')
|
|
|
|
const disrequire = require('disrequire')
|
2020-02-23 13:25:39 -05:00
|
|
|
const AWS = require('aws-sdk')
|
2019-12-16 05:42:36 -05:00
|
|
|
|
2019-12-23 08:36:12 -05:00
|
|
|
logger.logger.level('info')
|
|
|
|
|
|
|
|
const fsReaddir = promisify(fs.readdir)
|
2020-01-02 04:53:07 -05:00
|
|
|
const sleep = promisify(setTimeout)
|
2019-12-23 08:36:12 -05:00
|
|
|
|
|
|
|
class FilestoreApp {
|
|
|
|
constructor() {
|
|
|
|
this.running = false
|
|
|
|
this.initing = false
|
|
|
|
}
|
|
|
|
|
|
|
|
async runServer() {
|
2019-12-16 05:42:41 -05:00
|
|
|
if (this.running) {
|
2019-12-23 08:36:12 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.initing) {
|
2024-05-22 05:37:08 -04:00
|
|
|
return await this.waitForInit()
|
2019-12-23 08:36:12 -05:00
|
|
|
}
|
|
|
|
this.initing = true
|
|
|
|
|
|
|
|
this.app = await FilestoreApp.requireApp()
|
|
|
|
|
|
|
|
await new Promise((resolve, reject) => {
|
|
|
|
this.server = this.app.listen(
|
|
|
|
Settings.internal.filestore.port,
|
2024-04-25 08:56:00 -04:00
|
|
|
'127.0.0.1',
|
2021-07-13 07:04:46 -04:00
|
|
|
err => {
|
2019-12-23 08:36:12 -05:00
|
|
|
if (err) {
|
|
|
|
return reject(err)
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
2019-12-23 08:36:12 -05:00
|
|
|
resolve()
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
|
|
|
)
|
2019-12-23 08:36:12 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
if (Settings.filestore.backend === 's3') {
|
|
|
|
try {
|
|
|
|
await FilestoreApp.waitForS3()
|
|
|
|
} catch (err) {
|
|
|
|
await this.stop()
|
|
|
|
throw err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.initing = false
|
2020-02-17 09:04:42 -05:00
|
|
|
this.persistor = require('../../../app/js/PersistorManager')
|
2019-12-23 08:36:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
async waitForInit() {
|
|
|
|
while (this.initing) {
|
2020-01-02 04:53:07 -05:00
|
|
|
await sleep(1000)
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
2019-12-23 08:36:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
async stop() {
|
2020-02-23 13:26:30 -05:00
|
|
|
if (!this.server) return
|
2020-01-02 04:53:07 -05:00
|
|
|
const closeServer = promisify(this.server.close).bind(this.server)
|
|
|
|
try {
|
|
|
|
await closeServer()
|
|
|
|
} finally {
|
2019-12-23 08:36:12 -05:00
|
|
|
delete this.server
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
2019-12-23 08:36:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static async waitForS3() {
|
|
|
|
let tries = 0
|
|
|
|
if (!Settings.filestore.s3.endpoint) {
|
|
|
|
return
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
2019-12-16 05:42:36 -05:00
|
|
|
|
2020-02-23 13:25:39 -05:00
|
|
|
const s3 = new AWS.S3({
|
|
|
|
accessKeyId: Settings.filestore.s3.key,
|
|
|
|
secretAccessKey: Settings.filestore.s3.secret,
|
|
|
|
endpoint: Settings.filestore.s3.endpoint,
|
|
|
|
s3ForcePathStyle: true,
|
2021-07-13 07:04:46 -04:00
|
|
|
signatureVersion: 'v4',
|
2020-02-23 13:25:39 -05:00
|
|
|
})
|
2019-12-23 08:36:12 -05:00
|
|
|
|
2020-02-23 13:25:39 -05:00
|
|
|
while (true) {
|
2019-12-23 08:36:12 -05:00
|
|
|
try {
|
2020-02-23 13:25:39 -05:00
|
|
|
return await s3
|
|
|
|
.putObject({
|
|
|
|
Key: 'startup',
|
|
|
|
Body: '42',
|
2021-07-13 07:04:46 -04:00
|
|
|
Bucket: Settings.filestore.stores.user_files,
|
2020-02-23 13:25:39 -05:00
|
|
|
})
|
|
|
|
.promise()
|
2019-12-23 08:36:12 -05:00
|
|
|
} catch (err) {
|
2020-01-02 04:53:07 -05:00
|
|
|
// swallow errors, as we may experience them until fake-s3 is running
|
2020-02-23 13:25:39 -05:00
|
|
|
if (tries === 9) {
|
|
|
|
// throw just before hitting the 10s test timeout
|
|
|
|
throw err
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
2020-02-23 13:25:39 -05:00
|
|
|
tries++
|
|
|
|
await sleep(1000)
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
2019-12-23 08:36:12 -05:00
|
|
|
}
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
2019-12-16 05:42:36 -05:00
|
|
|
|
2019-12-23 08:36:12 -05:00
|
|
|
static async requireApp() {
|
|
|
|
// unload the app, as we may be doing this on multiple runs with
|
|
|
|
// different settings, which affect startup in some cases
|
|
|
|
const files = await fsReaddir(Path.resolve(__dirname, '../../../app/js'))
|
2021-07-13 07:04:46 -04:00
|
|
|
files.forEach(file => {
|
2019-12-23 08:36:12 -05:00
|
|
|
disrequire(Path.resolve(__dirname, '../../../app/js', file))
|
|
|
|
})
|
|
|
|
disrequire(Path.resolve(__dirname, '../../../app'))
|
2020-07-07 08:49:54 -04:00
|
|
|
disrequire('@overleaf/object-persistor')
|
2019-12-23 08:36:12 -05:00
|
|
|
|
|
|
|
return require('../../../app')
|
|
|
|
}
|
2019-12-16 05:42:41 -05:00
|
|
|
}
|
2019-12-23 08:36:12 -05:00
|
|
|
|
|
|
|
module.exports = FilestoreApp
|