<|start_filename|>setup/init.bat<|end_filename|>
REM Please enter a unique name for your service somemthing along the lines below
set DA_VIEWER_SERVIVCE_NAME=youcompanyname-service-37a1eae178c3

REM Please enter your AWS access key
set AWS_ACCESS_KEY_ID=

REM Please enter your AWS access key secret
set AWS_SECRET_ACCESS_KEY=

REM The region can be configured
set AWS_DEFAULT_REGION=us-west-2

REM Please enter a unique name for the bucket, something along the lines below
set DA_VIEWER_DWG_BUCKET=youcompanyname-service-37a1eae178c3

REM Please enter the Autodesk developer key
set ADSK_DEVELOPER_KEY=

REM Please enter the Autodesk developer key secret
set ADSK_DEVELOPER_SECRET=



<|start_filename|>setup/package.json<|end_filename|>
{
  "name": "ViewerSampleSetup",
  "version": "0.1.0",
  "description": "ViewerSampleSetup",
  "main": "setup.js",
  "author": {
    "name": "<NAME>",
    "email": "<EMAIL>"
  },
  "dependencies": {
    "aws-sdk": "^2.2.48",
    "uuid": "^2.0.2"
  }
}


<|start_filename|>src/RxApp/Commands.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices.Core;
using Autodesk.AutoCAD.DatabaseServices;
using System.Collections.ObjectModel;
using Autodesk.AutoCAD.EditorInput;
using System.IO;
using System.Runtime.Serialization.Json;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.ApplicationServices;

[assembly: CommandClass(typeof(RxApp.Commands))]
[assembly: ExtensionApplication(null)]

namespace RxApp
{
    public class Commands
    {
        [CommandMethod("MyTestCommand", "test", CommandFlags.Modal)]
        static public void Test()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;

            PromptResult pr = ed.GetString("Specify output filename:");
            if (pr.Status == Autodesk.AutoCAD.EditorInput.PromptStatus.Cancel)
            {
                ed.WriteMessage("Command cancelled");
                return;
            }
            string outputFile = pr.StringResult;
            if (string.IsNullOrEmpty(outputFile))
            {
                ed.WriteMessage("Error: Invalid output file");
                return;
            }

            try
            {
                Collection<DBObjectInfo> xdata = new Collection<DBObjectInfo>();

                Database db = doc.Database;
                ObjectId modId = SymbolUtilityServices.GetBlockModelSpaceId(db);
                using (Transaction trans = doc.TransactionManager.StartTransaction())
                {
                    BlockTableRecord btr = trans.GetObject(modId, OpenMode.ForRead) as BlockTableRecord;
                    foreach (ObjectId entId in btr)
                    {
                        DBObject obj = trans.GetObject(entId, OpenMode.ForRead);
                        ResultBuffer rb = obj.XData;
                        if (rb == null)
                            continue;

                        DBObjectInfo objInfo = new DBObjectInfo();
                        objInfo.Id = obj.Handle.ToString();
                        string strValue;
                        foreach (TypedValue tvalue in rb)
                        {
                            strValue = "";
                            if (tvalue.TypeCode == 1004)
                            {
                                string hexvalue = BitConverter.ToString(tvalue.Value as byte[]);
                                hexvalue = hexvalue.Replace("-", "");
                                strValue = hexvalue;
                            }
                            else
                            {
                                strValue = string.Format("{0}", tvalue.Value);
                            }

                            DataValue dataVal = new DataValue();
                            dataVal.Type = tvalue.TypeCode;
                            dataVal.Value = strValue;

                            objInfo.XData.Add(dataVal);
                        }
                        rb.Dispose();

                        xdata.Add(objInfo);
                    }
                }

                if (xdata.Count <= 0)
                {
                    ed.WriteMessage("There are no XData associated with entities in this drawing.");
                    return;
                }

                Directory.CreateDirectory(Path.GetDirectoryName(outputFile));
                using (var stream = File.Create(outputFile))
                {
                    DataContractJsonSerializer ser = new DataContractJsonSerializer(xdata.GetType());
                    ser.WriteObject(stream, xdata);
                }

            }
            catch (System.Exception e)
            {
                ed.WriteMessage("Error: {0}", e);
            }
        }

