public static async Task ProcessFileAsync(string userId, string hubId, string projectId, string folderUrn, string itemUrn, string versionUrn, string fileName, PerformContext console) { Credentials credentials = await Credentials.FromDatabaseAsync(userId); // start the translation DerivativesApi derivative = new DerivativesApi(); derivative.Configuration.AccessToken = credentials.TokenInternal; dynamic document = new JObject(); document.hubId = hubId.Replace("-", string.Empty); // this is breaking the search... document.projectId = projectId; document.folderUrn = folderUrn; document.itemUrn = itemUrn; document.versionUrn = versionUrn; document.fileName = fileName; document.metadata = new JArray(); string versionUrn64 = Base64Encode(versionUrn); dynamic manifest = await derivative.GetManifestAsync(versionUrn64); if (manifest.status == "inprogress") { throw new Exception("Translating..."); // force run it again } List <ManifestItem> manifestItems = ParseManifest(manifest.derivatives); List <Resource> resouces = new List <Resource>(); foreach (ManifestItem item in manifestItems) { if (item.MIME != "application/autodesk-db") { continue; } string file = "objects_vals.json.gz"; // the only file we need here Uri myUri = new Uri(new Uri(item.Path.BasePath), file); resouces.Add(new Resource() { FileName = file, RemotePath = "derivativeservice/v2/derivatives/" + Uri.UnescapeDataString(myUri.AbsoluteUri), LocalPath = Path.Combine(item.Path.LocalPath, file) }); } // this approach uses the Viewer propertyDatabase, which is a non-supported way of accessing the model metadata // it will return the non-duplicated list of attributes values (not the attribute type) // as we don't want to manipulate it, just search, it doesn't matter if this list changes its format IRestClient forgeClient = new RestClient("https://developer.api.autodesk.com/"); if (resouces.Count != 1 && fileName.ToLower().IndexOf("pdf") == -1) { throw new Exception(resouces.Count + " objects_vals.json.gz found, will try again"); } if (fileName.ToLower().IndexOf("pdf") != -1) { } else { RestRequest forgeRequest = new RestRequest(resouces[0].RemotePath, Method.GET); forgeRequest.AddHeader("Authorization", "Bearer " + credentials.TokenInternal); forgeRequest.AddHeader("Accept-Encoding", "gzip, deflate"); IRestResponse response = await forgeClient.ExecuteTaskAsync(forgeRequest); if (response.StatusCode != System.Net.HttpStatusCode.OK) { console.WriteLine(string.Format("Cannot download attributes ({0}), will retry", response.StatusCode)); throw new Exception(string.Format("Cannot download attributes: {0}", response.StatusCode)); } using (GZipStream gzip = new GZipStream(new MemoryStream(response.RawBytes), CompressionMode.Decompress)) using (var fileStream = new StreamReader(gzip)) { dynamic viewProperties = new JObject(); viewProperties.viewId = "viewer"; viewProperties.collection = System.Text.RegularExpressions.Regex.Replace(fileStream.ReadToEnd(), @"\n", string.Empty); document.metadata.Add(viewProperties); } // as an alternative solution, using supported APIs, one could get the complete metadata JSON // but that results in more data that we don't need for search, like attribute names /*{ * dynamic metadata = await derivative.GetMetadataAsync(versionUrn64); * foreach (KeyValuePair<string, dynamic> metadataItem in new DynamicDictionaryItems(metadata.data.metadata)) * { * dynamic properties = await derivative.GetModelviewPropertiesAsync(versionUrn64, metadataItem.Value.guid); * if (properties == null) * { * console.WriteLine("Model not ready, will retry"); * throw new Exception("Model not ready..."); * } * console.WriteLine(string.Format("View: {0}", (string)metadataItem.Value.guid)); * JArray collection = JObject.Parse(properties.ToString()).data.collection; * * if (collection.Count > 0) * { * dynamic viewProperties = new JObject(); * viewProperties.viewId = (string)metadataItem.Value.guid; * viewProperties.collection = collection.ToString(Newtonsoft.Json.Formatting.None); * document.metadata.Add(viewProperties); * } * } * }*/ } string json = (string)document.ToString(Newtonsoft.Json.Formatting.None); string absolutePath = string.Format("/manifest/_doc/{0}", Base64Encode(itemUrn)); RestClient elasticSearchclient = new RestClient(Config.ElasticSearchServer); RestRequest elasticSearchRequest = new RestRequest(absolutePath, RestSharp.Method.POST); elasticSearchRequest.AddHeader("Content-Type", "application/json"); elasticSearchRequest.AddParameter("text/json", json, ParameterType.RequestBody); if (!string.IsNullOrEmpty(Config.AWSKey) && !string.IsNullOrEmpty(Config.AWSSecret)) { SortedDictionary <string, string> headers = AWS.Signature.SignatureHeader( Amazon.RegionEndpoint.GetBySystemName(Config.AWSRegion), new Uri(Config.ElasticSearchServer).Host, "POST", json, absolutePath); foreach (var entry in headers) { elasticSearchRequest.AddHeader(entry.Key, entry.Value); } } IRestResponse res = await elasticSearchclient.ExecuteTaskAsync(elasticSearchRequest); console.WriteLine(string.Format("Submit to elasticsearch status: {0}", res.StatusCode.ToString())); }
[Route("api/forge/clientid")] // see Web.Config FORGE_CALLBACK_URL variable public dynamic GetClientID() { return(new { id = Credentials.GetAppSetting("FORGE_CLIENT_ID") }); }
public async Task <IActionResult> StartWorkitem([FromForm] StartWorkitemInput input) { Credentials = await Credentials.FromSessionAsync(base.Request.Cookies, Response.Cookies); if (Credentials == null) { return(null); } // basic input validation JObject workItemData = JObject.Parse(input.data); string inputRvtFileName = workItemData["inputRvtFileName"].Value <string>(); string inputRvtFileUrl = workItemData["inputRvtFileUrl"].Value <string>(); string inputFamilyFileName = workItemData["inputFamilyFileName"].Value <string>(); string inputFamilyFileUrl = workItemData["inputFamilyFileUrl"].Value <string>(); string outputFolderUrl = workItemData["outputFolderUrl"].Value <string>(); string roomUniquId = workItemData["roomUniquId"].Value <string>(); string gridTypeId = workItemData["gridTypeId"].Value <string>(); string distanceXMinParam = workItemData["distanceXMinParam"].Value <string>(); string distanceXMaxParam = workItemData["distanceXMaxParam"].Value <string>(); string distanceYMinParam = workItemData["distanceYMinParam"].Value <string>(); string distanceYMaxParam = workItemData["distanceYMaxParam"].Value <string>(); string distanceWallMinParam = workItemData["distanceWallMinParam"].Value <string>(); string distanceWallMaxParam = workItemData["distanceWallMaxParam"].Value <string>(); string browerConnectionId = workItemData["browerConnectionId"].Value <string>(); string activityName = string.Format("{0}.{1}", NickName, workItemData["activityName"].Value <string>()); // OAuth token dynamic da4rToken = Credentials.DA4RTokenInternal; dynamic userToken = Credentials.TokenInternal; VersionsApi versionApi = new VersionsApi(); versionApi.Configuration.AccessToken = Credentials.TokenInternal; // Revit file download URL string[] revitFileParams = inputRvtFileUrl.Split('/'); string revitFileProjectIdParam = revitFileParams[1]; string revitFileVersionIdParam = revitFileParams[2]; dynamic revitFileVersion = await versionApi.GetVersionAsync(revitFileProjectIdParam, revitFileVersionIdParam); string[] revitFileVersionStorageParams = ((string)revitFileVersion.data.relationships.storage.data.id).Split('/'); string[] revitFileBucketKeyParams = revitFileVersionStorageParams[revitFileVersionStorageParams.Length - 2].Split(':'); string revitFileBucketKey = revitFileBucketKeyParams[revitFileBucketKeyParams.Length - 1]; string revitFileObjectName = revitFileVersionStorageParams[revitFileVersionStorageParams.Length - 1]; string revitFileDownloadUrl = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", revitFileBucketKey, revitFileObjectName); // Family file download URL string[] familyFileParams = inputFamilyFileUrl.Split('/'); string familyFileProjectIdParam = familyFileParams[1]; string familyFileVersionIdParam = familyFileParams[2]; dynamic familyFileVersion = await versionApi.GetVersionAsync(familyFileProjectIdParam, familyFileVersionIdParam); string[] familyFileVersionStorageParams = ((string)familyFileVersion.data.relationships.storage.data.id).Split('/'); string[] familyFileBucketKeyParams = familyFileVersionStorageParams[familyFileVersionStorageParams.Length - 2].Split(':'); string familyFileBucketKey = familyFileBucketKeyParams[familyFileBucketKeyParams.Length - 1]; string familyFileObjectName = familyFileVersionStorageParams[familyFileVersionStorageParams.Length - 1]; string familyFileDownloadUrl = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", familyFileBucketKey, familyFileObjectName); // prepare workitem arguments // 1. input file XrefTreeArgument inputRevitFileArgument = new XrefTreeArgument() { Url = string.Format(revitFileDownloadUrl), Verb = Verb.Get, Headers = new Dictionary <string, string>() { { "Authorization", "Bearer " + userToken } } }; XrefTreeArgument inputFamilyFileArgument = new XrefTreeArgument() { Url = string.Format(familyFileDownloadUrl), Verb = Verb.Get, Headers = new Dictionary <string, string>() { { "Authorization", "Bearer " + userToken } } }; // 2. input json dynamic inputJson = new JObject(); inputJson.RoomUniqueId = roomUniquId; inputJson.GridTypeId = gridTypeId; inputJson.FamilyFileName = inputFamilyFileName; inputJson.OutputZipFileName = "exportedDwgs"; inputJson.DistanceXMinParam = distanceXMinParam; inputJson.DistanceXMaxParam = distanceXMaxParam; inputJson.DistanceYMinParam = distanceYMinParam; inputJson.DistanceYMaxParam = distanceYMaxParam; inputJson.DistanceWallMinParam = distanceWallMinParam; inputJson.DistanceWallMaxParam = distanceWallMaxParam; XrefTreeArgument inputJsonArgument = new XrefTreeArgument() { Url = "data:application/json, " + ((JObject)inputJson).ToString(Formatting.None).Replace("\"", "'") }; // 3. output file string[] folderParams = outputFolderUrl.Split('/'); string outputFolderId = folderParams[folderParams.Length - 1]; string outputProjectId = folderParams[folderParams.Length - 3]; dynamic storageCreatedZip = await this.CreateStorage(outputFolderId, outputProjectId, "exportedDwgs" + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".zip"); string[] zipFileStorageIdParams = ((string)storageCreatedZip.data.id).Split('/'); string[] zipFileBucketKeyParams = zipFileStorageIdParams[zipFileStorageIdParams.Length - 2].Split(':'); string zipFileBucketKey = zipFileBucketKeyParams[zipFileBucketKeyParams.Length - 1]; string zipFileObjectName = zipFileStorageIdParams[zipFileStorageIdParams.Length - 1]; string uploadZipFileUrl = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", zipFileBucketKey, zipFileObjectName); XrefTreeArgument outputZipFileArgument = new XrefTreeArgument() { Url = uploadZipFileUrl, Verb = Verb.Put, Headers = new Dictionary <string, string>() { { "Authorization", "Bearer " + userToken } } }; // prepare & submit workitem string callbackUrl = string.Format("{0}/api/forge/callback/designautomation/grid_object_placement?id={1}&zipFileName={2}&zipFileBucketKey={3}&zipFileObjectName={4}&zipStorageId={5}&projectId={6}&folderId={7}", Credentials.GetAppSetting("FORGE_WEBHOOK_URL"), browerConnectionId, "exportedDwgs.zip", zipFileBucketKey, zipFileObjectName, (string)storageCreatedZip.data.id, outputProjectId, outputFolderId); WorkItem workItemSpec = new WorkItem() { ActivityId = activityName, Arguments = new Dictionary <string, IArgument>() { { "inputRvtFile", inputRevitFileArgument }, { "inputFamilyFile", inputFamilyFileArgument }, { "inputJsonFile", inputJsonArgument }, { "resultZipFile", outputZipFileArgument }, { "onComplete", new XrefTreeArgument { Verb = Verb.Post, Url = callbackUrl } } } }; WorkItemStatus workItemStatus = null; try { workItemStatus = await _designAutomation.CreateWorkItemAsync(workItemSpec); } catch (Exception e) { string message = e.Message; } return(Ok(new { WorkItemId = workItemStatus.Id })); }
public async Task <dynamic> UploadObject([FromForm] UploadFile input) { // get the uploaded file and save on the server var fileSavePath = Path.Combine(_env.ContentRootPath, input.fileToUpload.FileName); using (var stream = new FileStream(fileSavePath, FileMode.Create)) await input.fileToUpload.CopyToAsync(stream); // user credentials Credentials = await Credentials.FromSessionAsync(base.Request.Cookies, Response.Cookies); // extract projectId and folderId from folderHref string[] hrefParams = input.folderHref.Split("/"); string projectId = hrefParams[hrefParams.Length - 3]; string folderId = hrefParams[hrefParams.Length - 1]; // prepare storage ProjectsApi projectApi = new ProjectsApi(); projectApi.Configuration.AccessToken = Credentials.TokenInternal; StorageRelationshipsTargetData storageRelData = new StorageRelationshipsTargetData(StorageRelationshipsTargetData.TypeEnum.Folders, folderId); CreateStorageDataRelationshipsTarget storageTarget = new CreateStorageDataRelationshipsTarget(storageRelData); CreateStorageDataRelationships storageRel = new CreateStorageDataRelationships(storageTarget); BaseAttributesExtensionObject attributes = new BaseAttributesExtensionObject(string.Empty, string.Empty, new JsonApiLink(string.Empty), null); CreateStorageDataAttributes storageAtt = new CreateStorageDataAttributes(input.fileToUpload.FileName, attributes); CreateStorageData storageData = new CreateStorageData(CreateStorageData.TypeEnum.Objects, storageAtt, storageRel); CreateStorage storage = new CreateStorage(new JsonApiVersionJsonapi(JsonApiVersionJsonapi.VersionEnum._0), storageData); dynamic storageCreated = await projectApi.PostStorageAsync(projectId, storage); string[] storageIdParams = ((string)storageCreated.data.id).Split('/'); string[] bucketKeyParams = storageIdParams[storageIdParams.Length - 2].Split(':'); string bucketKey = bucketKeyParams[bucketKeyParams.Length - 1]; string objectName = storageIdParams[storageIdParams.Length - 1]; // upload the file/object, which will create a new object ObjectsApi objects = new ObjectsApi(); objects.Configuration.AccessToken = Credentials.TokenInternal; // get file size long fileSize = (new FileInfo(fileSavePath)).Length; // decide if upload direct or resumable (by chunks) if (fileSize > UPLOAD_CHUNK_SIZE * 1024 * 1024) // upload in chunks { long chunkSize = 2 * 1024 * 1024; // 2 Mb long numberOfChunks = (long)Math.Round((double)(fileSize / chunkSize)) + 1; long start = 0; chunkSize = (numberOfChunks > 1 ? chunkSize : fileSize); long end = chunkSize; string sessionId = Guid.NewGuid().ToString(); // upload one chunk at a time using (BinaryReader reader = new BinaryReader(new FileStream(fileSavePath, FileMode.Open))) { for (int chunkIndex = 0; chunkIndex < numberOfChunks; chunkIndex++) { string range = string.Format("bytes {0}-{1}/{2}", start, end, fileSize); long numberOfBytes = chunkSize + 1; byte[] fileBytes = new byte[numberOfBytes]; MemoryStream memoryStream = new MemoryStream(fileBytes); reader.BaseStream.Seek((int)start, SeekOrigin.Begin); int count = reader.Read(fileBytes, 0, (int)numberOfBytes); memoryStream.Write(fileBytes, 0, (int)numberOfBytes); memoryStream.Position = 0; await objects.UploadChunkAsync(bucketKey, objectName, (int)numberOfBytes, range, sessionId, memoryStream); start = end + 1; chunkSize = ((start + chunkSize > fileSize) ? fileSize - start - 1 : chunkSize); end = start + chunkSize; } } } else // upload in a single call { using (StreamReader streamReader = new StreamReader(fileSavePath)) { await objects.UploadObjectAsync(bucketKey, objectName, (int)streamReader.BaseStream.Length, streamReader.BaseStream, "application/octet-stream"); } } // cleanup string fileName = input.fileToUpload.FileName; System.IO.File.Delete(fileSavePath); // check if file already exists... FoldersApi folderApi = new FoldersApi(); folderApi.Configuration.AccessToken = Credentials.TokenInternal; var filesInFolder = await folderApi.GetFolderContentsAsync(projectId, folderId); string itemId = string.Empty; foreach (KeyValuePair <string, dynamic> item in new DynamicDictionaryItems(filesInFolder.data)) { if (item.Value.attributes.displayName == fileName) { itemId = item.Value.id; // this means a file with same name is already there, so we'll create a new version } } // now decide whether create a new item or new version if (string.IsNullOrWhiteSpace(itemId)) { // create a new item BaseAttributesExtensionObject baseAttribute = new BaseAttributesExtensionObject(projectId.StartsWith("a.") ? "items:autodesk.core:File" : "items:autodesk.bim360:File", "1.0"); CreateItemDataAttributes createItemAttributes = new CreateItemDataAttributes(fileName, baseAttribute); CreateItemDataRelationshipsTipData createItemRelationshipsTipData = new CreateItemDataRelationshipsTipData(CreateItemDataRelationshipsTipData.TypeEnum.Versions, CreateItemDataRelationshipsTipData.IdEnum._1); CreateItemDataRelationshipsTip createItemRelationshipsTip = new CreateItemDataRelationshipsTip(createItemRelationshipsTipData); StorageRelationshipsTargetData storageTargetData = new StorageRelationshipsTargetData(StorageRelationshipsTargetData.TypeEnum.Folders, folderId); CreateStorageDataRelationshipsTarget createStorageRelationshipTarget = new CreateStorageDataRelationshipsTarget(storageTargetData); CreateItemDataRelationships createItemDataRelationhips = new CreateItemDataRelationships(createItemRelationshipsTip, createStorageRelationshipTarget); CreateItemData createItemData = new CreateItemData(CreateItemData.TypeEnum.Items, createItemAttributes, createItemDataRelationhips); BaseAttributesExtensionObject baseAttExtensionObj = new BaseAttributesExtensionObject(projectId.StartsWith("a.") ? "versions:autodesk.core:File" : "versions:autodesk.bim360:File", "1.0"); CreateStorageDataAttributes storageDataAtt = new CreateStorageDataAttributes(fileName, baseAttExtensionObj); CreateItemRelationshipsStorageData createItemRelationshipsStorageData = new CreateItemRelationshipsStorageData(CreateItemRelationshipsStorageData.TypeEnum.Objects, storageCreated.data.id); CreateItemRelationshipsStorage createItemRelationshipsStorage = new CreateItemRelationshipsStorage(createItemRelationshipsStorageData); CreateItemRelationships createItemRelationship = new CreateItemRelationships(createItemRelationshipsStorage); CreateItemIncluded includedVersion = new CreateItemIncluded(CreateItemIncluded.TypeEnum.Versions, CreateItemIncluded.IdEnum._1, storageDataAtt, createItemRelationship); CreateItem createItem = new CreateItem(new JsonApiVersionJsonapi(JsonApiVersionJsonapi.VersionEnum._0), createItemData, new List <CreateItemIncluded>() { includedVersion }); ItemsApi itemsApi = new ItemsApi(); itemsApi.Configuration.AccessToken = Credentials.TokenInternal; var newItem = await itemsApi.PostItemAsync(projectId, createItem); return(newItem); } else { // create a new version BaseAttributesExtensionObject attExtensionObj = new BaseAttributesExtensionObject(projectId.StartsWith("a.") ? "versions:autodesk.core:File" : "versions:autodesk.bim360:File", "1.0"); CreateStorageDataAttributes storageDataAtt = new CreateStorageDataAttributes(fileName, attExtensionObj); CreateVersionDataRelationshipsItemData dataRelationshipsItemData = new CreateVersionDataRelationshipsItemData(CreateVersionDataRelationshipsItemData.TypeEnum.Items, itemId); CreateVersionDataRelationshipsItem dataRelationshipsItem = new CreateVersionDataRelationshipsItem(dataRelationshipsItemData); CreateItemRelationshipsStorageData itemRelationshipsStorageData = new CreateItemRelationshipsStorageData(CreateItemRelationshipsStorageData.TypeEnum.Objects, storageCreated.data.id); CreateItemRelationshipsStorage itemRelationshipsStorage = new CreateItemRelationshipsStorage(itemRelationshipsStorageData); CreateVersionDataRelationships dataRelationships = new CreateVersionDataRelationships(dataRelationshipsItem, itemRelationshipsStorage); CreateVersionData versionData = new CreateVersionData(CreateVersionData.TypeEnum.Versions, storageDataAtt, dataRelationships); CreateVersion newVersionData = new CreateVersion(new JsonApiVersionJsonapi(JsonApiVersionJsonapi.VersionEnum._0), versionData); VersionsApi versionsApis = new VersionsApi(); versionsApis.Configuration.AccessToken = Credentials.TokenInternal; dynamic newVersion = await versionsApis.PostVersionAsync(projectId, newVersionData); return(newVersion); } }
[Route("api/forge/clientid")] // see Web.Config FORGE_CALLBACK_URL variable public static async Task <string> GetClientIdAsync() { string clientIdKey = await Credentials.GetAppSetting("FORGE_CLIENT_ID"); return(clientIdKey); }