mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-23 00:37:47 +00:00
safari files support (#2278)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
5642e6823e
commit
6e4474494d
@ -22,7 +22,7 @@ import { decodeToken, Token } from '@hcengineering/server-token'
|
|||||||
import bp from 'body-parser'
|
import bp from 'body-parser'
|
||||||
import compression from 'compression'
|
import compression from 'compression'
|
||||||
import cors from 'cors'
|
import cors from 'cors'
|
||||||
import express from 'express'
|
import express, { Response } from 'express'
|
||||||
import fileUpload, { UploadedFile } from 'express-fileupload'
|
import fileUpload, { UploadedFile } from 'express-fileupload'
|
||||||
import https from 'https'
|
import https from 'https'
|
||||||
import { BucketItem, Client, ItemBucketMetadata } from 'minio'
|
import { BucketItem, Client, ItemBucketMetadata } from 'minio'
|
||||||
@ -62,6 +62,94 @@ async function readMinioData (client: Client, db: string, name: string): Promise
|
|||||||
return chunks
|
return chunks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRange (range: string, size: number): [number, number] {
|
||||||
|
const [startStr, endStr] = range.replace(/bytes=/, '').split('-')
|
||||||
|
|
||||||
|
let start = parseInt(startStr, 10)
|
||||||
|
let end = endStr !== undefined ? parseInt(endStr, 10) : size - 1
|
||||||
|
|
||||||
|
if (!isNaN(start) && isNaN(end)) {
|
||||||
|
end = size - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(start) && !isNaN(end)) {
|
||||||
|
start = size - end
|
||||||
|
end = size - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return [start, end]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFileRange (
|
||||||
|
range: string,
|
||||||
|
client: Client,
|
||||||
|
workspace: string,
|
||||||
|
uuid: string,
|
||||||
|
res: Response
|
||||||
|
): Promise<void> {
|
||||||
|
const stat = await client.statObject(workspace, uuid)
|
||||||
|
|
||||||
|
const size = stat.size
|
||||||
|
|
||||||
|
const [start, end] = getRange(range, size)
|
||||||
|
|
||||||
|
if (start >= size || end >= size) {
|
||||||
|
res.writeHead(416, {
|
||||||
|
'Content-Range': `bytes */${size}`
|
||||||
|
})
|
||||||
|
res.end()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client.getPartialObject(workspace, uuid, start, end - start + 1, (err, dataStream) => {
|
||||||
|
if (err !== null) {
|
||||||
|
console.log(err)
|
||||||
|
res.status(500).send()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.writeHead(206, {
|
||||||
|
Connection: 'keep-alive',
|
||||||
|
'Content-Range': `bytes ${start}-${end}/${size}`,
|
||||||
|
'Accept-Ranges': 'bytes',
|
||||||
|
'Content-Length': end - start + 1,
|
||||||
|
'Content-Type': stat.metaData['content-type']
|
||||||
|
})
|
||||||
|
|
||||||
|
dataStream.pipe(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFile (client: Client, workspace: string, uuid: string, res: Response): Promise<void> {
|
||||||
|
const stat = await client.statObject(workspace, uuid)
|
||||||
|
|
||||||
|
client.getObject(workspace, uuid, (err, dataStream) => {
|
||||||
|
if (err !== null) {
|
||||||
|
console.log(err)
|
||||||
|
res.status(500).send()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.status(200)
|
||||||
|
res.set('Cache-Control', 'max-age=604800')
|
||||||
|
|
||||||
|
const contentType = stat.metaData['content-type']
|
||||||
|
if (contentType !== undefined) {
|
||||||
|
res.setHeader('Content-Type', contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStream.on('data', function (chunk) {
|
||||||
|
res.write(chunk)
|
||||||
|
})
|
||||||
|
dataStream.on('end', function () {
|
||||||
|
res.end()
|
||||||
|
})
|
||||||
|
dataStream.on('error', function (err) {
|
||||||
|
console.log(err)
|
||||||
|
res.status(500).send()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
* @param port -
|
* @param port -
|
||||||
@ -113,7 +201,33 @@ export function start (
|
|||||||
app.use(express.static(dist, { maxAge: '168h' }))
|
app.use(express.static(dist, { maxAge: '168h' }))
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
app.get('/files', async (req, res) => {
|
app.head('/files', async (req, res: Response) => {
|
||||||
|
try {
|
||||||
|
const token = req.query.token as string
|
||||||
|
const payload = decodeToken(token)
|
||||||
|
let uuid = req.query.file as string
|
||||||
|
const size = req.query.size as 'inline' | 'tiny' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large' | 'full'
|
||||||
|
|
||||||
|
uuid = await getResizeID(size, uuid, config, payload)
|
||||||
|
const stat = await config.minio.statObject(payload.workspace, uuid)
|
||||||
|
|
||||||
|
const fileSize = stat.size
|
||||||
|
|
||||||
|
res.status(200)
|
||||||
|
|
||||||
|
res.setHeader('accept-ranges', 'bytes')
|
||||||
|
|
||||||
|
res.setHeader('content-length', fileSize)
|
||||||
|
|
||||||
|
res.end()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
res.status(500).send()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
|
app.get('/files', async (req, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const token = req.query.token as string
|
const token = req.query.token as string
|
||||||
const payload = decodeToken(token)
|
const payload = decodeToken(token)
|
||||||
@ -122,30 +236,12 @@ export function start (
|
|||||||
|
|
||||||
uuid = await getResizeID(size, uuid, config, payload)
|
uuid = await getResizeID(size, uuid, config, payload)
|
||||||
|
|
||||||
const stat = await config.minio.statObject(payload.workspace, uuid)
|
const range = req.headers.range
|
||||||
|
if (range !== undefined) {
|
||||||
config.minio.getObject(payload.workspace, uuid, function (err, dataStream) {
|
await getFileRange(range, config.minio, payload.workspace, uuid, res)
|
||||||
if (err !== null) {
|
} else {
|
||||||
return console.log(err)
|
await getFile(config.minio, payload.workspace, uuid, res)
|
||||||
}
|
}
|
||||||
res.status(200)
|
|
||||||
res.set('Cache-Control', 'max-age=604800')
|
|
||||||
|
|
||||||
const contentType = stat.metaData['content-type']
|
|
||||||
if (contentType !== undefined) {
|
|
||||||
res.setHeader('Content-Type', contentType)
|
|
||||||
}
|
|
||||||
|
|
||||||
dataStream.on('data', function (chunk) {
|
|
||||||
res.write(chunk)
|
|
||||||
})
|
|
||||||
dataStream.on('end', function () {
|
|
||||||
res.end()
|
|
||||||
})
|
|
||||||
dataStream.on('error', function (err) {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
res.status(500).send()
|
res.status(500).send()
|
||||||
@ -170,26 +266,12 @@ export function start (
|
|||||||
try {
|
try {
|
||||||
const token = authHeader.split(' ')[1]
|
const token = authHeader.split(' ')[1]
|
||||||
const payload = decodeToken(token)
|
const payload = decodeToken(token)
|
||||||
// const fileId = await awsUpload(file as UploadedFile)
|
|
||||||
const uuid = await minioUpload(config.minio, payload.workspace, file)
|
const uuid = await minioUpload(config.minio, payload.workspace, file)
|
||||||
console.log('uploaded uuid', uuid)
|
console.log('uploaded uuid', uuid)
|
||||||
|
|
||||||
const space = req.query.space as Ref<Space> | undefined
|
const space = req.query.space as Ref<Space> | undefined
|
||||||
const attachedTo = req.query.attachedTo as Ref<Doc> | undefined
|
const attachedTo = req.query.attachedTo as Ref<Doc> | undefined
|
||||||
|
|
||||||
// const name = req.query.name as string
|
|
||||||
|
|
||||||
// await createAttachment(
|
|
||||||
// transactorEndpoint,
|
|
||||||
// token,
|
|
||||||
// 'core:account:System' as Ref<Account>,
|
|
||||||
// space,
|
|
||||||
// attachedTo,
|
|
||||||
// collection,
|
|
||||||
// name,
|
|
||||||
// fileId
|
|
||||||
// )
|
|
||||||
|
|
||||||
if (space !== undefined && attachedTo !== undefined) {
|
if (space !== undefined && attachedTo !== undefined) {
|
||||||
const elastic = await createElasticAdapter(config.elasticUrl, payload.workspace)
|
const elastic = await createElasticAdapter(config.elasticUrl, payload.workspace)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user