        [CommandMethod("MyTestCommand", "testpoly", CommandFlags.Modal)]
        static public void Poly()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            using (DocumentLock l = doc.LockDocument())
            {
                using (Transaction t = doc.Database.TransactionManager.StartTransaction())
                {
                    BlockTable bt = (BlockTable)t.GetObject(doc.Database.BlockTableId, OpenMode.ForRead);
                    BlockTableRecord btr = (BlockTableRecord)t.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                    using (Autodesk.ObjectDbxSample.Poly poly = new Autodesk.ObjectDbxSample.Poly())
                    {
                        poly.Center = new Point2d(100, 100);
                        poly.StartPoint2d = new Point2d(300, 100);
                        poly.NumberOfSides = 5;
                        poly.Name = "Managed Poly";

                        btr.AppendEntity(poly);
                        t.AddNewlyCreatedDBObject(poly, true);

                        AddRegAppTableRecord("IOVIEWERSAMPLE");
                        ResultBuffer rb = new ResultBuffer(new TypedValue(1001, "IOVIEWERSAMPLE"),
                            new TypedValue(1000, "This is a sample string"));

                        poly.XData = rb;
                        rb.Dispose();
                    }
                    t.Commit();
                }
            }            
        }

        static void AddRegAppTableRecord(string regAppName)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            using (Transaction tr = doc.TransactionManager.StartTransaction())
            {
                RegAppTable regAppTable = (RegAppTable)tr.GetObject(db.RegAppTableId, OpenMode.ForRead, false);
                if (!regAppTable.Has(regAppName))
                {
                    regAppTable.UpgradeOpen();
                    RegAppTableRecord regAppTableRecord = new RegAppTableRecord();
                    regAppTableRecord.Name = regAppName;
                    regAppTable.Add(regAppTableRecord);
                    tr.AddNewlyCreatedDBObject(regAppTableRecord, true);
                }
                tr.Commit();
            }
        }
    }
}


<|start_filename|>src/www/Autodesk.DASample.Viewing.Extension.DisplayXData.js<|end_filename|>
﻿// The viewer extension to view Xdata associated with the object
//
AutodeskNamespace("Autodesk.DASample.Viewing.Extension");

// The property panel to view the xdata values
XDataPanel = function (parentContainer, id, x, y) {
    this.content = document.createElement('div');
    Autodesk.Viewing.UI.PropertyPanel.call(this, parentContainer, id, 'XData');

    this.container.style.height = "auto";
    this.container.style.width = "auto";
    this.container.style.resize = "none";
    this.container.style.left = x + "px";
    this.container.style.top = y + "px";
};

XDataPanel.prototype = Object.create(Autodesk.Viewing.UI.PropertyPanel.prototype);
XDataPanel.prototype.constructor = XDataPanel;
XDataPanel.prototype.initialize = function () {

    this.title = this.createTitleBar(this.titleLabel || this.container.id);
    this.container.appendChild(this.title);
    this.container.appendChild(this.content);
    this.initializeMoveHandlers(this.container);
};


Autodesk.DASample.Viewing.Extension.DisplayXData = function (viewer, options) {

    Autodesk.Viewing.Extension.call(this, viewer, options);

    var _self = this;
    var _panel = null;

    _self.load = function () {
        viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, onSelectionChanged);
        _panel = new XDataPanel(viewer.container, guid(), 5, 5);
        _panel.setVisible(true);

        return true;
    };

    _self.unload = function () {

        viewer.removeEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, onSelectionChanged);
        return true;
    };

    function guid() {

        var d = new Date().getTime();

        var guid = 'xxxx-xxxx-xxxx-xxxx'.replace(
          /[xy]/g,
          function (c) {
              var r = (d + Math.random() * 16) % 16 | 0;
              d = Math.floor(d / 16);
              return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
          });

        return guid;
    }

    function onSelectionChanged(event) {
        _panel.removeAllProperties();

        var viewer = event.target;
        event.dbIdArray.forEach(function (dbId) {
            displayXData(dbId);
        });
    }

    // The function checks if the object that is passed has any xdata that has 
    // been cached. The object handle is used to check the availability 
    // in the cache.
    //
    function displayXData(dbId) {
        if (!xdatainfo)
            return;

        viewer.getProperties(dbId, function _cb(result) {
            if (result.properties) {
                var displayValue;
                var length = result.properties.length;
                for (var i = 0; i < length; i++) {
                    var prop = result.properties[i];
                    if (prop.displayName === "elementId") {
                        displayValue = prop.displayValue;
                        break;
                    }
                }

                if (displayValue) {
                    if (xdatainfo[displayValue]) {
                        var xdata = xdatainfo[displayValue].XData;
                        var length = xdata.length;
                        for (var i = 0; i < length; i++) {
                            _panel.addProperty(xdata[i].Type, xdata[i].Value, dbId);
                        }
                    }
                }
            }
        });
    }
};

Autodesk.DASample.Viewing.Extension.DisplayXData.prototype =
    Object.create(Autodesk.Viewing.Extension.prototype);

Autodesk.DASample.Viewing.Extension.DisplayXData.prototype.constructor =
    Autodesk.DASample.Viewing.Extension.DisplayXData;

Autodesk.Viewing.theExtensionManager.registerExtension(
    'Autodesk.DASample.Viewing.Extension.DisplayXData',
    Autodesk.DASample.Viewing.Extension.DisplayXData);


<|start_filename|>src/lambda/npminstall.bat<|end_filename|>
rem call npm install to download all the dependencies
npm install



<|start_filename|>src/lambda/app.js<|end_filename|>
﻿"use strict";

var AWS = require("aws-sdk");
var request = require("request");
var uuid = require("uuid");
var unzip = require("unzip");
var async = require("async");
var stream = require("stream");
var path = require("path");

// local files
var config = require("./config.js");



// Helper functions
//

