Projektdateien hinzufügen.
This commit is contained in:
19
MachinePlannerExport/Interaction/Interaction.csproj
Normal file
19
MachinePlannerExport/Interaction/Interaction.csproj
Normal file
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autodesk.Forge.DesignAutomation" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
118
MachinePlannerExport/Interaction/Program.cs
Normal file
118
MachinePlannerExport/Interaction/Program.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Autodesk.Forge.Core;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Interaction
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private struct Command
|
||||
{
|
||||
public string Description;
|
||||
public Func<Publisher, Task> Action;
|
||||
}
|
||||
|
||||
private static readonly Command[] commands = new Command[]
|
||||
{
|
||||
new Command { Description = "Post app bundle", Action = (publisher) => publisher.PostAppBundleAsync() },
|
||||
new Command { Description = "Post activity", Action = (publisher) => publisher.PublishActivityAsync() },
|
||||
new Command { Description = "Run work item", Action = (publisher) => publisher.RunWorkItemAsync() },
|
||||
new Command { Description = "List available engines", Action = (publisher) => publisher.ListEnginesAsync() },
|
||||
new Command { Description = "Clean existing app bundle and activity", Action = (publisher) => publisher.CleanExistingAppActivityAsync() },
|
||||
};
|
||||
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
// TODO: ensure you've set credentials in `appsettings.json`
|
||||
|
||||
bool useCommandLine = (args.Length == 1);
|
||||
try
|
||||
{
|
||||
Publisher publisher = CreatePublisher();
|
||||
|
||||
if (useCommandLine)
|
||||
{
|
||||
await RunCommand(publisher, args[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
await RunLoop(publisher);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
|
||||
if (useCommandLine || Debugger.IsAttached)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Press any key to close console...");
|
||||
Console.ReadKey();
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RunLoop(Publisher publisher)
|
||||
{
|
||||
PrintHelp();
|
||||
while (true)
|
||||
{
|
||||
Console.Write("> ");
|
||||
// wait for pressed key
|
||||
ConsoleKeyInfo key = Console.ReadKey();
|
||||
if (key.Key == ConsoleKey.Q) break;
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
if (key.Key == ConsoleKey.H) { PrintHelp(); continue; }
|
||||
if (key.Key == ConsoleKey.C) { Console.Clear(); continue; }
|
||||
|
||||
await RunCommand(publisher, key.KeyChar.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RunCommand(Publisher publisher, string commandIndex)
|
||||
{
|
||||
// try to convert the key to index of available actions
|
||||
if (int.TryParse(commandIndex, out var index) &&
|
||||
(index >= 0 && index < commands.Length))
|
||||
{
|
||||
Command command = commands[index];
|
||||
Console.WriteLine($"Running '{command.Description}'");
|
||||
await command.Action(publisher);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Unknown command");
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintHelp()
|
||||
{
|
||||
Console.WriteLine("Design Automation interaction console");
|
||||
Console.WriteLine("Available actions:");
|
||||
for (int i = 0; i < commands.Length; i++)
|
||||
{
|
||||
Console.WriteLine($" {i} - {commands[i].Description}");
|
||||
}
|
||||
Console.WriteLine(" H - Help");
|
||||
Console.WriteLine(" C - Clear console");
|
||||
Console.WriteLine(" Q - Quit");
|
||||
}
|
||||
|
||||
private static Publisher CreatePublisher()
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("appsettings.json", false)
|
||||
.AddEnvironmentVariables()
|
||||
.AddForgeAlternativeEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
return new Publisher(configuration);
|
||||
}
|
||||
}
|
||||
}
|
121
MachinePlannerExport/Interaction/Publisher.Custom.cs
Normal file
121
MachinePlannerExport/Interaction/Publisher.Custom.cs
Normal file
@ -0,0 +1,121 @@
|
||||
using System.Collections.Generic;
|
||||
using Autodesk.Forge.DesignAutomation.Model;
|
||||
|
||||
namespace Interaction
|
||||
{
|
||||
/// <summary>
|
||||
/// Customizable part of Publisher class.
|
||||
/// </summary>
|
||||
internal partial class Publisher
|
||||
{
|
||||
/// <summary>
|
||||
/// Constants.
|
||||
/// </summary>
|
||||
private static class Constants
|
||||
{
|
||||
// Constants containing the name of the specific Inventor engines. Please note
|
||||
// that potentially not all engines are listed - new egines may have been added meanwhile.
|
||||
// Please use the interaction tools function - list all engines in order to find name of engine that is not listed here
|
||||
private const string InventorEngine2021 = "Autodesk.Inventor+2021"; // Inventor 2021
|
||||
private const string InventorEngine2022 = "Autodesk.Inventor+2022"; // Inventor 2022
|
||||
private const string InventorEngine2023 = "Autodesk.Inventor+2023"; // Inventor 2023
|
||||
private const string InventorEngine2024 = "Autodesk.Inventor+2024"; // Inventor 2024
|
||||
private const string InventorEngine2025 = "Autodesk.Inventor+2025"; // Inventor 2025
|
||||
|
||||
public static readonly string Engine = InventorEngine2025;
|
||||
|
||||
public const string Description = "PUT DESCRIPTION HERE";
|
||||
|
||||
internal static class Bundle
|
||||
{
|
||||
public static readonly string Id = "MachinePlannerExport";
|
||||
public const string Label = "alpha";
|
||||
|
||||
public static readonly AppBundle Definition = new AppBundle
|
||||
{
|
||||
Engine = Engine,
|
||||
Id = Id,
|
||||
Description = Description
|
||||
};
|
||||
}
|
||||
|
||||
internal static class Activity
|
||||
{
|
||||
public static readonly string Id = Bundle.Id;
|
||||
public const string Label = Bundle.Label;
|
||||
}
|
||||
|
||||
internal static class Parameters
|
||||
{
|
||||
public const string InventorDoc = nameof(InventorDoc);
|
||||
public const string OutputIpt = nameof(OutputIpt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get command line for activity.
|
||||
/// </summary>
|
||||
private static List<string> GetActivityCommandLine()
|
||||
{
|
||||
return new List<string> { $"$(engine.path)\\InventorCoreConsole.exe /al \"$(appbundles[{Constants.Activity.Id}].path)\" /i \"$(args[{Constants.Parameters.InventorDoc}].path)\"" };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get activity parameters.
|
||||
/// </summary>
|
||||
private static Dictionary<string, Parameter> GetActivityParams()
|
||||
{
|
||||
return new Dictionary<string, Parameter>
|
||||
{
|
||||
{
|
||||
Constants.Parameters.InventorDoc,
|
||||
new Parameter
|
||||
{
|
||||
Verb = Verb.Get,
|
||||
Description = "IPT file to process"
|
||||
}
|
||||
},
|
||||
{
|
||||
Constants.Parameters.OutputIpt,
|
||||
new Parameter
|
||||
{
|
||||
Verb = Verb.Put,
|
||||
LocalName = "result.ipt",
|
||||
Description = "Resulting IPT",
|
||||
Ondemand = false,
|
||||
Required = false
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get arguments for workitem.
|
||||
/// </summary>
|
||||
private static Dictionary<string, IArgument> GetWorkItemArgs()
|
||||
{
|
||||
// TODO: update the URLs below with real values
|
||||
return new Dictionary<string, IArgument>
|
||||
{
|
||||
{
|
||||
Constants.Parameters.InventorDoc,
|
||||
new XrefTreeArgument
|
||||
{
|
||||
LocalName = "document.ipt",
|
||||
Url = "!!! CHANGE ME !!!"
|
||||
}
|
||||
},
|
||||
{
|
||||
Constants.Parameters.OutputIpt,
|
||||
new XrefTreeArgument
|
||||
{
|
||||
LocalName = "document.ipt",
|
||||
Verb = Verb.Put,
|
||||
Url = "!!! CHANGE ME !!!"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
216
MachinePlannerExport/Interaction/Publisher.cs
Normal file
216
MachinePlannerExport/Interaction/Publisher.cs
Normal file
@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Autodesk.Forge.Core;
|
||||
using Autodesk.Forge.DesignAutomation;
|
||||
using Autodesk.Forge.DesignAutomation.Model;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Interaction
|
||||
{
|
||||
internal partial class Publisher
|
||||
{
|
||||
private string _nickname;
|
||||
|
||||
internal DesignAutomationClient Client { get; }
|
||||
private static string PackagePathname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
public Publisher(IConfiguration configuration)
|
||||
{
|
||||
Client = CreateDesignAutomationClient(configuration);
|
||||
PackagePathname = configuration.GetValue<string>("PackagePathname");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List available engines.
|
||||
/// </summary>
|
||||
public async Task ListEnginesAsync()
|
||||
{
|
||||
string page = null;
|
||||
do
|
||||
{
|
||||
using (var response = await Client.EnginesApi.GetEnginesAsync(page))
|
||||
{
|
||||
if (!response.HttpResponse.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine("Request failed");
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var engine in response.Content.Data)
|
||||
{
|
||||
Console.WriteLine(engine);
|
||||
}
|
||||
|
||||
page = response.Content.PaginationToken;
|
||||
}
|
||||
} while (page != null);
|
||||
}
|
||||
|
||||
public async Task PostAppBundleAsync()
|
||||
{
|
||||
if (!File.Exists(PackagePathname))
|
||||
throw new Exception("App Bundle with package is not found. Ensure it set correctly in appsettings.json");
|
||||
|
||||
var shortAppBundleId = $"{Constants.Bundle.Id}+{Constants.Bundle.Label}";
|
||||
Console.WriteLine($"Posting app bundle '{shortAppBundleId}'.");
|
||||
|
||||
// try to get already existing bundle
|
||||
var response = await Client.AppBundlesApi.GetAppBundleAsync(shortAppBundleId, throwOnError: false);
|
||||
if (response.HttpResponse.StatusCode == HttpStatusCode.NotFound) // create new bundle
|
||||
{
|
||||
await Client.CreateAppBundleAsync(Constants.Bundle.Definition, Constants.Bundle.Label, PackagePathname);
|
||||
Console.WriteLine("Created new app bundle.");
|
||||
}
|
||||
else // create new bundle version
|
||||
{
|
||||
var version = await Client.UpdateAppBundleAsync(Constants.Bundle.Definition, Constants.Bundle.Label, PackagePathname);
|
||||
Console.WriteLine($"Created version #{version} for '{shortAppBundleId}' app bundle.");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RunWorkItemAsync()
|
||||
{
|
||||
// create work item
|
||||
var wi = new WorkItem
|
||||
{
|
||||
ActivityId = await GetFullActivityId(),
|
||||
Arguments = GetWorkItemArgs()
|
||||
};
|
||||
|
||||
// run WI and wait for completion
|
||||
var status = await Client.CreateWorkItemAsync(wi);
|
||||
Console.WriteLine($"Created WI {status.Id}");
|
||||
while (status.Status == Status.Pending || status.Status == Status.Inprogress)
|
||||
{
|
||||
Console.Write(".");
|
||||
Thread.Sleep(2000);
|
||||
status = await Client.GetWorkitemStatusAsync(status.Id);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"WI {status.Id} completed with {status.Status}");
|
||||
Console.WriteLine();
|
||||
|
||||
// dump report
|
||||
var client = new HttpClient();
|
||||
var report = await client.GetStringAsync(status.ReportUrl);
|
||||
var oldColor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||
Console.Write(report);
|
||||
Console.ForegroundColor = oldColor;
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private async Task<string> GetFullActivityId()
|
||||
{
|
||||
string nickname = await GetNicknameAsync();
|
||||
return $"{nickname}.{Constants.Activity.Id}+{Constants.Activity.Label}";
|
||||
}
|
||||
|
||||
public async Task<string> GetNicknameAsync()
|
||||
{
|
||||
if (_nickname == null)
|
||||
{
|
||||
_nickname = await Client.GetNicknameAsync("me");
|
||||
}
|
||||
|
||||
return _nickname;
|
||||
}
|
||||
|
||||
public async Task PublishActivityAsync()
|
||||
{
|
||||
var nickname = await GetNicknameAsync();
|
||||
|
||||
// prepare activity definition
|
||||
var activity = new Activity
|
||||
{
|
||||
Appbundles = new List<string> { $"{nickname}.{Constants.Bundle.Id}+{Constants.Bundle.Label}" },
|
||||
Id = Constants.Activity.Id,
|
||||
Engine = Constants.Engine,
|
||||
Description = Constants.Description,
|
||||
CommandLine = GetActivityCommandLine(),
|
||||
Parameters = GetActivityParams()
|
||||
};
|
||||
|
||||
// check if the activity exists already
|
||||
var response = await Client.ActivitiesApi.GetActivityAsync(await GetFullActivityId(), throwOnError: false);
|
||||
if (response.HttpResponse.StatusCode == HttpStatusCode.NotFound) // create activity
|
||||
{
|
||||
Console.WriteLine($"Creating activity '{Constants.Activity.Id}'");
|
||||
await Client.CreateActivityAsync(activity, Constants.Activity.Label);
|
||||
Console.WriteLine("Done");
|
||||
}
|
||||
else // add new activity version
|
||||
{
|
||||
Console.WriteLine("Found existing activity. Updating...");
|
||||
int version = await Client.UpdateActivityAsync(activity, Constants.Activity.Label);
|
||||
Console.WriteLine($"Created version #{version} for '{Constants.Activity.Id}' activity.");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CleanExistingAppActivityAsync()
|
||||
{
|
||||
var bundleId = Constants.Bundle.Id;
|
||||
var activityId = Constants.Activity.Id;
|
||||
var shortAppBundleId = $"{bundleId}+{Constants.Bundle.Label}";
|
||||
|
||||
|
||||
//check app bundle exists already
|
||||
var appResponse = await Client.AppBundlesApi.GetAppBundleAsync(shortAppBundleId, throwOnError: false);
|
||||
if (appResponse.HttpResponse.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
//remove exsited app bundle
|
||||
Console.WriteLine($"Removing existing app bundle. Deleting {bundleId}...");
|
||||
await Client.AppBundlesApi.DeleteAppBundleAsync(bundleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"The app bundle {bundleId} does not exist.");
|
||||
}
|
||||
|
||||
//check activity exists already
|
||||
var activityResponse = await Client.ActivitiesApi.GetActivityAsync(await GetFullActivityId(), throwOnError: false);
|
||||
if (activityResponse.HttpResponse.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
//remove exsited activity
|
||||
Console.WriteLine($"Removing existing activity. Deleting {activityId}...");
|
||||
await Client.ActivitiesApi.DeleteActivityAsync(activityId);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"The activity {activityId} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static DesignAutomationClient CreateDesignAutomationClient(IConfiguration configuration)
|
||||
{
|
||||
var forgeService = CreateForgeService(configuration);
|
||||
|
||||
var rsdkCfg = configuration.GetSection("DesignAutomation").Get<Configuration>();
|
||||
var options = (rsdkCfg == null) ? null : Options.Create(rsdkCfg);
|
||||
return new DesignAutomationClient(forgeService, options);
|
||||
}
|
||||
|
||||
private static ForgeService CreateForgeService(IConfiguration configuration)
|
||||
{
|
||||
var forgeCfg = configuration.GetSection("Forge").Get<ForgeConfiguration>();
|
||||
var httpMessageHandler = new ForgeHandler(Options.Create(forgeCfg))
|
||||
{
|
||||
InnerHandler = new HttpClientHandler()
|
||||
};
|
||||
|
||||
return new ForgeService(new HttpClient(httpMessageHandler));
|
||||
}
|
||||
}
|
||||
}
|
7
MachinePlannerExport/Interaction/appsettings.json
Normal file
7
MachinePlannerExport/Interaction/appsettings.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"Forge": {
|
||||
"ClientId": "!!! CHANGE ME !!!",
|
||||
"ClientSecret": "!!! CHANGE ME !!!"
|
||||
},
|
||||
"PackagePathname": "..\\..\\..\\..\\Output\\MachinePlannerExportPlugin.bundle.zip"
|
||||
}
|
32
MachinePlannerExport/Interaction/readme.md
Normal file
32
MachinePlannerExport/Interaction/readme.md
Normal file
@ -0,0 +1,32 @@
|
||||
# Overview
|
||||
|
||||
This is a sample project, which allows to post app bundle, activity and work item to Design Automation services by using [.NET SDK](https://github.com/Autodesk-Forge/forge-api-dotnet-design.automation).
|
||||
|
||||
# Steps for test run
|
||||
1. Build the whole solution.
|
||||
1. (if necessary) Make `Interaction` as active project. Expand it.
|
||||
1. Set Forge credentials
|
||||
* Use environment variables
|
||||
```
|
||||
FORGE_CLIENT_ID=<your client id>
|
||||
FORGE_CLIENT_SECRET=<your client secret>
|
||||
```
|
||||
or
|
||||
```
|
||||
Forge__ClientId=<your client id>
|
||||
Forge__ClientSecret=<your client secret>
|
||||
```
|
||||
* _(not recommended)_ Open `appsettings.json` and update `ClientId` and `ClientSecret` with real values.
|
||||
1. Open `Publisher.Custom.cs` and supply URLs in `GetWorkItemArgs()` method.
|
||||
|
||||
# Custom adjustments
|
||||
|
||||
The template project contains placeholders or default data for app bundle and activity. So update constants in `Publisher.Custom.cs` with your project-specific data.
|
||||
|
||||
# Usage
|
||||
|
||||
The console app can be used in two modes.
|
||||
## Interaction
|
||||
Launch the console and follow the instructions. Basically - each DA interaction command will have unique number, just press the required one. Command any number of commands one by one.
|
||||
## Run selected command
|
||||
Put number of the wanted command in command line and the console will executed it on start and exist right away. Useful if some repetetive task (like post work item) should be run frequently.
|
Reference in New Issue
Block a user