diff --git a/docker-compose.yml b/docker-compose.yml index 170764d..bc21142 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,18 +13,18 @@ services: - ${PORT}:${PORT} command: "node server.js" - task_runner_gantry: - build: - context: . - dockerfile: Dockerfile - env_file: ./.env - volumes: - - ./src/build:/ffs/ - - /ffs/node_modules - - ${LOCAL_DIR_GANTRY}:/ffs/FileShare/Gantry - network_mode: host - command: "node taskRunner.js gantry" - + # task_runner_gantry: + # build: + # context: . + # dockerfile: Dockerfile + # env_file: ./.env + # volumes: + # - ./src/build:/ffs/ + # - /ffs/node_modules + # - ${LOCAL_DIR_GANTRY}:/ffs/FileShare/Gantry + # network_mode: host + # command: "node taskRunner.js gantry" + # # task_runner_lathe: # build: # context: . diff --git a/src/config.ts b/src/config.ts index 51e3beb..34ace86 100644 --- a/src/config.ts +++ b/src/config.ts @@ -48,4 +48,5 @@ export const folderMap: any = { export const port = process.env.PORT; export const forgeClientId = process.env.FORGE_CLIENT_ID; export const forgeClientSecret = process.env.FORGE_CLIENT_SECRET; -export const forgeCallbackURL = process.env.FORGE_CALLBACK_URL; \ No newline at end of file +export const forgeCallbackURL = process.env.FORGE_CALLBACK_URL; +export const hookCallbackURL = `${process.env.HOOK_CALLBACK_HOSTNAME}/hook`; \ No newline at end of file diff --git a/src/downloader.ts b/src/downloader.ts index 144a167..18ac19a 100644 --- a/src/downloader.ts +++ b/src/downloader.ts @@ -14,7 +14,8 @@ const ObjectsApi = new ForgeSDK.ObjectsApi(); * @param {string} destination * @param {Object} credentials */ -exports.download = (storageLocation: string, fileName: string, destination: string, credentials: any) => { +exports.download = async (projectID: string, itemID: string, fileName: string, destination: string, credentials: any) => { + const storageLocation = await getStorageLocation(projectID, itemID, credentials); ObjectsApi.getObject('wip.dm.prod', storageLocation, {}, config.authClient, credentials) .then((res: any) => { @@ -27,3 +28,21 @@ exports.download = (storageLocation: string, fileName: string, destination: stri }); } +const getStorageLocation = (projectID: string, itemID: string, credentials: any) => { + axios({ + method: 'GET', + url: `https://developer.api.autodesk.com/data/v1/projects/${projectID}/items/${itemID}`, + headers: { + Authorization: `Bearer ${credentials.access_token}` + }, + }).then((res: any) => { + return res.data.included; + }).then((data: any) => { + var storageID = data.relationships.storage.data.id; + storageID = storageID.substring(storageID.indexOf('/') + 1); + return storageID; + }).catch((err: any) => { + console.log(err) + }) +} + diff --git a/src/server.ts b/src/server.ts index 81ba333..6401c0d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,6 +1,7 @@ import express = require('express'); +const webhooks = require('./webhooks'); import * as config from './config'; -const fs = require('fs'); +import fs = require('fs'); /** @@ -64,6 +65,9 @@ const createServer = () => { ); }) .then(() => { + // run the setup function for webhooks + webhooks.setup(credentials); + // sets refresh() function to run on an interval every 55 minutes intervalID = setInterval(() => refresh(), refreshTime * 1000); // 55 seconds to ms @@ -101,14 +105,6 @@ const createServer = () => { }); app.post('/hook', function (req: any, res: any) { - // console.log(req.data); - // console.log(req.payload); - // console.log(req.res); - // fs.writeFile(__dirname + '/FileShare/res.json', req, (err: any) => { - // if (err) { - // throw err; - // } - // }) let body: any = []; req.on('error', (err: any) => { console.error(err); @@ -144,6 +140,9 @@ const refresh = () => { '\x1b[0mnew token generated from refresh token:' ); console.log(credentials); + + // check on webhooks + webhooks.setup(credentials); }) .catch(err => { console.log(err); diff --git a/src/taskRunner.ts b/src/taskRunner.ts index a67b554..8686fd7 100644 --- a/src/taskRunner.ts +++ b/src/taskRunner.ts @@ -1,6 +1,6 @@ const axios = require('axios'); const watcher = require('./watcher'); -const watcher2 = require('./watcher2') +// const watcher2 = require('./watcher2') const downloader = require('./downloader'); const fs = require('fs'); import * as config from './config'; @@ -69,7 +69,8 @@ const fetchToken = () => { '\x1b[92mtaskRunner.js::fetchToken:', '\x1b[0mCredentials received' ); - watcher2.createHook(credentials); + // watcher2.createHook(credentials); + // watcher2.setup(credentials); } else { console.log( '\x1b[96mtaskRunner.js::fetchToken:', diff --git a/src/watcher2.ts b/src/watcher2.ts deleted file mode 100644 index 1af27f4..0000000 --- a/src/watcher2.ts +++ /dev/null @@ -1,25 +0,0 @@ - - -exports.createHook = (credentials: any) => { - const axios = require('axios'); - - axios({ - method: 'POST', - url: 'https://developer.api.autodesk.com/webhooks/v1/systems/data/events/dm.version.added/hooks', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${credentials.access_token}` - }, - data: { - callbackUrl: "http://6ae7-128-210-106-76.ngrok.io/hook", - autoReactivateHook: false, - scope: { - folder: "urn:adsk.wipprod:fs.folder:co.IxiedfeBTOGg6NSIGQhXxQ" // Gantry folder - } - } - }).then((res: any) => { - console.log(res); - }).catch((err: any) => { - console.log(err); - }); -} \ No newline at end of file diff --git a/src/webhooks.ts b/src/webhooks.ts new file mode 100644 index 0000000..cea9053 --- /dev/null +++ b/src/webhooks.ts @@ -0,0 +1,109 @@ +const axios = require('axios'); +import * as config from './config'; + + +// instead of using this file to constanly poll the api, it will setup and maintain the webhooks + +const FileShareID = "urn:adsk.wipprod:fs.folder:co.T0n0mYQeS16K0lq1VuuYVQ" + +/** + * Function to manage hook lifecycle + */ +exports.setup = (credentials: any) => { + axios({ + method: 'GET', + url: 'https://developer.api.autodesk.com/webhooks/v1/hooks', + headers: { + Authorization: `Bearer ${credentials.access_token}` + } + }).then((res: any) => { + return res.data.data; + }).then((data: any) => { + var hookEvents = []; + for (var index in data) { + + const hook = data[index]; + + if (hook.callbackUrl != config.hookCallbackURL) { // hooks with invalid callbacks will be deleted, not added to current list of hooks + deleteHook(hook.event, hook.hookId, credentials); + } else { + hookEvents.push(hook.event); + if (hook.status === 'inactive') { + console.log("reactivating " + hook.event + " hook"); + reactivateHook(hook.event, hook.hookId, credentials); + } + } + } + + // these are the events we want, if not in the list, then register the hook + if (!hookEvents.includes('dm.version.added')) { + createHook('dm.version.added', credentials); + } + + if (!hookEvents.includes('dm.version.modified')) { + createHook('dm.version.modified', credentials); + } + + if (!hookEvents.includes('dm.version.deleted')) { + createHook('dm.version.deleted', credentials); + } + }).catch((err: any) => { + console.log(err); + }) +} + + +const createHook = (event: string, credentials: any) => { + axios({ + method: 'POST', + url: `https://developer.api.autodesk.com/webhooks/v1/systems/data/events/${event}/hooks`, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${credentials.access_token}` + }, + data: { + autoReactivateHook: true, + callbackUrl: config.hookCallbackURL, + scope: { + folder: FileShareID + } + } + }).then((res: any) => { + console.log("sucessfully created hook for " + event); + }).catch((err: any) => { + console.log("error creating hook for " + event + ": " + err.response.status); + }); +} + +const reactivateHook = (event: string, hookID: string, credentials: any) => { + axios({ + method: 'PATCH', + url: `https://developer.api.autodesk.com/webhooks/v1/systems/data/events/${event}/hooks/${hookID}`, + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${credentials.access_token}` + }, + data: { + status: 'active', + autoReactivateHook: true, + } + }).then((res: any) => { + console.log("successfully reactivated " + event + " hook"); + }).catch((err: any) => { + console.log("error reactivating hook for " + event + ": " + err.response.status); + }); +} + +const deleteHook = (event:string, hookID: string, credentials: any) => { + axios({ + method: 'DELETE', + url: `https://developer.api.autodesk.com/webhooks/v1/systems/data/events/${event}/hooks/${hookID}`, + headers: { + Authorization: `Bearer ${credentials.access_token}` + } + }).then((res: any) => { + console.log("deleted " + event + " hook with bad callback url"); + }).catch((err: any) => { + console.log("error deleting hook for " + event + ": " + err.response.status); + }); +} \ No newline at end of file