// Sends a request with the authorization token
//
function sendAuthData(uri, httpmethod, token, data, callback) {

    var requestbody = "";
    if (data) {
        requestbody = JSON.stringify(data);
    }

    request({
        url: uri,
        method: httpmethod,
        headers: {
            "Content-Type": "application/json",
            "Authorization": token
        },
        body: requestbody
    }, function (error, response, body) {
        if (callback) {
            callback(error || response.statusCode, body);
        } else {
            if (error) {
                console.log(error);
            } else {
                console.log(response.statusCode, body);
            }
        }
    });
}

// Helper function to check if the given app package is available
//
function isPackageAvailable(url, token, packagename, callback) {
    var uri = url + "(\'" + packagename + "\')";
    sendAuthData(uri, "GET", token, null, function (status) {
        if (status === 200) {
            callback(true);
        }
        else {
            callback(false);
        }
    });
}

// The function checks if the activity with the given name is available
//
function isActivityAvailable(url, token, activityname, callback) {
    var uri = url + "(\'" + activityname + "\')";
    sendAuthData(uri, "GET", token, null, function (status) {
        if (status === 200) {
            callback(true);
        }
        else {
            callback(false);
        }
    });
}

// The functions submits a workitem using the Design Automation API.
//
function submitWorkItem(url, token, activityname, resource, callback) {
    var workitembody = {
        "ActivityId": activityname,
        "Arguments": {
            "InputArguments": [
                {
                    "Name": "HostDwg",
                    "Resource": resource,
                    "StorageProvider": "Generic"
                }
            ],
            "OutputArguments": [
                {
                    "HttpVerb": "POST",
                    "Name": "Results",
                    "Resource": null,
                    "ResourceKind": "ZipPackage",
                    "StorageProvider": "Generic"
                }
            ]
        }
    };

    sendAuthData(url, "POST", token, workitembody, function (status, param) {
        if (status === 200 || status === 201) {
            console.log("Submitted work item");
            var paramObj = JSON.parse(param);
            callback(true, paramObj.Id);
        } else {
            console.log("Error: submitting workitem");
            callback(false);
        }
    });
}

// The function creates the app package and the custom activity if not available and then submits the
// workitem for the given drawing.
//
function submitItem(token, dwgLocation, activityname, callback) {

    isPackageAvailable(config.package_endpoint, token, config.package_name, function (status) {
        if (status) {
            isActivityAvailable(config.activity_endpoint, token, activityname, function (status) {
                if (status) {
                    submitWorkItem(config.workitem_endpoint, token, activityname, dwgLocation, function (ret, workitemId) {
                        if (ret) {
                            console.log("Sucessfully submitted the workitem");
                            callback(true, workitemId);
                        } else {
                            console.log("Error: submitting the workitem");
                            callback(false);
                        }
                    });
                } else {
                    console.log("Error: Activity " + activityname + " not available ");
                    callback(false);
                    return;
                }
            });
        } else {
            console.log("Error: AppPackage " + config.package_name + " not available ");
            callback(false);
            return;
        }
    });
}

// Helper function to download binary data
//
function getBinaryData(uri, callback) {
    request({
        url: uri,
        method: "GET",
        encoding: null
    }, function (error, response, body) {
        if (callback) {
            callback(error || response.statusCode, body);
        } else {
            if (error) {
                console.log(error);
            } else {
                console.log(response.statusCode, body);
            }
        }
    });
}

// The function uncompresses the data, and upload the result to S3.
// In the process it also stores the location of SVF/F2D and xdata,
// and returns it to the caller.
//
function uploadResultToS3(body, folderName, callback) {

    var s3 = new AWS.S3({ accessKeyId: config.aws_key, secretAccessKey: config.aws_secret });

    var resultLocation;
    var location;
    var customdatalocation;
    var count = 0;
    var bufferStream = new stream.PassThrough();
    bufferStream.end(body);
    bufferStream.pipe(unzip.Parse()).on("entry", function (entry) {
        ++count;
        var fileName = entry.path;

        var index = fileName.indexOf("\\");
        if (index !== -1) {
            fileName = fileName.replace("\\", "/");
        }

        var key = folderName + fileName;

        var params = { Bucket: config.aws_s3_bucket, Key: key, ACL: "public-read", Body: entry };
        s3.upload(params, function (err, data) {
            if (err) {
                console.log("Error: uploading to S3" + ": " + err);
                entry.autodrain();
                callback(false);
            } else {
                resultLocation = path.parse(data.Location);
                if (resultLocation) {
                    if (resultLocation.ext.toUpperCase() === ".SVF") {
                        location = data.Location;
                    } else if (resultLocation.ext.toUpperCase() === ".F2D") {
                        location = data.Location;
                    } else {
                        if (resultLocation.base.toUpperCase() === "XDATA.JSON") {
                            customdatalocation = data.Location;
                        }
                    }
                }
                count--;
                console.log("Successfully uploaded " + count);
                if (count === 0) {
                    callback(true, location, customdatalocation);
                }
            }
        });
    });
}

