Skip to content

Instantly share code, notes, and snippets.

@wallabyway
Last active July 27, 2021 03:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wallabyway/feb1d0c2a853ee413d2b8b0600df02e3 to your computer and use it in GitHub Desktop.
Save wallabyway/feb1d0c2a853ee413d2b8b0600df02e3 to your computer and use it in GitHub Desktop.

Forge Properties API swizzle endpoint

A Proxy Server that provides an alternative Forge Properties API endpoints for your BIM360 content. It does this by replacing any reference of svf2 dbids with svf1 dbids.

Just point your application to this proxy server, and it will swizzle the dbIDs for you, and provide you the matching properties meta-data (prior to the July 1st changes).

Screen Shot 2021-07-26 at 8 01 35 PM

TO INSTALL

> npm install node-fetch fastify

TO RUN

> node server-props-proxy.js

TO TEST

> curl http://localhost:3000/:urn/metadata/:guid/properties

| include bim360 access token in the bearer header

See screenshot:

Screen Shot 2021-07-26 at 7 59 22 PM

/*
Alternative Forge Properties API endpoints for BIM360 content, and replaces svf2 dbids with svf1 dbids.
INSTALL
> npm install node-fetch fastify
RUN
> node server-props-proxy.js
> curl localhost:8000/properties?urn=:urn&guid=:guid
> include bim360 bearer token
*/
const fetch = require('node-fetch');
const fastify = require('fastify')({ logger: true });
const fs = require('fs');
const path = require('path');
const FORGE_SVF2_URL = `https://otg.autodesk.com/modeldata/manifest`;
const opts = token => ({ compress: true, headers: { 'Authorization': 'Bearer ' + token }});
fastify.register(require('fastify-static'), {
root: path.join(__dirname, 'ui'),
prefix: '/', // optional: default '/'
})
function setCORS(reply) {
reply.header("Access-Control-Allow-Origin", "*");
reply.header("Access-Control-Allow-Methods", "POST");
}
const cache =[];
// INPUT: projectID, folderID, AccessToken
// OUTPUT: list of BIM360 files in the folder
fastify.get('/:urn/metadata/:guid/properties', async (request, reply) => {
if (!request.headers.authorization) return "error: expected BIM360 ACCESS-TOKEN in bearer header";
if (!request.params.urn) return "INPUT: missing URN";
if (!request.params.guid) return "INPUT: missing guid";
setCORS(reply);
const urn = request.params.urn;
const guid = request.params.guid;
const token = request.headers.authorization.slice(7);
let dbidIdx;
if (!cache[urn]) {
const otg_manifest = await getPathFromManifest(urn, token);
dbidIdx = await downloadLookupTable(otg_manifest, token);
cache[urn]=dbidIdx;
} else
dbidIdx = cache[urn];
const res_svf2 = await getAllProperties(dbidIdx, urn, guid, token);
return res_svf2;
});
async function getPathFromManifest(urn, token) {
const resp = await fetch(`${FORGE_SVF2_URL}/${urn}`, opts(token));
if (resp.status != 200)
throw("!! PLEASE LOG IN. GRAB A BIM360 ACCESS TOKEN");
const jsn = await resp.json();
return jsn.children[0].otg_manifest;
}
async function downloadLookupTable(otgm, token) {
const file = `dbid.idx`;
const url = `https://us.otgs.autodesk.com/modeldata/file/${otgm.paths.version_root}${otgm.pdb_manifest.pdb_version_rel_path}`;
const buff = await ( await fetch(`${url}${file}?acmsession=${otgm.urn}`, opts(token) )).buffer();
const dbidIdx = new Uint32Array(buff.buffer, buff.byteOffset, buff.byteLength / Uint32Array.BYTES_PER_ELEMENT);
return dbidIdx;
}
// GET {urn}/metadata/:guid/properties
async function getAllProperties(dbidIdx, urn, guid, token) {
const json = await ( await fetch(`https://developer.api.autodesk.com/modelderivative/v2/designdata/${urn}/metadata/${guid}/properties`, opts(token) )).json();
json.data.collection.map( i => {i.svf2 = i.objectid; i.objectid = dbidIdx[i.svf2]})
return json;
}
//GET {urn}/metadata/:guid
async function getAllGUID(dbidIdx, urn, guid, token) {
const json = await ( await fetch(`https://developer.api.autodesk.com/modelderivative/v2/designdata/${urn}/metadata/${guid}`, opts(token) )).json();
json.data.collection.map( i => {i.svf2 = i.objectid; i.objectid = dbidIdx[i.svf2]})
return json;
}
//GET {urn}/metadata
async function getAllMetaData(dbidIdx, urn, token) {
const json = await ( await fetch(`https://developer.api.autodesk.com/modelderivative/v2/designdata/${urn}/metadata`, opts(token) )).json();
json.data.collection.map( i => {i.svf2 = i.objectid; i.objectid = dbidIdx[i.svf2]})
return json;
}
fastify.listen(process.env.PORT || 3000, "0.0.0.0", (err, address) => {
if (err) throw err
console.log(`server listening on ${address}`)
fastify.log.info(`server listening on ${address}`)
})
// lookup svf1 DBID and get it's SVF2 dbid, and use this to retrieve Forge Properties.
// SETUP:
// add your DBID, URN, GUID & BIM360_ACCESS_TOKEN
// > npm install node-fetch
// > node svf1tosvf2.js
// OUTPUT:
/*
svf1-dbid:998 => svf2-dbid:1126
getting properties using id:1126
{"data":{"type":"properties","collection":[{"objectid":1126,"name":"Steelcase - 4799 Platinum Metallic","externalId":"1/4/0/0/38/0/3","properties":{"Item":{"Name":"Steelcase - 4799 Platinum Metallic","Type":"Solid","Icon":"Geometry","Hidden":"No","Required":"No","Material":"Steelcase - 4799 Platinum Metallic","Source File":"4E Map.rvt","Layer":"Level 1"},"Material":{"Name":"Steelcase - 4799 Platinum Metallic","Ambient.Red":"0.612","Ambient.Green":"0.616","Ambient.Blue":"0.624","Diffuse.Red":"0.612","Diffuse.Green":"0.616","Diffuse.Blue":"0.624","Specular.Red":"0.000","Specular.Green":"0.000","Specular.Blue":"0.000","Emissive.Red":"0.000","Emissive.Green":"0.000","Emissive.Blue":"0.000","Shininess":"0.500","Transparency":"0.000"},"Revit Material":{"Name":"Steelcase - 4799 Platinum Metallic","Color":"156, 157, 159","Shininess":"64","Smoothness":"50","Transparency":"0"},"Autodesk Material":{"Name":"Steelcase - 4799 Platinum Metallic","Type":"WallPaint"}}}]}}
done
*/
const fetch = require('node-fetch');
const opts = token => ({ compress: true, headers: { 'Authorization': 'Bearer ' + token }});
const DBID = 998;
const URN = "dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLk9PQXpBSk55UXZlcW53eW9wejJDSVE_dmVyc2lvbj0x";
const GUID = "e9209e66-de3c-4272-a58f-d5abd5def166";
const TOKEN = "eyJhbGciOiJSUzI1NiIsImtpZCI6IlU3c0dGRldUTzlBekNhSzBqZURRM2dQZXBURVdWN2VhIn0.eyJzY29wZSI6WyJidWNrZXQ6Y3JlYXRlIiwiYnVja2V0OnJlYWQiLCJkYXRhOnJlYWQiLCJkYXRhOmNyZWF0ZSIsImRhdGE6d3JpdGUiXSwiY2xpZW50X2lkIjoiSXdhVEdSZjM4bUFlTkl4WFpTNnlrM0pGeGZub2RBTG8iLCJhdWQiOiJodHRwczovL2F1dG9kZXNrLmNvbS9hdWQvYWp3dGV4cDYwIiwianRpIjoicmU4eUtoMGdJdXNxZzFYN3cxMktkdWM4dTY0SEQxc0RjN0thTDdsS1FXMUp3Z0J3UnFkeDh0MkFPTjZ1bnM1YiIsInVzZXJpZCI6IjIwMDgxMTIwMDQwNzgwNCIsImV4cCI6MTYyNjQwNjU5NH0.f7-GBOiGY9ulRY2ksMSwxW6HFZuwJV58rsUG3iXpguL8DeJzMuPKXP0y0CdBaCT7Lmd-n2QtGMTU3DSXSuK5C_ijmD8QZlW38bgtbxs__ynR7fOOOAgivQNLlF-fu_ZwpRCBpEzywUIt6TeKsl7j26e-EfDf0lcDnuvGJJt64VJYmHRz1kWYInIGsaCpXQYqYALf5KaamZa-BFJjPwRqdW8tNy2EvlvIZNdtPEMcHNEwTCkSxOhPnmp_zlcRxlfoLKRT2YgIawVRpK47oaIJ7eQ58OC6feDs9FCpzdHN1fEWf_9BDK3Q87FX4EBIp5PewPmd1Xv7xlTzVY-3vkrdxw"
const FORGE_SVF2_URL = `https://otg.autodesk.com/modeldata/manifest`;
async function getPathFromManifest(urn, token) {
const resp = await fetch(`${FORGE_SVF2_URL}/${urn}`, opts(token));
if (resp.status != 200)
throw("!! PLEASE LOG IN. GRAB A BIM360 ACCESS TOKEN");
const jsn = await resp.json();
return jsn.children[0].otg_manifest;
}
async function downloadLookupTable(otgm, token) {
const file = `dbid.idx`;
const url = `https://us.otgs.autodesk.com/modeldata/file/${otgm.paths.version_root}${otgm.pdb_manifest.pdb_version_rel_path}`;
const buff = await ( await fetch(`${url}${file}?acmsession=${URN}`, opts(token) )).buffer();
const dbidIdx = new Uint32Array(buff.buffer, buff.byteOffset, buff.byteLength / Uint32Array.BYTES_PER_ELEMENT);
return dbidIdx;
}
async function getProperties(svf2_dbid, token) {
const json = await ( await fetch(`https://developer.api.autodesk.com/modelderivative/v2/designdata/${URN}/metadata/${GUID}/properties?objectid=${svf2_dbid}`, opts(token) )).json();
return json;
}
async function main(urn, guid, dbid, token) {
const otg_manifest = await getPathFromManifest(urn, token);
const dbidIdx = await downloadLookupTable(otg_manifest, token);
console.log(`svf1-dbid:${dbid} => svf2-dbid:${dbidIdx[dbid]}`);
console.log(`getting properties using id:${dbidIdx[dbid]}`);
const res = await getProperties(dbidIdx[dbid], token);
console.log(JSON.stringify(res));
console.log('done');
}
main(URN, GUID, DBID, TOKEN);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment