Micro service for uploading and image resizing files to a storage server.
Find a file
Jonatan Nilsson 68eef3a6b6 Complete refactor, features and optimization of code
Removed large amount of dependencies.
Added vips support and automatically resizing based on any criteria.
Faster and leaner.
Added ability to fetch listing of files in folders.
2022-01-05 14:47:51 +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/development Complete refactor, features and optimization of code 2022-01-05 14:47:51 +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
package.json Complete refactor, features and optimization of code 2022-01-05 14:47:51 +00:00
README.md Update README.md 2017-12-10 12:35:10 +00:00
test.json Finished unit test, refactored to use flaska instead of koa 2021-10-11 00:21:57 +00:00

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)
//   })