// Get the result and process it.
//
function uploadWorkItemResult(url, folderName, callback) {
    if (!url) {
        callback(false);
    }

    getBinaryData(url, function (status, body) {
        if (status === 200) {
            uploadResultToS3(body, folderName, function (status, resultlocation, xdatalocation) {
                if (status) {
                    callback(true, resultlocation, xdatalocation);
                } else {
                    console.log("Error: failed to upload the results to S3");
                    callback(false);
                }
            });
        }
        else {
            callback(false);
        }
    });
}

// The function gets the status of the workitem using the DesignAutomation API,
// loops through to a count of ten if the status is pending with a time interval
// of two seconds. The AWS API gateway timesout at 30s, and so it keeps the loop
// below thirty seconds after which it returns the pending status to the client.
// It returns the status immediately on success or failure.
//
function getWorkItemStatus(url, token, callback) {
    var count = 0;
    async.forever(function (next) {
        setTimeout(sendAuthData(url, "GET", token, null, function (status, body) {
            if (status === 200) {
                var result = JSON.parse(body);
                if (result.Status === "Pending" || result.Status === "InProgress") {
                    if (count > 10) {
                        // Exit at count 10, we do not want to run over 20s
                        next({ Status: true, StatusText: "Pending" });
                        return;
                    }

                    next();
                    ++count;
                } else if (result.Status === "Succeeded") {
                    next({ Status: true, StatusText: "Succeeded", Result: { Output: result.Arguments.OutputArguments[0].Resource, Report: result.StatusDetails.Report } });
                }
                else {
                    next({ Status: true, StatusText: "Failed", Result: { Report: result.StatusDetails.Report } });
                }
            }
            else {
                next({ Status: false, StatusText: "Failed", Result: body });
            }
        }), 2000);
    }, function (obj) {
        if (obj.Status) {
            callback(true, obj.StatusText, obj.Result);
        } else {
            callback(false, obj.StatusText, obj.Result);
        }
    });
}


// Helper function to get the access token
//
function requestToken(authurl, key, secret, callback) {
    request({
        url: authurl,
        method: "POST",
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        },
        body: "client_id=" + key + "&client_secret=" + secret + "&grant_type=client_credentials" + "&scope=code:all"
    }, function (error, response, body) {
        if (callback) {
            var token = "";
            var bodyObj = {};
            if (body) {
                bodyObj = JSON.parse(body);
            }
            if (bodyObj.token_type && bodyObj.access_token) {
                token = bodyObj.token_type + " " + bodyObj.access_token;
            }
            callback(error, token);
        }
        else {
            if (error) {
                console.log(error);
            } else {
                console.log(response.statusCode, body);
            }
        }
    });
}

function getToken(url, key, secret, callback) {
    requestToken(url, key, secret, function (err, token) {
        if (err) {
            console.log("Error: " + err.toString());
        }
        callback(token);
    });
}

// The function returns a pre-signed url location that the client can upload the drawing
//
module.exports.uploadlocation = (event, context, callback) => {

    // The drawing name is passed as part of the input request
    var drawingName = event.dwgname;
    if (drawingName) {
        drawingName = decodeURIComponent(drawingName);
    } else {
        drawingName = "input.dwg";
    }

    // Create a unique key
    var key = "drawings/" + uuid.v4() + "/" + drawingName;

    var s3 = new AWS.S3({ accessKeyId: config.aws_key, secretAccessKey: config.aws_secret });
    var params = { Bucket: config.aws_s3_bucket, Key: key };
    var url = s3.getSignedUrl("putObject", params);

    // Return the presigned url
    if (url) {
        context.callbackWaitsForEmptyEventLoop = false;
        var param = { Result: url };
        callback(null, param);
    } else {
        context.callbackWaitsForEmptyEventLoop = false;
        callback("Could not process the request", "Error message");
    }
};

// The function takes the activity name, and the location of the drawing file as input.
// It checks if the custom package and the activity are present.
// And then the workitem is then submitted using the DesignAutomation API, configured to run the
// activity that was passed.
//
module.exports.submitworkitem = (event, context, callback) => {

    // Get the activity name from the request
    //
    var activityname = event.activityname;

    if (!activityname) {
        callback("Error: Invalid activity name", "Error message");
        return;
    }

    if (!event.dwglocation) {
        callback("Error: Invalid drawing location");
        return;
    }

    var url = event.dwglocation;
    if (url.indexOf("?") !== -1) {
        var key = event.dwglocation;
        var strtoken = "amazonaws.com/";
        key = key.substring(key.indexOf(strtoken) + strtoken.length);
        key = key.substring(0, key.indexOf("?"));
        if (!key) {
            callback("Invalid pre-signed url");
            return;
        }

        key = decodeURIComponent(key);

        // Create a presigned url for GET that needs to be passed to DesignAutomation API
        //
        var s3 = new AWS.S3({ accessKeyId: config.aws_key, secretAccessKey: config.aws_secret });
        var params = { Bucket: config.aws_s3_bucket, Key: key };
        url = s3.getSignedUrl("getObject", params);
    }

    if (!url) {
        context.callbackWaitsForEmptyEventLoop = false;
        callback("Could not process the request", "Error message");
        return;
    }

    getToken(config.auth_endpoint, config.developer_key, config.developer_secret, function (token) {
        if (!token) {
            callback("Error: Failed to obtain the access token");
            return;
        }

        submitItem(token, url, activityname, function (ret, workitemId) {
            if (ret) {
                context.callbackWaitsForEmptyEventLoop = false;
                var param = { Result: workitemId };
                callback(null, param);
            } else {
                context.callbackWaitsForEmptyEventLoop = false;
                callback("Could not process the request", "Error message");
            }
        });
    });
}

