Define Activity
Activity is the specification of an action that can be executed using a specified engine. It specifies the number of input and output files, and the AppBundle and entry-point to use.
In this tutorial sample, the activity has 2 inputs (file & JSON data) and 1 output (file).
- Node.js & VSCode
- .NET 6 & VSCode
- .NET 6 & VS2022
- Activity
Now we will write endpoints for creating new activity and getting the existing activities, copy the following code into DesignAutomation.js
file before the last line module.exports = router;
/// <summary>
/// CreateActivity a new Activity
/// </summary>
router.post(
"/aps/designautomation/activities",
async (/*CreateActivity*/ req, res) => {
const activitySpecs = req.body;
// basic input validation
const zipFileName = activitySpecs.zipFileName;
const engineName = activitySpecs.engine;
// standard name for this sample
const appBundleName = zipFileName + "AppBundle";
const activityName = zipFileName + "Activity";
// get defined activities
const api = await Utils.dav3API(req.oauth_token);
let activities = null;
try {
activities = await api.getActivities();
} catch (ex) {
console.error(ex);
return res.status(500).json({
diagnostic: "Failed to get activity list",
});
}
const qualifiedActivityId = `${Utils.NickName}.${activityName}+${Utils.Alias}`;
if (!activities.data.includes(qualifiedActivityId)) {
// define the activity
// ToDo: parametrize for different engines...
const engineAttributes = Utils.EngineAttributes(engineName);
const commandLine = engineAttributes.commandLine.replace(
"{0}",
appBundleName
);
const activitySpec = {
id: activityName,
appbundles: [`${Utils.NickName}.${appBundleName}+${Utils.Alias}`],
commandLine: [commandLine],
engine: engineName,
parameters: {
inputFile: {
description: "input file",
localName: "$(inputFile)",
ondemand: false,
required: true,
verb: dav3.Verb.get,
zip: false,
},
inputJson: {
description: "input json",
localName: "params.json",
ondemand: false,
required: false,
verb: dav3.Verb.get,
zip: false,
},
outputFile: {
description: "output file",
localName: "outputFile." + engineAttributes.extension,
ondemand: false,
required: true,
verb: dav3.Verb.put,
zip: false,
},
},
settings: {
script: {
value: engineAttributes.script,
},
},
};
try {
const newActivity = await api.createActivity(activitySpec);
} catch (ex) {
console.error(ex);
return res.status(500).json({
diagnostic: "Failed to create new activity",
});
}
// specify the alias for this Activity
const aliasSpec = {
id: Utils.Alias,
version: 1,
};
try {
const newAlias = await api.createActivityAlias(activityName, aliasSpec);
} catch (ex) {
console.error(ex);
return res.status(500).json({
diagnostic: "Failed to create new alias for activity",
});
}
res.status(200).json({
activity: qualifiedActivityId,
});
return;
}
// as this activity points to a AppBundle "dev" alias (which points to the last version of the bundle),
// there is no need to update it (for this sample), but this may be extended for different contexts
res.status(200).json({
activity: "Activity already defined",
});
}
);
/// <summary>
/// Get all Activities defined for this account
/// </summary>
router.get(
"/aps/designautomation/activities",
async (/*GetDefinedActivities*/ req, res) => {
const api = await Utils.dav3API(req.oauth_token);
// filter list of
let activities = null;
try {
activities = await api.getActivities();
} catch (ex) {
console.error(ex);
return res.status(500).json({
diagnostic: "Failed to get activity list",
});
}
let definedActivities = [];
for (let i = 0; i < activities.data.length; i++) {
let activity = activities.data[i];
if (
activity.startsWith(Utils.NickName) &&
activity.indexOf("$LATEST") === -1
)
definedActivities.push(activity.replace(Utils.NickName + ".", ""));
}
res.status(200).json(definedActivities);
}
);
The following methods should be added to the DesignAutomationController
class.
- EngineAttributes
To define the activity we'll need the executable and the default file extension. This helper function provides it (from the engine name).
/// <summary>
/// Helps identify the engine
/// </summary>
private dynamic EngineAttributes(string engine)
{
if (engine.Contains("3dsMax")) return new { commandLine = "$(engine.path)\\3dsmaxbatch.exe -sceneFile \"$(args[inputFile].path)\" $(settings[script].path)", extension = "max", script = "da = dotNetClass(\"Autodesk.Forge.Sample.DesignAutomation.Max.RuntimeExecute\")\nda.ModifyWindowWidthHeight()\n" };
if (engine.Contains("AutoCAD")) return new { commandLine = "$(engine.path)\\accoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\" /s $(settings[script].path)", extension = "dwg", script = "UpdateParam\n" };
if (engine.Contains("Inventor")) return new { commandLine = "$(engine.path)\\inventorcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", extension = "ipt", script = string.Empty };
if (engine.Contains("Revit")) return new { commandLine = "$(engine.path)\\revitcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", extension = "rvt", script = string.Empty };
throw new Exception("Invalid engine");
}
- CreateActivity
Define a new activity with an input file, input data (JSON) and an output file.
/// <summary>
/// Define a new activity
/// </summary>
[HttpPost]
[Route("api/aps/designautomation/activities")]
public async Task<IActionResult> CreateActivity([FromBody]JObject activitySpecs)
{
// basic input validation
string zipFileName = activitySpecs["zipFileName"].Value<string>();
string engineName = activitySpecs["engine"].Value<string>();
// standard name for this sample
string appBundleName = zipFileName + "AppBundle";
string activityName = zipFileName + "Activity";
//
Page<string> activities = await _designAutomation.GetActivitiesAsync();
string qualifiedActivityId = string.Format("{0}.{1}+{2}", NickName, activityName, Alias);
if (!activities.Data.Contains(qualifiedActivityId))
{
// define the activity
// ToDo: parametrize for different engines...
dynamic engineAttributes = EngineAttributes(engineName);
string commandLine = string.Format(engineAttributes.commandLine, appBundleName);
Activity activitySpec = new Activity()
{
Id = activityName,
Appbundles = new List<string>() { string.Format("{0}.{1}+{2}", NickName, appBundleName, Alias) },
CommandLine = new List<string>() { commandLine },
Engine = engineName,
Parameters = new Dictionary<string, Parameter>()
{
{ "inputFile", new Parameter() { Description = "input file", LocalName = "$(inputFile)", Ondemand = false, Required = true, Verb = Verb.Get, Zip = false } },
{ "inputJson", new Parameter() { Description = "input json", LocalName = "params.json", Ondemand = false, Required = false, Verb = Verb.Get, Zip = false } },
{ "outputFile", new Parameter() { Description = "output file", LocalName = "outputFile." + engineAttributes.extension, Ondemand = false, Required = true, Verb = Verb.Put, Zip = false } }
},
Settings = new Dictionary<string, ISetting>()
{
{ "script", new StringSetting(){ Value = engineAttributes.script } }
}
};
Activity newActivity = await _designAutomation.CreateActivityAsync(activitySpec);
// specify the alias for this Activity
Alias aliasSpec = new Alias() { Id = Alias, Version = 1 };
Alias newAlias = await _designAutomation.CreateActivityAliasAsync(activityName, aliasSpec);
return Ok(new { Activity = qualifiedActivityId });
}
// as this activity points to a AppBundle "dev" alias (which points to the last version of the bundle),
// there is no need to update it (for this sample), but this may be extended for different contexts
return Ok(new { Activity = "Activity already defined" });
}
- GetDefinedActivities
We'll also need a method to return all defined activities. Note that returns only those defined by you (we use the APS Client Id as nick name, which then appears as a prefix).
/// <summary>
/// Get all Activities defined for this account
/// </summary>
[HttpGet]
[Route("api/aps/designautomation/activities")]
public async Task<List<string>> GetDefinedActivities()
{
// filter list of
Page<string> activities = await _designAutomation.GetActivitiesAsync();
List<string> definedActivities = new List<string>();
foreach (string activity in activities.Data)
if (activity.StartsWith(NickName) && activity.IndexOf("$LATEST") == -1)
definedActivities.Add(activity.Replace(NickName + ".", String.Empty));
return definedActivities;
}
The following methods should be added to the DesignAutomationController
class.
- EngineAttributes
To define the activity we'll need the executable and the default file extension. This helper function provides it (from the engine name).
/// <summary>
/// Helps identify the engine
/// </summary>
private dynamic EngineAttributes(string engine)
{
if (engine.Contains("3dsMax")) return new { commandLine = "$(engine.path)\\3dsmaxbatch.exe -sceneFile \"$(args[inputFile].path)\" $(settings[script].path)", extension = "max", script = "da = dotNetClass(\"Autodesk.Forge.Sample.DesignAutomation.Max.RuntimeExecute\")\nda.ModifyWindowWidthHeight()\n" };
if (engine.Contains("AutoCAD")) return new { commandLine = "$(engine.path)\\accoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\" /s $(settings[script].path)", extension = "dwg", script = "UpdateParam\n" };
if (engine.Contains("Inventor")) return new { commandLine = "$(engine.path)\\inventorcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", extension = "ipt", script = string.Empty };
if (engine.Contains("Revit")) return new { commandLine = "$(engine.path)\\revitcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", extension = "rvt", script = string.Empty };
throw new Exception("Invalid engine");
}
- CreateActivity
Define a new activity with an input file, input data (JSON) and an output file.
/// <summary>
/// Define a new activity
/// </summary>
[HttpPost]
[Route("api/aps/designautomation/activities")]
public async Task<IActionResult> CreateActivity([FromBody]JObject activitySpecs)
{
// basic input validation
string zipFileName = activitySpecs["zipFileName"].Value<string>();
string engineName = activitySpecs["engine"].Value<string>();
// standard name for this sample
string appBundleName = zipFileName + "AppBundle";
string activityName = zipFileName + "Activity";
//
Page<string> activities = await _designAutomation.GetActivitiesAsync();
string qualifiedActivityId = string.Format("{0}.{1}+{2}", NickName, activityName, Alias);
if (!activities.Data.Contains(qualifiedActivityId))
{
// define the activity
// ToDo: parametrize for different engines...
dynamic engineAttributes = EngineAttributes(engineName);
string commandLine = string.Format(engineAttributes.commandLine, appBundleName);
Activity activitySpec = new Activity()
{
Id = activityName,
Appbundles = new List<string>() { string.Format("{0}.{1}+{2}", NickName, appBundleName, Alias) },
CommandLine = new List<string>() { commandLine },
Engine = engineName,
Parameters = new Dictionary<string, Parameter>()
{
{ "inputFile", new Parameter() { Description = "input file", LocalName = "$(inputFile)", Ondemand = false, Required = true, Verb = Verb.Get, Zip = false } },
{ "inputJson", new Parameter() { Description = "input json", LocalName = "params.json", Ondemand = false, Required = false, Verb = Verb.Get, Zip = false } },
{ "outputFile", new Parameter() { Description = "output file", LocalName = "outputFile." + engineAttributes.extension, Ondemand = false, Required = true, Verb = Verb.Put, Zip = false } }
},
Settings = new Dictionary<string, ISetting>()
{
{ "script", new StringSetting(){ Value = engineAttributes.script } }
}
};
Activity newActivity = await _designAutomation.CreateActivityAsync(activitySpec);
// specify the alias for this Activity
Alias aliasSpec = new Alias() { Id = Alias, Version = 1 };
Alias newAlias = await _designAutomation.CreateActivityAliasAsync(activityName, aliasSpec);
return Ok(new { Activity = qualifiedActivityId });
}
// as this activity points to a AppBundle "dev" alias (which points to the last version of the bundle),
// there is no need to update it (for this sample), but this may be extended for different contexts
return Ok(new { Activity = "Activity already defined" });
}
- GetDefinedActivities
We'll also need a method to return all defined activities. Note that returns only those defined by you (we use the APS Client Id as nick name, which then appears as a prefix).
/// <summary>
/// Get all Activities defined for this account
/// </summary>
[HttpGet]
[Route("api/aps/designautomation/activities")]
public async Task<List<string>> GetDefinedActivities()
{
// filter list of
Page<string> activities = await _designAutomation.GetActivitiesAsync();
List<string> definedActivities = new List<string>();
foreach (string activity in activities.Data)
if (activity.StartsWith(NickName) && activity.IndexOf("$LATEST") == -1)
definedActivities.Add(activity.Replace(NickName + ".", String.Empty));
return definedActivities;
}
Now you can click on Configure (top-right), select the AppBundle, select the Engine and click on Define Activity, which should define and upload the appbundle and define the activity. The results panel (left-side) shows the respective ids. All other buttons do not work yet... let's move forward.