Skip to content
This repository has been archived by the owner on Jun 26, 2024. It is now read-only.

Commit

Permalink
fix: dataset autoreload with github api conditional request
Browse files Browse the repository at this point in the history
  • Loading branch information
vhf committed Oct 28, 2019
1 parent 465d42d commit e056ca3
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 47 deletions.
54 changes: 44 additions & 10 deletions api/github/api.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const helpersFactory = require('./helpers')
const octokitFactory = require('@octokit/rest')
const debug = require('debug')('editor:api')

module.exports = class GitHubAPIv3 {
constructor ({ forge, editor, ontology }) {
debug('new GitHubAPIv3')
this.branch = editor.github.branch
this.owner = editor.github.owner
this.repo = editor.github.repo
Expand All @@ -25,6 +27,8 @@ module.exports = class GitHubAPIv3 {
const { getRefSHA, getFileSHA } = helpersFactory(this.__octokit)
this.__getRefSHA = getRefSHA
this.__getFileSHA = getFileSHA

this.__cache = new Map()
}

async createBranch () {
Expand All @@ -49,12 +53,42 @@ module.exports = class GitHubAPIv3 {
}
}

async getHeadSHA ({ branch = this.branch } = {}) {
const owner = this.owner
const repo = this.repo
const ref = `heads/${branch}`
const response = await this.__octokit.repos.getCommitRefSha({ owner, repo, ref })
return response.data.sha
}

async getFile ({ path = this.ontologyPath, branch = this.branch } = {}) {
const owner = this.owner
const repo = this.repo
const ref = `heads/${this.branch}`
const result = await this.__octokit.repos.getContents({ owner, repo, path, ref })
const content = Buffer.from(result.data.content, 'base64').toString()
const ref = `heads/${branch}`
const query = { owner, repo, path, ref }

const cached = this.__cache.get(`${ref}/${path}`)
const headers = cached ? { 'If-Modified-Since': cached.lastModified } : {}

let content
try {
const response = await this.__octokit.repos.getContents({ ...query, headers })
content = Buffer.from(response.data.content, 'base64').toString()
const lastModified = response.headers['last-modified']
this.__cache.set(`${ref}/${path}`, { lastModified, content })
}
catch (error) {
// '304 not modified', let's serve cached version
if (error.status === 304) {
debug(`github sent 304 for file ${ref}/${path}`)
content = cached.content
}
else {
debug(`rate limit: ${error.headers['x-ratelimit-remaining']}`)
throw error
}
}

return content
}

Expand All @@ -71,7 +105,7 @@ module.exports = class GitHubAPIv3 {
repo
})

const result = await this.__octokit.repos.updateFile({
const response = await this.__octokit.repos.updateFile({
content: Buffer.from(content).toString('base64'),
path,
owner,
Expand All @@ -83,14 +117,14 @@ module.exports = class GitHubAPIv3 {
author
})

return result
return response
}

async createPR ({ title, body, branch } = {}) {
const owner = this.owner
const repo = this.repo

const result = await this.__octokit.pullRequests.create({
const response = await this.__octokit.pullRequests.create({
head: branch,
base: this.branch,
maintainer_can_modify: true,
Expand All @@ -101,24 +135,24 @@ module.exports = class GitHubAPIv3 {
})

return {
number: result.data.number
number: response.data.number
}
}

async mergePR ({ number, sha } = {}) {
const owner = this.owner
const repo = this.repo

const result = await this.__octokit.pullRequests.merge({
const response = await this.__octokit.pullRequests.merge({
owner,
repo,
number,
sha
})

return {
success: !!result.data.merged, // true | undefined => bool
message: result.data.message // shown to user if !success
success: !!response.data.merged, // true | undefined => bool
message: response.data.message // shown to user if !success
}
}

Expand Down
34 changes: 1 addition & 33 deletions api/github/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
const _ = require('lodash')
const Router = require('express').Router
const axios = require('axios')
const apicache = require('apicache')
const gql = require('graphql-tag')
const debug = require('debug')('editor:api')
const apolloClientFactory = require('../getApolloClient')
const GitHubAPIv3 = require('./api')

module.exports = async function (editorConfig) {
const router = Router()
const api = new GitHubAPIv3(editorConfig)
const onlyStatus200 = (req, res) => res.statusCode === 200
const cache = (duration) => apicache.middleware(duration, onlyStatus200)

process.on('SIGHUP', () => {
apicache.clear()
debug('GitHub API: apicache cleared')
})

const anonApolloClient = await apolloClientFactory()
const getApolloClientForUser = async (req) => apolloClientFactory({
Expand All @@ -25,29 +16,13 @@ module.exports = async function (editorConfig) {
getAuth: () => req.get('Authorization'),
ssr: true
})
const ontologyFilename = editorConfig.ontology.ontologyRawUrl.substr(editorConfig.ontology.ontologyRawUrl.lastIndexOf('/') + 1)
const structureFilename = editorConfig.ontology.structureRawUrl.substr(editorConfig.ontology.structureRawUrl.lastIndexOf('/') + 1)

router.get('/', (req, res, next) => {
res.send('Ontology Editor currently using GitHub')
})

router.get('/cache', (req, res) => {
res.json(apicache.getIndex())
})

router.get('/blob/:branch/:file', cache('5 minutes'), async (req, res, next) => {
router.get('/blob/:file', async (req, res, next) => {
const path = req.params.file
const branch = req.params.branch
const content = await api.getFile({ path, branch })
res.type('application/n-triples')

res.send(content)
})

router.get('/blob/:file', cache('5 minutes'), async (req, res, next) => {
const path = req.params.file
req.apicacheGroup = `file:${path}`
const content = await api.getFile({ path })
res.type('application/n-triples')

Expand Down Expand Up @@ -227,10 +202,6 @@ module.exports = async function (editorConfig) {
})

router.post('/proposal/merge', async (req, res, next) => {
[ontologyFilename, structureFilename].forEach((file) => {
apicache.clear(`file:${file}`)
})

const { threadId, number } = req.body

try {
Expand Down Expand Up @@ -272,9 +243,6 @@ module.exports = async function (editorConfig) {
})

router.post('/proposal/close', async (req, res, next) => {
[ontologyFilename, structureFilename].forEach((file) => {
apicache.clear(`file:${file}`)
})

const { threadId, number, status } = req.body

Expand Down
2 changes: 1 addition & 1 deletion components/admin/AdminProposalList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ export default {
catch (err) {
this.working = false
console.error(err)
this.$sentry.captureException(err)
this.$toast.error(`Error: ${err.response.data.message || err.message}`, toastClose).goAway(1600)
this.$sentry.captureException(err)
}
},
async reject (proposal, status = 'REJECTED') {
Expand Down
1 change: 1 addition & 0 deletions components/fallback/ClassProposals.vue
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default {
}
},
fetchPolicy: 'no-cache',
pollInterval: 1000 * 15,
result ({ data, loading }) {
if (!loading) {
const proposals = _get(data, 'proposals.proposals', [])
Expand Down
1 change: 1 addition & 0 deletions components/fallback/PropertyProposals.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export default {
}
},
fetchPolicy: 'no-cache',
pollInterval: 1000 * 15,
result ({ data, loading }) {
if (!loading) {
const proposals = _get(data, 'proposals.proposals', [])
Expand Down
2 changes: 1 addition & 1 deletion nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ module.exports = async () => {
* Order matters!
*/
plugins: [
'@/plugins/sentry',
'@/plugins/libs/rdf',
'@/plugins/models/Class',
'@/plugins/models/Property',
Expand Down Expand Up @@ -136,7 +137,6 @@ module.exports = async () => {
** Module config: sentry
*/
sentry: {
dsn: process.env.SENTRY_DSN,
config: {
release: version
}
Expand Down
3 changes: 3 additions & 0 deletions plugins/nuxt-init.client.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export default async (context) => {
if (process.browser) {
await context.store.dispatch('nuxtClientInit', context)
setInterval(() => {
context.store.dispatch('graph/RELOAD_DATASET')
}, 10000)
}
}
9 changes: 9 additions & 0 deletions plugins/sentry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default ({ app }, inject) => {
if (!process.SENTRY_DSN) {
inject('sentry', { captureException })
}
}

function captureException (error) {
console.error(error)
}
8 changes: 8 additions & 0 deletions store/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as VueDeepSet from 'vue-deepset'

let datasetPolling = false

export const state = () => ({
authProcessDone: false
})
Expand Down Expand Up @@ -28,6 +30,12 @@ export const actions = {
if (req && req.structure) {
commit('graph/structureInit', req.structure)
}
if (!datasetPolling && process.server) {
datasetPolling = setInterval(() => {
console.log(new Date())
dispatch('graph/RELOAD_DATASET')
}, 5000)
}
},
async nuxtClientInit ({ commit, dispatch }, context) {
commit('class/NEW')
Expand Down
4 changes: 2 additions & 2 deletions trifid/dataset-fetch-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import axios from 'axios'

const debug = require('debug')('editor:trifid')

// * used by the store to refresh client-side dataset after a merge
// only used client-side, the other one cannot be used client-side because of
// * used by the store to refresh client-side dataset after a merge.
// Only used client-side, the other one cannot be used client-side because of
// knex
export default async function fetchDataset (editorConfig) {
const ontologyFilename = editorConfig.ontology.ontologyRawUrl.substr(editorConfig.ontology.ontologyRawUrl.lastIndexOf('/') + 1)
Expand Down

0 comments on commit e056ca3

Please sign in to comment.