// The function takes the workitem identifier as the input, and checks the
// status of the respective workitem. The function uses the DesignAutomation
// API to poll the status. It returns immediately on success or failure of the
// workitem. If the workitem status is pending or in-progress, it loops through,
// polling the status every two seconds for up to twenty seconds and then returns.
// The reason it returns after twenty seconds is due to a thirty second timeout
// limit set by the AWS API gateway. If the API does not respond within thirty
// seconds, then the request is terminated and an error status of 504 is returned
// by the AWS API gateway.
//
module.exports.workitemstatus = (event, context, callback) => {

    // Get the workitem id from the request
    //
    var workitemId = event.workitemid;
    if (!workitemId) {
        callback("Error: Invalid workitem id");
        return;
    }
    workitemId = decodeURIComponent(workitemId);
    var url = config.workitem_endpoint + "(\'" + workitemId + "\')";

    getToken(config.auth_endpoint, config.developer_key, config.developer_secret, function (token) {

        getWorkItemStatus(url, token, function (status, statustext, body) {
            if (status) {
                context.callbackWaitsForEmptyEventLoop = false;
                var param = { StatusText: statustext, Result: body };
                callback(null, param);
            } else {
                context.callbackWaitsForEmptyEventLoop = false;
                var errormsg = "Error getting workitem status";
                if (body) {
                    errormsg = body;
                }
                callback(errormsg, "Error message");
            }
        });
    });
}

// The function takes the location of the result posted by DesignAutomation API
// for the workitem that was submitted. The result which is a compressed file
// containing the output is uncompressed by the function and uploaded to a unique
// location on S3. The location of the SVF/F2D and the XData files are returned.
//
module.exports.processresult = (event, context, callback) => {

    var url = event.output;
    if (!url) {
        console.log("Error: Invalid url");
        callback("Error: Invalid url");
        return;
    }

    var folderName = "files/" + uuid.v4() + "/";

    // The function gets the result output by the Design Automation API,
    // which is a compressed form. It uncompresses the result, uploads
    // the files to a unique location on S3, and returns the location
    // of SVF/F2D files, along with the location of the xdata.
    //
    uploadWorkItemResult(url, folderName, function (status, resultlocation, xdatalocation) {
        if (status) {
            context.callbackWaitsForEmptyEventLoop = false;
            var param = { Result: resultlocation, CustomData: xdatalocation };
            callback(null, param);
        }
        else {
            context.callbackWaitsForEmptyEventLoop = false;
            var errormsg = "Could not process the request";
            if (resultlocation) {
                errormsg = resultlocation;
            }
            callback(errormsg, "Error message");
        }
    });
}


<|start_filename|>src/lambda/config.js<|end_filename|>
module.exports = {
    auth_endpoint: "https://developer.api.autodesk.com/authentication/v1/authenticate",

    package_endpoint: "https://developer.api.autodesk.com/autocad.io/us-east/v2/AppPackages",
    package_upload_endpoint: "https://developer.api.autodesk.com/autocad.io/us-east/v2/AppPackages/Operations.GetUploadUrl()",
    activity_endpoint: "https://developer.api.autodesk.com/autocad.io/us-east/v2/Activities",
    workitem_endpoint: "https://developer.api.autodesk.com/autocad.io/us-east/v2/WorkItems",
    package_name: "MyCustomPackage",

    developer_key: "ADSK_DEVELOPER_KEY",
    developer_secret: "ADSK_DEVELOPER_SECRET",

    aws_key: "AWS_ACCESS_KEY_ID",
    aws_secret: "AWS_SECRET_ACCESS_KEY",
    aws_region: "",
    aws_s3_bucket: "DA_VIEWER_DWG_BUCKET"
}


<|start_filename|>server/package.json<|end_filename|>
{
  "name": "ViewerSampleServer",
  "version": "0.1.0",
  "description": "ViewerSampleServer",
  "main": "setup.js",
  "author": {
    "name": "<NAME>",
    "email": "<EMAIL>"
  },
  "dependencies": {
    "express": ">= 4.12.3"      
  }
}



<|start_filename|>src/RxApp/DBObjectInfo.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace RxApp
{
    [DataContract]
    class DBObjectInfo
    {
        Collection<DataValue> coll = new Collection<DataValue>();
        public DBObjectInfo()
        {

        }

        [DataMember]
        public string Id { get; set; }

        [DataMember]
        public Collection<DataValue> XData
        {
            get
            {
                return coll;
            }
        }
    }

    [DataContract]
    class DataValue
    {
        public DataValue()
        {

        }

        [DataMember]
        public short Type { get; set; }

        [DataMember]
        public string Value { get; set; }
    }
}


