Micro service for uploading and image resizing files to a storage server.
 
Go to file
Jonatan Nilsson 92338b94ca Add missing test images 2022-01-05 14:51:32 +00:00
.circleci Fix logging, fix a few bugs, add docker file, move files a bit and add auto build and publish to docker 2021-10-11 03:39:01 +00:00
api Complete refactor, features and optimization of code 2022-01-05 14:47:51 +00:00
config Complete refactor, features and optimization of code 2022-01-05 14:47:51 +00:00
public Add missing test images 2022-01-05 14:51:32 +00:00
test Complete refactor, features and optimization of code 2022-01-05 14:47:51 +00:00
.gitignore Fix logging, fix a few bugs, add docker file, move files a bit and add auto build and publish to docker 2021-10-11 03:39:01 +00:00
.npmrc circleci: Fix running test, permanently stop package-lock 2021-10-11 01:24:51 +00:00
Dockerfile Fix logging, fix a few bugs, add docker file, move files a bit and add auto build and publish to docker 2021-10-11 03:39:01 +00:00
README.md Update README.md 2017-12-10 12:35:10 +00:00
package.json Complete refactor, features and optimization of code 2022-01-05 14:47:51 +00:00
test.json Finished unit test, refactored to use flaska instead of koa 2021-10-11 00:21:57 +00:00

README.md

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' }
  • Error Response:

    • Code: 422 UNPROCESSABLE ENTRY
      Content: { status:422, message: "error message here" }
  • 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)
//   })