.circleci | ||
api | ||
config | ||
public | ||
test | ||
.gitignore | ||
.npmrc | ||
Dockerfile | ||
package.json | ||
README.md | ||
test.json |
storage-upload
Docker micro service for uploading files to a storage server.
Usage
storage-upload listens on port 4020 by default. Since the storage upload needs a place to store the uploaded files, it's important to map the /app/public
folder to either locally or some volume.
In addition it's recommended to also map the config file /app/config/config.production.json
which should include a list of accepted sites and the corresponding json web token secret.
docker run -d \
--name storage-upload \
-v /path/to/store/files:/app/public \
-v /path/to/config/file.json:/app/config/config.production.json \
-p 4000:4020
nfpis/storage-upload
Config
The mapped config file should look something like this:
config.production.json
{
"sites": {
"site1": "site1-secret",
"site2": "site2-secret"
}
}
The server checks the token in the query for supported site name and then verifies the secret match. To generate a token valid to upload to site2
above, you can run something like this:
const jwt = require('jsonwebtoken')
let token = jwt.sign({ site: 'site2' }, 'site2-secret')
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaXRlIjoic2l0ZTIifQ.Ovz7fnTMzaWOLOhnbkMtqHPk20EVqhCD8WDsLKk_Wv0
Hint: Post the above token to https://jwt.io/ and check it out.
Using the above token would save the requested file under /app/public/site2/
folder
API
Media
Uploading or removing uploaded files on the storage server.
-
URL
/media
-
Method:
POST
-
URL Params
token=[site-token-here]
-
Data Params
file=@my-file-to-upload.jpg
-
Success Response:
- Code: 200
Content:{ filename: '20171210_115632_my-file-to-upload.jpg', path: '/development/20171210_115632_my-file-to-upload.jpg' }
- Code: 200
-
Error Response:
- Code: 422 UNPROCESSABLE ENTRY
Content:{ status:422, message: "error message here" }
- Code: 422 UNPROCESSABLE ENTRY
-
Sample Call:
curl -X POST -F "file=@test.png" http://localhost:4000/media\?token\=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaXRlIjoidGVzdCJ9.2LAuYwb1bwiMPUWD3gNJKwt9PwLgctleLhYd6sc0FCU
Example node.js helper
upload.js
const http = require('http')
const path = require('path')
const fs = require('fs')
function upload(token, file) {
return new Promise((resolve, reject) => {
fs.readFile(file, (err, data) => {
if (err) return reject(err)
const crlf = '\r\n'
const filename = path.basename(file)
const boundary = `--${Math.random().toString(16)}`
const headers = [
`Content-Disposition: form-data; name="file"; filename="${filename}"` + crlf
]
const multipartBody = Buffer.concat([
new Buffer(
`${crlf}--${boundary}${crlf}` +
headers.join('') + crlf
),
data,
new Buffer(
`${crlf}--${boundary}--`
)
])
const options = {
port: 2111,
hostname: 'storage01.nfp.is',
method: 'POST',
path: '/media?token=' + token,
headers: {
'Content-Type': 'multipart/form-data; boundary=' + boundary,
'Content-Length': multipartBody.length
},
}
const req = http.request(options)
req.write(multipartBody)
req.end()
req.on('error', reject)
req.on('response', res => {
res.setEncoding('utf8')
let output = ''
res.on('data', function (chunk) {
output += chunk.toString()
})
res.on('end', function () {
try {
output = JSON.parse(output)
} catch (e) {
// Do nothing
}
resolve(output)
})
})
})
})
}
// upload('insert-site-token-here', 'test.png')
// .then(res => {
// console.log('GOT RESULT', res)
// }, err => {
// console.log('ERROR', err)
// })