<|start_filename|>setup/setup.js<|end_filename|>
"use strict";

var fs = require("fs");
const exec = require("child_process").exec;

var configfile = "..\\src\\lambda\\config.js";
var deployfile = "..\\src\\lambda\\deploy.bat";
var indexfile = "..\\src\\www\\index.html";
var startmarker = "endpoints:";
var endmarker = "functions:";

var variables = ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_DEFAULT_REGION",
        "DA_VIEWER_DWG_BUCKET", "ADSK_DEVELOPER_KEY", "ADSK_DEVELOPER_SECRET"];

// Updates the config file with actual values
//
function updateConfigFile(callback) {

    var file = fs.createReadStream(configfile, "utf8");
    var newdata = "";
    file.on("data", function (data) {
        var updatedata = data;
        variables.forEach(function (val) {
            updatedata = updatedata.toString().replace(val, process.env[val]);
        });

        newdata += updatedata;
    });

    file.on("end", function () {
        fs.writeFile(configfile, newdata, function (err) {
            if (err) {
                console.log(err);
                callback(false);
                return;
            }

            callback(true);
        });
    });
}

// Helper function to execute the batch file
//
function execbatchfile(filename, callback) {

    exec(filename, function (err, stdout) {
        if (err) {
            console.error(err);
            callback(false, null);
            return;
        }

        callback(true, stdout);
    });
}

// Updates the webpage with the AWS API Gateway endpoints
//
function updateUrl(value, callback) {

    var outputtext = value.toString();
    var start = outputtext.indexOf(startmarker) + startmarker.length;
    var end = outputtext.indexOf(endmarker);

    outputtext = outputtext.slice(start, end);
    outputtext = outputtext.trim();

    var endpoints = outputtext.split("\n");
    var uploadurl = endpoints[0].trim();
    var workitemurl = endpoints[1].trim();
    var workitemstatusurl = endpoints[2].trim();
    var processurl = endpoints[3].trim();

    uploadurl = uploadurl.slice(uploadurl.indexOf("-") + 1);
    uploadurl = uploadurl.trim();
    workitemurl = workitemurl.slice(workitemurl.indexOf("-") + 1);
    workitemurl = workitemurl.trim();
    workitemstatusurl = workitemstatusurl.slice(workitemstatusurl.indexOf("-") + 1);
    workitemstatusurl = workitemstatusurl.trim();
    processurl = processurl.slice(processurl.indexOf("-") + 1);
    processurl = processurl.trim();

    if (!uploadurl || !workitemurl || !workitemstatusurl || !processurl) {
        console.log("The endpoints could not be extracted");
        callback(false);
        return;
    }

    var file = fs.createReadStream(indexfile, "utf8");
    var newdata = "";
    file.on("data", function (data) {
        var updatedata = data;
        updatedata = updatedata.toString().replace("UPLOAD_URL", uploadurl);
        updatedata = updatedata.toString().replace("WORKITEM_URL", workitemurl);
        updatedata = updatedata.toString().replace("WORKITEMSTATUS_URL", workitemstatusurl);
        updatedata = updatedata.toString().replace("PROCESS_URL", processurl);

        newdata += updatedata;
    });

    file.on("end", function () {
        fs.writeFile(indexfile, newdata, function (err) {
            if (err) {
                console.log("Error updating index.html");
                console.log(err);
                callback(false);
                return;
            }

            callback(true);
        });
    });
}

var initfunction = function () {
    console.log("Staring installation of the service...");
    var initialized = true;
    variables.forEach(function (val) {
        if (!process.env[val]) {
            console.log(val + " environment variable not set");
            initialized = false;
        }
    });

    if (!initialized) {
        console.log("\n");
        console.log("Please set the value of environment variables in init.bat, and run the batch file");
        return;
    }

    console.log("Update the config file...");
    // Update the config file
    //
    updateConfigFile(function (status) {
        if (!status) {
            return;
        }

        console.log("Deploying the service, this will take sometime");
        // Start the deployment
        //
        execbatchfile(deployfile, function (status, text) {
            if (!status) {
                console.log("Error deploying to AWS");
                return;
            }

            // Update the html file
            //
            var output = text.toString();
            console.log(output);
            console.log("Update the html file...");
            updateUrl(output, function (status) {
                if (status) {
                    console.log("Successfully updated index.html");
                }
            });
        });
    });
    
};

initfunction();


<|start_filename|>setup/setup.bat<|end_filename|>
rem call init.bat
call init.bat
rem call clientApp
..\src\bin\Output\ClientApp.exe

if errorlevel 0 goto success
goto failed
:success
rem install dependencies
call npminstall.bat
rem npm install
cd ..\src\lambda
call npminstall.bat
cd ..\..\server
call npminstall.bat
cd ..\setup

rem deploying...
call node setup.js

rem run server...
cd ..\server
start call node server.js

rem load the test page...
cd ..\setup
start "" http://localhost:8080

goto done

:failed
echo setup failed

:done



