i am trying to isolate an array of dbid in the viewer that contains multi models. but the problem sometimes isolate model A and sometimes model B is there any way to isolate both models at the same time?
function getExternalIds(model: any): any {
return new Promise(function(resolve, reject) {
model.getExternalIdMapping(resolve, reject);
});
}
//---------------------------------------------
async function isolateAndColorObject(
viewer: any,
externalId ? : string[],
color ? : any
) {
const externalIds = await getExternalIds(viewer.model);
let arr: any = [];
externalId ? .forEach((id) => {
const dbid = externalIds[id];
arr.push(dbid);
});
for (const model of viewer.getAllModels()) { //viewer.getVisibleModels()
viewer.isolate(arr, model);
}
}
//calling the function:
isolateAndColorObject(viewer, [
"5aa7c220-434e-47ec-966b-7aa35a5327a9-001c988b",
"5cd83cb7-08c9-4bb2-bf3a-523af6622a4f-000e9567",
"4845d7d6-c3ba-433c-9418-acbdb1ff7e5f-0011d9e2",
"7e6d9dcb-b26f-4e71-9eb2-3169d28411da-001e3370",
]);
update: I have fixed
function getExternalIds(
model: Autodesk.Viewing.Model
): Promise<{ [key: string]: number }> {
return new Promise(function (resolve, reject) {
model.getExternalIdMapping(resolve, reject);
});
}
async function isolateAndColorObject(
viewer: Autodesk.Viewing.GuiViewer3D,
externalIds: string[]
) {
let neededDbId: number[] = [];
const allModels = viewer.getAllModels();
if (allModels) {
for await (const model of allModels) {
const iExIds = await getExternalIds(model);
if (iExIds) {
externalIds.forEach((id: string) => {
const dbid = iExIds[id];
neededDbId.push(dbid);
});
}
viewer.isolate(neededDbId, model);
}
}
}
Related
Use this function to flatten the response returned from strapi on version 4. Helps you get rid of data and attributes properties
This will give you the same response structure as version 3 of strapi. This would help you migrate to version 4 from version 3 easily.
How to use it?
import the file.
const flattnedData = flattenObj({...data})
NOTE: The data here is the response returned from strapi version 4.
export const flattenObj = (data) => {
const isObject = (data) =>
Object.prototype.toString.call(data) === "[object Object]";
const isArray = (data) =>
Object.prototype.toString.call(data) === "[object Array]";
const flatten = (data) => {
if (!data.attributes) return data;
return {
id: data.id,
...data.attributes,
};
};
if (isArray(data)) {
return data.map((item) => flattenObj(item));
}
if (isObject(data)) {
if (isArray(data.data)) {
data = [...data.data];
} else if (isObject(data.data)) {
data = flatten({ ...data.data });
} else if (data.data === null) {
data = null;
} else {
data = flatten(data);
}
for (const key in data) {
data[key] = flattenObj(data[key]);
}
return data;
}
return data;
};
In my case I created a new middleware "flatten-response.js" in "middlewares" folder.
function flattenArray(obj) {
return obj.map(e => flatten(e));
}
function flattenData(obj) {
return flatten(obj.data);
}
function flattenAttrs(obj) {
let attrs = {};
for (var key in obj.attributes) {
attrs[key] = flatten(obj.attributes[key]);
}
return {
id: obj.id,
...attrs
};
}
function flatten(obj) {
if(Array.isArray(obj)) {
return flattenArray(obj);
}
if(obj && obj.data) {
return flattenData(obj);
}
if(obj && obj.attributes) {
return flattenAttrs(obj);
}
for (var k in obj) {
if(typeof obj[k] == "object") {
obj[k] = flatten(obj[k]);
}
}
return obj;
}
async function respond(ctx, next) {
await next();
if (!ctx.url.startsWith('/api')) {
return;
}
ctx.response.body = flatten(ctx.response.body.data)
}
module.exports = () => respond;
And I called it in "config/middlewares.js"
module.exports = [
/* ... Strapi middlewares */
'global::flatten-response' // <- your middleware,
'strapi::favicon',
'strapi::public',
];
We are using forge viewer in our web application. We need to zoom camera inside room and show interior of the room.
Please help me to find out that how we can view room interior in forge viewer.
This is a duplicate question on SO, here is an already answered link: https://stackoverflow.com/a/65827867/5747150
You may check out this sample. It’s a revision of my sample forge-viewer-traveling-path. It will move the viewer camera smoothly to the center point of the room’s bounding box.
Demo: https://youtu.be/3MzihDJpi70
Here is the main extension: https://github.com/yiskang/forge-viewer-traveling-path/blob/room-navigation/public/js/MoveToRoomExt.js
/////////////////////////////////////////////////////////////////////
// Copyright (c) Autodesk, Inc. All rights reserved
// Written by Forge Partner Development
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
/////////////////////////////////////////////////////////////////////
(function () {
class RoomListPanel extends Autodesk.Viewing.UI.DockingPanel {
constructor(parent) {
const options = {};
// Height adjustment for scroll container, offset to height of the title bar and footer by default.
if (!options.heightAdjustment)
options.heightAdjustment = 70;
if (!options.marginTop)
options.marginTop = 0;
//options.addFooter = false;
const viewer = parent.viewer;
super(viewer.container, viewer.container.id + 'RoomListPanel', 'Rooms', options);
this.container.classList.add('adn-docking-panel');
this.container.classList.add('adn-room-list-panel');
this.createScrollContainer(options);
this.viewer = viewer;
this.parent = parent;
this.options = options;
this.uiCreated = false;
this.addVisibilityListener(async (show) => {
if (!show) return;
if (!this.uiCreated)
await this.createUI();
});
}
async createUI() {
this.uiCreated = true;
const div = document.createElement('div');
const treeDiv = document.createElement('div');
div.appendChild(treeDiv);
this.treeContainer = treeDiv;
this.scrollContainer.appendChild(div);
const data = await this.getRoomData();
this.buildTree(data);
}
async getRoomData() {
const getRoomDbIds = () => {
return new Promise((resolve, reject) => {
this.viewer.search(
'Revit Rooms',
(dbIds) => resolve(dbIds),
(error) => reject(error),
['Category'],
{ searchHidden: true }
);
});
};
const getPropertiesAsync = (dbId) => {
return new Promise((resolve, reject) => {
this.viewer.getProperties(
dbId,
(result) => resolve(result),
(error) => reject(error),
);
});
}
const data = [];
try {
const roomDbIds = await getRoomDbIds();
if (!roomDbIds || roomDbIds.length <= 0) {
throw new Error('No Rooms found in current model');
}
for (let i = 0; i < roomDbIds.length; i++) {
const dbId = roomDbIds[i];
const propData = await getPropertiesAsync(dbId);
data.push({
id: propData.externalId,
dbId,
name: propData.name
});
}
} catch (ex) {
console.warn(`[RoomListPanel]: ${ex}`);
throw new Error('Failed to extract room data');
}
return data;
}
getBoundingBox(dbId) {
const model = this.viewer.model;
const it = model.getInstanceTree();
const fragList = model.getFragmentList();
let bounds = new THREE.Box3();
it.enumNodeFragments(dbId, (fragId) => {
let box = new THREE.Box3();
fragList.getWorldBounds(fragId, box);
bounds.union(box);
}, true);
return bounds;
}
buildTree(data) {
const nodes = [];
for (let i = 0; i < data.length; i++) {
const node = {
id: data[i].id,
dbId: data[i].dbId,
type: 'spaces',
text: data[i].name
};
nodes.push(node);
}
console.log(nodes);
$(this.treeContainer)
.jstree({
core: {
data: nodes,
multiple: false,
themes: {
icons: false,
name: 'default-dark'
}
},
sort: function (a, b) {
const a1 = this.get_node(a);
const b1 = this.get_node(b);
return (a1.text > b1.text) ? 1 : -1;
},
checkbox: {
keep_selected_style: false,
three_state: false,
deselect_all: true,
cascade: 'none'
},
types: {
spaces: {}
},
plugins: ['types', 'sort', 'wholerow'],
})
.on('changed.jstree', async (e, data) => {
console.log(e, data);
console.log(data.node.original);
const { dbId } = data.node.original;
if (!dbId) return;
const bbox = this.getBoundingBox(dbId);
const center = bbox.center();
const point = new THREE.Vector3(center.x, center.y, bbox.min.z);
this.parent.tweenToPoint(point);
});
}
}
class MoveToRoomExtension extends Autodesk.Viewing.Extension {
constructor(viewer, options) {
super(viewer, options);
this.cameraTweenTool = null;
this.uiCreated = false;
}
onToolbarCreated(toolbar) {
const panel = new RoomListPanel(this);
viewer.addPanel(panel);
this.panel = panel;
const roomsPanelButton = new Autodesk.Viewing.UI.Button('room-panel-button');
roomsPanelButton.onClick = () => {
panel.setVisible(!panel.isVisible());
};
roomsPanelButton.setToolTip('Open room list panel');
this.group = new Autodesk.Viewing.UI.ControlGroup('room-nav-tool-group');
this.group.addControl(roomsPanelButton);
toolbar.addControl(this.group);
}
tweenToPoint(point) {
this.viewer.setActiveNavigationTool('bimwalk');
const views = [];
const up = new THREE.Vector3(0, 0, 1);
const currentEye = this.viewer.navigation.getPosition().clone();
const targetPos = point.clone().add(up.clone().multiplyScalar(1.7 * 3.2808399));
const sightDir = point.clone().sub(currentEye).normalize();
const eyeLen = this.viewer.navigation.getEyeVector().length();
const target = targetPos.clone().add(sightDir.clone().multiplyScalar(eyeLen));
views.push({
up: up.toArray(),
eye: targetPos.toArray(),
target: target.toArray()
});
this.processTweens(views);
}
executeTweenPromised(view) {
return new Promise((resolve, reject) => {
const onTweenExecuted = (event) => {
console.log(event);
this.viewer.removeEventListener(
Autodesk.ADN.CameraTweenTool.CAMERA_TWEEN_ANIMATION_COMPLETED_EVENT,
onTweenExecuted
);
resolve();
};
this.viewer.addEventListener(
Autodesk.ADN.CameraTweenTool.CAMERA_TWEEN_ANIMATION_COMPLETED_EVENT,
onTweenExecuted
);
this.cameraTweenTool.tweenCameraTo({ viewport: view });
});
}
processTweens(data) {
//process each promise
//refer to http://jsfiddle.net/jfriend00/h3zaw8u8/
const promisesInSequence = (tasks, callback) => {
const results = [];
return tasks.reduce((p, item) => {
return p.then(() => {
return callback(item).then((data) => {
results.push(data);
return results;
});
});
}, Promise.resolve());
};
//start to process
return promisesInSequence(data, (d) => this.executeTweenPromised(d));
}
async load() {
const loadCSS = (href) => new Promise(function (resolve, reject) {
const el = document.createElement('link');
el.rel = 'stylesheet';
el.href = href;
el.onload = resolve;
el.onerror = reject;
document.head.appendChild(el);
});
await Promise.all([
Autodesk.Viewing.Private.theResourceLoader.loadScript('https://unpkg.com/#tweenjs/tween.js#18.6.4/dist/tween.umd.js', 'TWEEN'),
Autodesk.Viewing.Private.theResourceLoader.loadScript('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js', '$'),
Autodesk.Viewing.Private.theResourceLoader.loadScript('https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/jstree.min.js', '$'),
loadCSS('https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/themes/default/style.min.css'),
loadCSS('https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.7/themes/default-dark/style.min.css'),
this.viewer.loadExtension('Autodesk.BimWalk'),
this.viewer.loadExtension('Autodesk.ADN.CameraTweenTool')
]);
this.viewer.setBimWalkToolPopup(false);
this.cameraTweenTool = this.viewer.getExtension('Autodesk.ADN.CameraTweenTool');
console.log('MoveToRoomExtension has been loaded.');
return true;
}
async unload() {
this.viewer.unloadExtension('Autodesk.ADN.CameraTweenTool');
this.viewer.setBimWalkToolPopup(true);
delete this.cameraTweenTool;
this.cameraTweenTool = null;
console.log('MoveToRoomExtension has been unloaded.');
return true;
}
}
Autodesk.Viewing.theExtensionManager.registerExtension('Autodesk.ADN.MoveToRoomExtension', MoveToRoomExtension);
})();
I have to fetch 2 api from backend, and try to get the result from this two. but, at the moment, the JSON result I get from the first API is object Array in JSON. I need to pass the id from first API(using setState) to second API for path variables. But when I do in my way, it fail to retrieve the data. Consider the code below:
componentDidMount(){
// console.log(loginEmail)
fetch(`http://localhost:9000/api/item/list`,)
.then((resp)=>{
resp.json().then((res)=>{
console.log(res.data);
// localStorage.setItem('id', res.data.user_info.id);
this.setState({data: res.data});
}
)
})
const id = this.state.data.id;
fetch(`http://localhost:9000/api/item/photo/view/${id}`,)
.then((resp)=>{
resp.json().then((res)=>{
console.log(res);
// localStorage.setItem('id', res.data.user_info.id);
this.setState({res});}
)
})
}
The problem is that fetch returns a Promise so, at the line
const id = this.state.data.id;
You do not have data populated yet.
You have to concatenate the two requests in a way like the following:
componentDidMount() {
fetch(`http://localhost:9000/api/item/list`)
.then((resp) => {
// return the id
})
.then((id) => {
fetch(`http://localhost:9000/api/item/photo/view/${id}`)
.then((resp) => {
// do what you need with the result
})
})
}
Fetch is asynchronous, which means javascript will
fetch data on the first call with no waiting, and continue
to the second fetch call where the id is not defined or Null.
In order to fix that you can use promises as follow
My code example
import React from "react";
class Home extends React.Component {
constructor() {
super();
this.state = {
res: [],
}
}
// http://jsonplaceholder.typicode.com/users
fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((resp) => {
resp.json().then((res) => {
console.log(res);
// localStorage.setItem('id', res.data.user_info.id);
resolve(res);
}
)
})
})
}
async componentDidMount() {
let data = await this.fetchData("http://jsonplaceholder.typicode.com/users");
console.log("data :", data);
let id = data[0].id;
console.log("Id :", id);
let newData = await this.fetchData(`http://jsonplaceholder.typicode.com/users/${id}`);
this.setState({ res: newData });
}
render() {
return (
<div>
Call API
</div>
)
}
}
export default Home
Adapted on your code
fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((resp) => {
resp.json().then((res) => {
console.log(res.data);
// localStorage.setItem('id', res.data.user_info.id);
resolve(res.data);
}
)
})
})
}
async componentDidMount() {
// console.log(loginEmail)
let data = await this.fetchData("http://localhost:9000/api/item/list");
let id = data.id;
let newData = await this.fetchData(`http://localhost:9000/api/item/photo/view/${id}`);
this.setState({ res: newData });
}
You need to make sure that each id gets its relevant results.
async componentDidMount() {
await fetch(`http://localhost:9000/api/item/list`)
.then(async (resp) => {
let req_ = resp.map((item)=>{
return await fetch(`http://localhost:9000/api/item/photo/view/${item.id}`)
})
let result = Promise.all(req_)
console.log(result)
})
}
consider a function
exports.projectNotifyLaunch = (admin, functions) => {
return functions.database.ref("/projects/{pid}").onCreate(snap => {
const { title } = snap.val();
const notification = {
title: `${title} just launched!`,
body: `We just heard about a new cryptocurrency project called ${title}`
};
return admin.messaging().sendToTopic("premium", { notification });
});
};
How should I mock deeply nested functions such as
functions.database.ref("/projects/{pid}").onCreate(snap => {});
or
admin.messaging().sendToTopic("premium", { notification });
in Jest? I want to fire off the snap=>{} callback and assert against the value of notification.
I was able to make this work
This works but it's quite verbose. I'm wondering if there is a better way, or a type of testing I'm not aware of with Jest.
describe("send notification to premium users on new project", () => {
// INPUTS
const snap = {
val: () => ({
title: "Test Title"
})
};
const functions = {
database: {
ref: () => ({
onCreate: callback => callback(snap)
})
}
};
// outputs
let topicStub = null;
let notificationStub = null;
const admin = {
messaging: () => ({
sendToTopic: (topic, notification) => {
topicStub = topic;
notificationStub = notification;
}
})
};
projectNotifyLaunch(admin, functions);
test("title is correct", () => {
expect(notificationStub.notification.title).toBe(
"Test Title just launched!"
);
});
test("topic is premium", () => {
expect(topicStub).toBe("premium");
});
});
Refering to this post, [Download all the derivatives for the purpose of the using Forge Viewer offline/C#, I know that the files provided by derivative api "GET :urn/manifest/:derivativeurn" are enough for offline viewing. However using the same as input in offline viewer isn't working. Analyzing the demo at https://extract.autodesk.io for existing sample files indicated that downloaded bubble has other files too like bin/pack/zip/ json, where can I get these files using C# Api ? Uploading a sample file and using model extractor returned error ("Cannot GET /extracted/1906495-seatdwf.zip")[As per the suggestion, tried extract.autodesk.io version of March 24,but to no use.]
Please guide on how to download required files for offline viewing using C#.
Thanks in advance.
Here is a clear commented Node.js version in ES6+async of the extractor that I wrote inspired from extract.autodesk.io:
import BaseSvc from './BaseSvc'
import archiver from 'archiver'
import Forge from 'forge-apis'
import request from 'request'
import mkdirp from 'mkdirp'
import Zip from 'node-zip'
import Zlib from 'zlib'
import path from 'path'
import _ from 'lodash'
import fs from 'fs'
export default class ExtractorSvc extends BaseSvc {
/////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////
constructor (config) {
super (config)
this.derivativesAPI = new Forge.DerivativesApi()
}
/////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////
name () {
return 'ExtractorSvc'
}
/////////////////////////////////////////////////////////
// Create directory async
//
/////////////////////////////////////////////////////////
mkdirpAsync (dir) {
return new Promise((resolve, reject) => {
mkdirp(dir, (error) => {
return error
? reject (error)
: resolve()
})
})
}
/////////////////////////////////////////////////////////
// download all URN resources to target directory
// (unzipped)
//
/////////////////////////////////////////////////////////
download (getToken, urn, directory) {
return new Promise (async (resolve, reject) => {
// make sure target dir exists
await this.mkdirpAsync (directory)
// get token, can be object token or an async
// function that returns the token
const token = ((typeof getToken == 'function')
? await getToken()
: getToken)
// get URN top level manifest
const manifest =
await this.derivativesAPI.getManifest (
urn, {}, {autoRefresh:false}, token)
// harvest derivatives
const derivatives = await this.getDerivatives (
getToken, manifest.body)
// format derivative resources
const nestedDerivatives = derivatives.map((item) => {
return item.files.map((file) => {
const localPath = path.resolve(
directory, item.localPath)
return {
basePath: item.basePath,
guid: item.guid,
mime: item.mime,
fileName: file,
urn: item.urn,
localPath
}
})
})
// flatten resources
const derivativesList = _.flattenDeep(
nestedDerivatives)
// creates async download tasks for each
// derivative file
const downloadTasks = derivativesList.map(
(derivative) => {
return new Promise(async(resolve) => {
const urn = path.join(
derivative.basePath,
derivative.fileName)
const data = await this.getDerivative(
getToken, urn)
const filename = path.resolve(
derivative.localPath,
derivative.fileName)
await this.saveToDisk(data, filename)
resolve(filename)
})
})
// wait for all files to be downloaded
const files = await Promise.all(downloadTasks)
resolve(files)
})
}
/////////////////////////////////////////////////////////
// Parse top level manifest to collect derivatives
//
/////////////////////////////////////////////////////////
parseManifest (manifest) {
const items = []
const parseNodeRec = (node) => {
const roles = [
'Autodesk.CloudPlatform.DesignDescription',
'Autodesk.CloudPlatform.PropertyDatabase',
'Autodesk.CloudPlatform.IndexableContent',
'leaflet-zip',
'thumbnail',
'graphics',
'preview',
'raas',
'pdf',
'lod',
]
if (roles.includes(node.role)) {
const item = {
guid: node.guid,
mime: node.mime
}
const pathInfo = this.getPathInfo(node.urn)
items.push (Object.assign({}, item, pathInfo))
}
if (node.children) {
node.children.forEach ((child) => {
parseNodeRec (child)
})
}
}
parseNodeRec({
children: manifest.derivatives
})
return items
}
/////////////////////////////////////////////////////////
// Collect derivatives for SVF
//
/////////////////////////////////////////////////////////
getSVFDerivatives (getToken, item) {
return new Promise(async(resolve, reject) => {
try {
const svfPath = item.urn.slice (
item.basePath.length)
const files = [svfPath]
const data = await this.getDerivative (
getToken, item.urn)
const pack = new Zip (data, {
checkCRC32: true,
base64: false
})
const manifestData =
pack.files['manifest.json'].asNodeBuffer()
const manifest = JSON.parse (
manifestData.toString('utf8'))
if (manifest.assets) {
manifest.assets.forEach((asset) => {
// Skip SVF embedded resources
if (asset.URI.indexOf('embed:/') === 0) {
return
}
files.push(asset.URI)
})
}
return resolve(
Object.assign({}, item, {
files
}))
} catch (ex) {
reject (ex)
}
})
}
/////////////////////////////////////////////////////////
// Collect derivatives for F2D
//
/////////////////////////////////////////////////////////
getF2dDerivatives (getToken, item) {
return new Promise(async(resolve, reject) => {
try {
const files = ['manifest.json.gz']
const manifestPath = item.basePath +
'manifest.json.gz'
const data = await this.getDerivative (
getToken, manifestPath)
const manifestData = Zlib.gunzipSync(data)
const manifest = JSON.parse (
manifestData.toString('utf8'))
if (manifest.assets) {
manifest.assets.forEach((asset) => {
// Skip SVF embedded resources
if (asset.URI.indexOf('embed:/') === 0) {
return
}
files.push(asset.URI)
})
}
return resolve(
Object.assign({}, item, {
files
}))
} catch (ex) {
reject (ex)
}
})
}
/////////////////////////////////////////////////////////
// Get all derivatives from top level manifest
//
/////////////////////////////////////////////////////////
getDerivatives (getToken, manifest) {
return new Promise(async(resolve, reject) => {
const items = this.parseManifest(manifest)
const derivativeTasks = items.map((item) => {
switch (item.mime) {
case 'application/autodesk-svf':
return this.getSVFDerivatives(
getToken, item)
case 'application/autodesk-f2d':
return this.getF2dDerivatives(
getToken, item)
case 'application/autodesk-db':
return Promise.resolve(
Object.assign({}, item, {
files: [
'objects_attrs.json.gz',
'objects_vals.json.gz',
'objects_offs.json.gz',
'objects_ids.json.gz',
'objects_avs.json.gz',
item.rootFileName
]}))
default:
return Promise.resolve(
Object.assign({}, item, {
files: [
item.rootFileName
]}))
}
})
const derivatives = await Promise.all(
derivativeTasks)
return resolve(derivatives)
})
}
/////////////////////////////////////////////////////////
// Generate path information from URN
//
/////////////////////////////////////////////////////////
getPathInfo (encodedURN) {
const urn = decodeURIComponent(encodedURN)
const rootFileName = urn.slice (
urn.lastIndexOf ('/') + 1)
const basePath = urn.slice (
0, urn.lastIndexOf ('/') + 1)
const localPathTmp = basePath.slice (
basePath.indexOf ('/') + 1)
const localPath = localPathTmp.replace (
/^output\//, '')
return {
rootFileName,
localPath,
basePath,
urn
}
}
/////////////////////////////////////////////////////////
// Get derivative data for specific URN
//
/////////////////////////////////////////////////////////
getDerivative (getToken, urn) {
return new Promise(async(resolve, reject) => {
const baseUrl = 'https://developer.api.autodesk.com/'
const url = baseUrl +
`derivativeservice/v2/derivatives/${urn}`
const token = ((typeof getToken == 'function')
? await getToken()
: getToken)
request({
url,
method: 'GET',
headers: {
'Authorization': 'Bearer ' + token.access_token,
'Accept-Encoding': 'gzip, deflate'
},
encoding: null
}, (err, response, body) => {
if (err) {
return reject(err)
}
if (body && body.errors) {
return reject(body.errors)
}
if ([200, 201, 202].indexOf(
response.statusCode) < 0) {
return reject(response)
}
return resolve(body || {})
})
})
}
/////////////////////////////////////////////////////////
// Save data to disk
//
/////////////////////////////////////////////////////////
saveToDisk (data, filename) {
return new Promise(async(resolve, reject) => {
await this.mkdirpAsync(path.dirname(filename))
const wstream = fs.createWriteStream(filename)
const ext = path.extname(filename)
wstream.on('finish', () => {
resolve()
})
if (typeof data === 'object' && ext === '.json') {
wstream.write(JSON.stringify(data))
} else {
wstream.write(data)
}
wstream.end()
})
}
/////////////////////////////////////////////////////////
// Create a zip
//
/////////////////////////////////////////////////////////
createZip (rootDir, zipfile, zipRoot, files) {
return new Promise((resolve, reject) => {
try {
const output = fs.createWriteStream(zipfile)
const archive = archiver('zip')
output.on('close', () => {
resolve()
})
archive.on('error', (err) => {
reject(err)
})
archive.pipe(output)
if (files) {
files.forEach((file) => {
try {
const rs = fs.createReadStream(file)
archive.append(rs, {
name:
`${zipRoot}/${file.replace(rootDir, '')}`
})
} catch(ex){
console.log(ex)
}
})
} else {
archive.bulk([ {
expand: false,
src: [rootDir + '/*']
}])
}
archive.finalize()
} catch (ex) {
reject(ex)
}
})
}
}
An example of use is as follow:
// name of model to download
const name = 'MyForgeModel'
// URN of model to download
const urn = 'dXGhsujdj .... '
// Get Forge service
const forgeSvc = ServiceManager.getService(
'ForgeSvc')
// getToken async function
const getToken = () => forgeSvc.get2LeggedToken()
// Get Extractor service
const extractorSvc = ServiceManager.getService(
'ExtractorSvc')
// target path to download SVF
const dir = path.resolve(__dirname, `${name}`)
// perform download
const files = await extractorSvc.download(
getToken, urn, dir)
// target zipfile
const zipfile = dir + '.zip'
// zip all files
await extractorSvc.createZip(
dir, zipfile, name, files)
// remove downloaded resources directory
rmdir(dir)