~romuloalves/get-instagram-feed

af571708199d7557299cd42f4637840ce1c59905 — Rômulo Alves 4 years ago 34cf02e + eb5415c
Merge pull request #3 from romuloalves/development-cache

Development cache
5 files changed, 137 insertions(+), 7 deletions(-)

M README.md
M package.json
A src/cache.js
M src/index.js
A src/verify-path-exists.js
M README.md => README.md +13 -0
@@ 22,6 22,19 @@ Access the service with the user in the end of the url:

Example: [http://localhost:3000/romuloaalves](http://localhost:3000/romuloaalves)

#### Cache
This service has a cache that is _DISABLED_ by default. To enable it, follow the steps below:

Set the environment variable `USE_CACHE` to `true`.

You can use more environment variables to cache requests, they are below:

- `CACHE_DIR`: (String, Default: `/tmp`) Directory where cache files will be included;
- `CACHE_LIFETIME`: (Number, Minutes, Default: `60`) How much time the cache is valid.


If the cache is active, you can use the parameter `?cache=false` in the url to ignore cache verification.

## License

MIT License

M package.json => package.json +1 -2
@@ 1,9 1,8 @@
{
  "name": "get-instagram-picture",
  "version": "0.1.1",
  "main": "src/index.js",
  "scripts": {
    "start": "micro"
    "start": "node ./src/index.js"
  },
  "dependencies": {
    "micro": "latest",

A src/cache.js => src/cache.js +52 -0
@@ 0,0 1,52 @@
// Native
const {join} = require('path')
const {stat, readFileSync, writeFile} = require('fs')

const cacheDir = process.env.CACHE_DIR || '/tmp'
const cacheLifetime = process.env.CACHE_LIFETIME || 60

const cacheTime = cacheLifetime * 60000

const getUserCachePath = user => join(cacheDir, `${user}.json`)

module.exports = {
  getDir: () => cacheDir,
  isCacheActive: () => process.env.USE_CACHE || false,
  get: async user => {
    return new Promise((resolve, reject) => {
      const userCacheDir = getUserCachePath(user)

      stat(userCacheDir, (errorStat, stats) => {
        if (errorStat) {
          console.log(`> User ${user}: Cache not found.`)
          resolve(null)
        } else {
          const fileContent = readFileSync(userCacheDir, 'utf-8')
          const jsonData = JSON.parse(fileContent)
          const timeDiff = new Date().getTime() - jsonData.time
          if (timeDiff > cacheTime) {
            console.log(`> User: ${user}: Cache expirated.`)
            resolve(null)
          } else {
            console.log(`> User ${user}: Response from cache.`)
            resolve(jsonData.data)
          }
        }
      })
    })
  },
  set: async (user, data) => {
    const userCacheDir = getUserCachePath(user)
    const jsonData = {
      time: new Date().getTime(),
      data
    }
    writeFile(userCacheDir, JSON.stringify(jsonData), 'utf8', err => {
      if (err) {
        console.error(err)
      } else {
        console.log(`> User ${user}: Cache writed.`)
      }
    })
  }
}

M src/index.js => src/index.js +58 -5
@@ 1,16 1,69 @@
// Native
const {parse} = require('url')

// Packages
const {send} = require('micro')
const micro = require('micro')
const get = require('micro-get')

// Get the port to execute the API
const port = process.env.PORT || 3000


const {send} = micro

const getPicture = require('./get-picture')
const verifyPath = require('./verify-path-exists')
const cache = require('./cache')

// Cache configuration
const useCache = cache.isCacheActive()

module.exports = get(async function (req, res) {
  const user = req.url.replace('/', '')
// Server function
const server = micro(get(async function (req, res) {
  // Verify user
  const {pathname, query} = parse(req.url, true)

  const user = pathname.replace('/', '')
  if (user.length === 0) {
    return send(res, 404, 'User is required.')
  }
  res.setHeader('Content-Type', 'application/json; charset=utf-8')

  let useCacheInRequest = useCache

  if (useCacheInRequest && query.cache === 'false') {
    useCacheInRequest = false
  }

  if (useCacheInRequest) {
    const cacheData = await cache.get(user)
    if (cacheData !== null) {
      return send(res, 200, cacheData)
    }
  }

  // Get pictures
  const data = await getPicture(user)
  res.setHeader('Content-Type', 'application/json; charset=utf-8')
  if (useCacheInRequest) {
    await cache.set(user, data)
  }
  send(res, 200, data)
})
}))

const startServer = () => {
  server.listen(port, () => {
    console.log(`> Server started on port ${port}.`)
  })
}

// Verify if cache is active
if (useCache) {
  // Verify if cache dir exists
  const cacheDir = cache.getDir()
  verifyPath(cacheDir)
    .then(() => startServer())
    .catch(err => console.error(err))
} else {
  startServer()
}


A src/verify-path-exists.js => src/verify-path-exists.js +13 -0
@@ 0,0 1,13 @@
// Native
const {stat} = require('fs')

module.exports = async path => {
  return new Promise((resolve, reject) => {
    stat(path, (err, stats) => {
      if (err) {
        return reject(err)
      }
      resolve()
    })
  })
}