<|start_filename|>src/ClientApp/Program.cs<|end_filename|>
﻿using ClientApp.ACES.Models;
using ClientApp.Operations;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ClientApp
{
    class Credentials
    {
        // Get your ConsumerKey/ConsumerSecret from https://developer.autodesk.com
        //
        public static string baseUrl = "https://developer.api.autodesk.com";
    }

    class Program
    {
        static readonly string PackageName = "MyCustomPackage";
        static readonly string zip = "package.zip";
        static readonly string ActivityName2d = "MyPublishActivity2d";
        static readonly string ActivityName3d = "MyPublishActivity3d";
        static readonly string ActivityNameCustom = "MyPublishActivityCustom";
        static readonly string Script2d = "_test ./result/xdata.json\r\n_prepareforpropertyextraction index.json\r\n_indexextractor index.json\r\n_publishtof2d ./output\r\n_createbubblepackage ./output ./result \r\n\n";
        static readonly string Script3d = "_test ./result/xdata.json\r\n_prepareforpropertyextraction index.json\r\n_indexextractor index.json\r\n_publishtosvf ./output/result.svf\r\n_createbubblepackage ./output ./result \r\n\n";
        static readonly string ScriptCustom = "_testpoly\r\n_save \r\n_test ./result/xdata.json\r\n_prepareforpropertyextraction index.json\r\n_indexextractor index.json\r\n_publishtof2d ./output\r\n_createbubblepackage ./output ./result \r\n\n";

        static readonly string RequiredEngineVersion = "22.0";

        static int Main(string[] args)
        {
            var consumerKey = Environment.GetEnvironmentVariable("ADSK_DEVELOPER_KEY");
            var consumerSecret = Environment.GetEnvironmentVariable("ADSK_DEVELOPER_SECRET");

            if (string.IsNullOrEmpty(consumerKey) || string.IsNullOrEmpty(consumerSecret))
            {
                Console.WriteLine("Please enter valid Autodesk consumer key secret");
                return 1;
            }

            var token = GetToken(consumerKey, consumerSecret);
            if (token == null)
            {
                Console.WriteLine("Error obtaining access token");
                return 1;
            }

            string url = Credentials.baseUrl + "/autocad.io/us-east/v2/";
            Container container = new Container(new Uri(url));
            container.SendingRequest2 += (sender, e) => e.RequestMessage.SetHeader("Authorization", token);

            // Create the app package if it does not exist
            AppPackage package = CreatePackage(container);            
            if (package == null)
            {
                Console.WriteLine("Error creating app package");
                return 1;
            }

            // Create the custom activity
            //
            Activity activity = CreateActivity(ActivityName2d, Script2d, container);
            if (activity == null)
            {
                Console.WriteLine("Error creating custom activity: " + ActivityName2d);
                return 1;
            }

            activity = CreateActivity(ActivityName3d, Script3d, container);
            if (activity == null)
            {
                Console.WriteLine("Error creating custom activity: " + ActivityName3d);
                return 1;
            }

            activity = CreateActivity(ActivityNameCustom, ScriptCustom, container);
            if (activity == null)
            {
                Console.WriteLine("Error creating custom activity: " + ActivityNameCustom);
                return 1;
            }

            // Save changes if any
            container.SaveChanges();

            return 0;
        }

        public static string GetToken(string consumerKey, string consumerSecret)
        {
            using (var client = new HttpClient())
            {
                var values = new List<KeyValuePair<string, string>>();
                values.Add(new KeyValuePair<string, string>("client_id", consumerKey));
                values.Add(new KeyValuePair<string, string>("client_secret", consumerSecret));
                values.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
                values.Add(new KeyValuePair<string, string>("scope", "code:all"));
                
                var requestContent = new FormUrlEncodedContent(values);
                string url = Credentials.baseUrl + "/authentication/v1/authenticate";
                var response = client.PostAsync(url, requestContent).Result;
                var responseContent = response.Content.ReadAsStringAsync().Result;
                var resValues = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseContent);
                return resValues["token_type"] + " " + resValues["access_token"];
            }
        }

        static AppPackage CreatePackage(Container container)
        {
            AppPackage package = null;
            try
            {
                package = container.AppPackages.ByKey(PackageName).GetValue();
            }
            catch
            {
            }
            if (package != null)
            {
                string res = null;
                res = Prompts.PromptForKeyword(string.Format("AppPackage '{0}' already exists. What do you want to do? [Recreate/Update/Leave]<Update>", PackageName));
                if (res == "Recreate")
                {
                    container.DeleteObject(package);
                    container.SaveChanges();
                    package = null;
                }
                if (res == "Leave")
                    return package;
            }

            var dir = Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
            if (!File.Exists(Path.Combine(dir, "RxApp.dll")))
            {
                Console.WriteLine("Error building RxApp.dll");
                return null;
            }
            if (!File.Exists(Path.Combine(dir, "asdkmgPoly.dll")))
            {
                Console.WriteLine("Error building asdkmgPoly.dll");
                return null;
            }
            if (!File.Exists(Path.Combine(dir, "asdkpolyobj.dbx")))
            {
                Console.WriteLine("Error building asdkpolyobj.dbx");
                return null;
            }

            string zipfile = CreateZip();
            if (string.IsNullOrEmpty(zipfile))
            {
                Console.WriteLine("Error creating package.zip");
                return null;
            }
            Console.WriteLine("The package.zip file was successfully created");

            Console.WriteLine("Creating/Updating AppPackage...");
            // Query for the url to upload the AppPackage file
            var url = container.AppPackages.GetUploadUrl().GetValue();
            var client = new HttpClient();
            // Upload AppPackage file
            client.PutAsync(url, new StreamContent(File.OpenRead(zip))).Result.EnsureSuccessStatusCode();

            // third step -- after upload, create the AppPackage entity
            if (package == null)
            {
                package = new AppPackage()
                {
                    Id = PackageName,
                    RequiredEngineVersion = RequiredEngineVersion,
                    Resource = url
                };
                container.AddToAppPackages(package);
            }
            else
            {
                package.Resource = url;
                container.UpdateObject(package);
            }

            container.SaveChanges();
            return package;
        }


        static Activity CreateActivity(string activityname, string script, Container container)
        {
            Activity activity = null;
            try { activity = container.Activities.ByKey(activityname).GetValue(); }
            catch { }
            if (activity != null)
            {
                if (Prompts.PromptForKeyword(string.Format("Activity '{0}' already exists. Do you want to recreate it? [Yes/No]<No>", activityname)) == "Yes")
                {
                    container.DeleteObject(activity);
                    container.SaveChanges();
                    activity = null;
                }
                else
                {
                    return activity;
                }
            }

            Console.WriteLine("Creating/Updating Activity...");
            activity = new Activity()
            {
                Id = activityname,
                Instruction = new Instruction()
                {
                    Script = script
                },
                Parameters = new Parameters()
                {
                    InputParameters = {
                        new Parameter() { Name = "HostDwg", LocalFileName = "$(HostDwg)" }
                    },
                    OutputParameters = { new Parameter() { Name = "Results", LocalFileName = "result" } }
                },
                RequiredEngineVersion = RequiredEngineVersion
            };
            activity.AppPackages.Add(PackageName); 
            activity.AppPackages.Add("Publish2View22"); // reference the custom AppPackage
            container.AddToActivities(activity);
            container.SaveChanges();
            return activity;
        }


        static string CreateZip()
        {
            Console.WriteLine("Generating autoloader zip...");
            if (File.Exists(zip))
                File.Delete(zip);
            var dir = Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
            using (var archive = ZipFile.Open(zip, ZipArchiveMode.Create))
            {
                string bundle = PackageName + ".bundle";
                string name = "PackageContents.xml";
                archive.CreateEntryFromFile(Path.Combine(dir,name), Path.Combine(bundle, name));
                name = "RxApp.dll";
                archive.CreateEntryFromFile(Path.Combine(dir, name), Path.Combine(bundle, "Contents", name));
                name = "asdkmgPoly.dll";
                archive.CreateEntryFromFile(Path.Combine(dir, name), Path.Combine(bundle, "Contents", name));
                name = "asdkpolyobj.dbx";
                archive.CreateEntryFromFile(Path.Combine(dir, name), Path.Combine(bundle, "Contents", name));
            }
            return zip;
        }
    }

    class Prompts
    {
        class KeywordPrompt
        {
            string[] m_keywords;
            string m_default;
            static Regex s_reg = new Regex(".*\\[(?<keywords>.*)\\]\\<(?<default>.*)\\>$");
            public KeywordPrompt(string prompt)
            {
                var match = s_reg.Match(prompt);
                if (!match.Success)
                    throw new ArgumentException();
                m_keywords = match.Groups["keywords"].Value.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                m_default = match.Groups["default"].Value;
                string dummy;
                if (string.IsNullOrEmpty(m_default) || !TryMatch(m_default, out dummy))
                    throw new ArgumentException();
            }
            public bool TryMatch(string str, out string match)
            {
                if (string.IsNullOrEmpty(str))
                {
                    match = m_default;
                    return true;
                }
                match = null;
                var matches = m_keywords.Where(s => s.StartsWith(str, StringComparison.CurrentCultureIgnoreCase));
                if (matches.Count() != 1)
                    return false;
                match = matches.First();
                return true;
            }
        }
        public static string PromptForKeyword(string promptString)
        {
            var prompt = new KeywordPrompt(promptString);
            while (true)
            {
                Console.Write("{0}:", promptString);
                var resp = Console.ReadLine();
                string ret;
                if (prompt.TryMatch(resp, out ret))
                    return ret;
            }

        }
    }

}


<|start_filename|>src/lambda/deploy.bat<|end_filename|>
rem call npm install to download all the dependencies
cd
cd ..\src\lambda
node_modules\.bin\serverless deploy


<|start_filename|>server/server.js<|end_filename|>
var express = require('express');

var app = express();
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});


app.use('/', express.static(__dirname + '/../src/www'));
app.set('port', 8080);

var server = app.listen(app.get('port'), function() {
    console.log('Server listening on port ' + server.address().port);
});

