public static iLogicForm Get(UiStorage storage, string formName, InventorParameters allowedParameters) { FormSpecification formSpec = storage.LoadFormSpecification(formName); var extractor = new FormExtractor(formSpec, allowedParameters); return(extractor.Run()); }
public async Task <string> Refresh() { string returnValue = ""; List <ObjectDetails> ossFiles = await _forgeOSS.GetBucketObjectsAsync(_bucket.BucketKey, "cache/"); foreach (ObjectDetails file in ossFiles) { string[] fileParts = file.ObjectKey.Split('/'); string project = fileParts[1]; string hash = fileParts[2]; string fileName = fileParts[3]; if (fileName == "parameters.json") { returnValue += "Project " + project + " (" + hash + ") is being updated\n"; string paramsFile = Path.Combine(_localCache.LocalRootName, "params.json"); await _bucket.DownloadFileAsync(file.ObjectKey, paramsFile); InventorParameters inventorParameters = Json.DeserializeFile <InventorParameters>(paramsFile); try { await _projectWork.DoSmartUpdateAsync(inventorParameters, project, true); returnValue += "Project " + project + " (" + hash + ") was updated\n"; } catch (Exception e) { returnValue += "Project " + project + " (" + hash + ") update failed\nException: " + e.Message + "\n"; } } } return(returnValue); }
public void SetJob(JobType jobTypeParam, OssBucket bucketParam, ProjectInfo projectInfoParam, string projectUrlParam, InventorParameters parametersParam = null) { jobType = jobTypeParam; bucket = bucketParam; projectInfo = projectInfoParam; projectUrl = projectUrlParam; parameters = parametersParam; }
public async Task CreateUpdateJob(string projectId, InventorParameters parameters, string token) { _logger.LogInformation($"invoked CreateJob, connectionId : {Context.ConnectionId}"); _userResolver.Token = token; // create job and run it var job = new UpdateModelJobItem(_logger, projectId, parameters, _projectWork); await RunJobAsync(job); }
/// <summary> /// Generate hash for stringified key/value representation of InventorParameters object. /// </summary> /// <remarks>It generates hash for the string, parameters are sorted by key, key-value;key-value;....</remarks> /// <returns>Hash string.</returns> public static string GenerateParametersHashString(InventorParameters parameters) { // make key-value string ONLY to generate hash string keyValuesStr = ""; foreach (KeyValuePair <string, InventorParameter> param in parameters.OrderBy(kvp => kvp.Key)) { keyValuesStr += $"{param.Key}-{param.Value.Value};"; } return(GenerateHashString(keyValuesStr)); }
public InventorParameters ExtractParameters(Document doc, dynamic userParameters) { /* The resulting json will be like this: * { * "length" : { * "unit": "in", * "value": "10 in", * "values": ["5 in", "10 in", "15 in"] * }, * "width": { * "unit": "in", * "value": "20 in", * } * } */ try { var parameters = new InventorParameters(); foreach (dynamic param in userParameters) { var nominalValue = param.Expression; try { var unitType = doc.UnitsOfMeasure.GetTypeFromString(param.Units); var value = doc.UnitsOfMeasure.GetValueFromExpression(param.Expression, unitType); nominalValue = doc.UnitsOfMeasure.GetPreciseStringFromValue(value, unitType); } // not all unitTypes seem to be convertible (e.g. kTextUnits). In that case, we'll go on with param.Expression assigned before. catch (Exception e) { LogError("Can't get nominalValue for " + param.Name + ": " + e.Message); } var parameter = new InventorParameter { Unit = param.Units, Value = nominalValue, Values = param.ExpressionList?.GetExpressionList() ?? new string[0] }; parameters.Add(param.Name, parameter); } return(parameters); } catch (Exception e) { LogError("Error reading params: " + e.Message); return(null); } }
/// <summary> /// Update project state with the parameters (or take it from cache). /// </summary> public async Task <ProjectStateDTO> DoSmartUpdateAsync(InventorParameters parameters, string projectId, bool bForceUpdate = false) { var hash = Crypto.GenerateObjectHashString(parameters); //_logger.LogInformation(JsonSerializer.Serialize(parameters)); _logger.LogInformation($"Incoming parameters hash is {hash}"); var storage = await _userResolver.GetProjectStorageAsync(projectId); var project = storage.Project; var localNames = project.LocalNameProvider(hash); // check if the data cached already if (Directory.Exists(localNames.SvfDir) && !bForceUpdate) { _logger.LogInformation("Found cached data."); } else { var resultingHash = await UpdateAsync(project, storage, parameters, hash, bForceUpdate); if (!hash.Equals(resultingHash, StringComparison.Ordinal)) { _logger.LogInformation($"Update returned different parameters. Hash is {resultingHash}."); await CopyStateAsync(project, resultingHash, hash, storage.IsAssembly); // update hash = resultingHash; } } var dto = _dtoGenerator.MakeProjectDTO <ProjectStateDTO>(project, hash, storage.IsAssembly); dto.Parameters = Json.DeserializeFile <InventorParameters>(localNames.Parameters); return(dto); }
/// <summary> /// Create adoption data. /// </summary> /// <param name="docUrl">URL to the input Inventor document (IPT or zipped IAM)</param> /// <param name="tlaFilename">Top level assembly in the ZIP. (if any)</param> /// <param name="parameters">Inventor parameters.</param> public async Task <UpdateData> ForUpdateAsync(string docUrl, string tlaFilename, InventorParameters parameters) { var bucket = await _userResolver.GetBucketAsync(); var urls = await Task.WhenAll( bucket.CreateSignedUrlAsync(OutputModelIAM, ObjectAccess.Write), bucket.CreateSignedUrlAsync(OutputModelIPT, ObjectAccess.Write), bucket.CreateSignedUrlAsync(SVF, ObjectAccess.Write), bucket.CreateSignedUrlAsync(Parameters, ObjectAccess.Write), bucket.CreateSignedUrlAsync(InputParams, ObjectAccess.ReadWrite), bucket.CreateSignedUrlAsync(BomJson, ObjectAccess.Write) ); await using var jsonStream = Json.ToStream(parameters); await bucket.UploadObjectAsync(InputParams, jsonStream); return(new UpdateData { InputDocUrl = docUrl, OutputIAMModelUrl = urls[0], OutputIPTModelUrl = urls[1], SvfUrl = urls[2], ParametersJsonUrl = urls[3], InputParamsUrl = urls[4], BomUrl = urls[5], TLA = tlaFilename }); }
/// <summary> /// Generate project data for the given parameters and cache results locally. /// </summary> /// <returns>Resulting parameters hash</returns> private async Task <string> UpdateAsync(Project project, ProjectStorage storage, InventorParameters parameters, string hash, bool bForceUpdate = false) { _logger.LogInformation("Update the project"); var bucket = await _userResolver.GetBucketAsync(); var isUpdateExists = bForceUpdate ? false : await IsGenerated(project, bucket, hash); if (isUpdateExists) { _logger.LogInformation("Detected existing outputs at OSS"); } else { var inputDocUrl = await bucket.CreateSignedUrlAsync(project.OSSSourceModel); UpdateData updateData = await _arranger.ForUpdateAsync(inputDocUrl, storage.Metadata.TLA, parameters); ProcessingResult result = await _fdaClient.UpdateAsync(updateData); if (!result.Success) { _logger.LogError($"Failed to update '{project.Name}' project."); throw new FdaProcessingException($"Failed to update '{project.Name}' project.", result.ReportUrl); } _logger.LogInformation("Moving files around"); // rearrange generated data according to the parameters hash // NOTE: hash might be changed if Inventor adjust them! hash = await _arranger.MoveViewablesAsync(project, storage.IsAssembly); } _logger.LogInformation($"Cache the project locally ({hash})"); // and now cache the generate stuff locally var projectStorage = new ProjectStorage(project); await projectStorage.EnsureViewablesAsync(bucket, hash); return(hash); }
public UpdateModelJobItem(ILogger logger, string projectId, InventorParameters parameters, ProjectWork projectWork) : base(logger, projectId, projectWork) { Parameters = parameters; }
private InventorParameters ExtractParameters(Document doc, dynamic userParameters) { /* The resulting json will be like this: * { * "length" : { * "unit": "in", * "value": "10 in", * "values": ["5 in", "10 in", "15 in"] * }, * "width": { * "unit": "in", * "value": "20 in", * } * } */ try { var parameters = new InventorParameters(); var docUnitsOfMeasure = doc.UnitsOfMeasure; foreach (dynamic param in userParameters) { var nominalValue = param.Expression; string errorMessage = null; try { var unitType = docUnitsOfMeasure.GetTypeFromString(param.Units); LogTrace($"Checking expression validity on extraction for {param.Expression} and unit type {param.Units} / {unitType}"); if (docUnitsOfMeasure.IsExpressionValid(param.Expression, unitType)) { var value = docUnitsOfMeasure.GetValueFromExpression(param.Expression, unitType); nominalValue = docUnitsOfMeasure.GetPreciseStringFromValue(value, unitType); } else { LogTrace($"Expression '{param.Expression}' invalid for unit type '{unitType}' on extract attempt"); errorMessage = "Parameter's expression is not valid for its unit type"; } } // not all unitTypes seem to be convertible (e.g. kTextUnits). In that case, we'll go on with param.Expression assigned before. catch (Exception e) { LogError("Can't get nominalValue for " + param.Name + ": " + e.Message); } var parameter = new InventorParameter { Unit = param.Units, Value = nominalValue, Values = param.ExpressionList?.GetExpressionList() ?? new string[0], ErrorMessage = errorMessage }; parameters.Add(param.Name, parameter); } return(parameters); } catch (Exception e) { LogError("Error reading params: " + e.Message); return(null); } }
public void Extract(Document doc, Parameters parameters, InventorParameters updateResultParameters = null) { // extract user parameters InventorParameters allParams = ExtractParameters(doc, parameters); // save current state LogTrace("Updating"); doc.Update2(); LogTrace("Saving"); doc.Save2(SaveDependents: true); // detect iLogic forms iLogicFormsReader reader = new iLogicFormsReader(doc, allParams); iLogicForm[] forms = reader.Extract(); LogTrace($"Found {forms.Length} iLogic forms"); foreach (var form in forms) { LogTrace($" - {form.Name}"); } // Choose set of parameters to use with the following algorithm: // - extract all iLogic forms from the document // - keep only 'user parameters' from a form // - use _first_ iLogic form with non-empty list of parameters // - if no forms - use UserParameters from the document InventorParameters resultingParameters; var candidate = forms.FirstOrDefault(form => form.Parameters.Count > 0); if (candidate != null) { LogTrace($"Using '{candidate.Name}' form as a parameter filter"); resultingParameters = candidate.Parameters; } else { LogTrace("No non-empty iLogic forms found. Using all user parameters."); resultingParameters = ExtractParameters(doc, parameters.UserParameters); } // if parameters from an update result were passed in, if validation errors were set on any replace values with them if (updateResultParameters != null) { foreach (KeyValuePair <string, InventorParameter> updateResultParam in updateResultParameters) { if (updateResultParam.Value.ErrorMessage != null) { resultingParameters[updateResultParam.Key] = updateResultParam.Value; } } } // generate resulting JSON. Note it's not formatted (to have consistent hash) string paramsJson = JsonConvert.SerializeObject(resultingParameters, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }); System.IO.File.WriteAllText("documentParams.json", paramsJson); LogTrace("Closing"); doc.Close(true); }
/// <summary> /// Generate project data for the given parameters and cache results locally. /// </summary> /// <returns>Resulting parameters hash</returns> private async Task <(string hash, FdaStatsDTO stats, string reportUrl)> UpdateAsync(ProjectStorage storage, InventorParameters parameters, string hash, bool bForceUpdate = false) { _logger.LogInformation("Update the project"); var bucket = await _userResolver.GetBucketAsync(); var isUpdateExists = bForceUpdate ? false : await IsGenerated(bucket, storage.GetOssNames(hash)); FdaStatsDTO stats; string reportUrl; if (isUpdateExists) { _logger.LogInformation("Detected existing outputs at OSS"); var statsNative = await bucket.DeserializeAsync <List <Statistics> >(storage.GetOssNames(hash).StatsUpdate); stats = FdaStatsDTO.CreditsOnly(statsNative); reportUrl = null; } else { Project project = storage.Project; var inputDocUrl = await bucket.CreateSignedUrlAsync(project.OSSSourceModel); UpdateData updateData = await _arranger.ForUpdateAsync(inputDocUrl, storage.Metadata.TLA, parameters); ProcessingResult result = await _fdaClient.UpdateAsync(updateData); if (!result.Success) { _logger.LogError($"Failed to update '{project.Name}' project."); throw new FdaProcessingException($"Failed to update '{project.Name}' project.", result.ReportUrl); } _logger.LogInformation("Moving files around"); // rearrange generated data according to the parameters hash // NOTE: hash might be changed if Inventor adjust them! hash = await _arranger.MoveViewablesAsync(project, storage.IsAssembly); // process statistics await bucket.UploadAsJsonAsync(storage.GetOssNames(hash).StatsUpdate, result.Stats); stats = FdaStatsDTO.All(result.Stats); reportUrl = result.ReportUrl; } _logger.LogInformation($"Cache the project locally ({hash})"); // and now cache the generated stuff locally await storage.EnsureViewablesAsync(bucket, hash); return(hash, stats, reportUrl); }
/// <summary> /// Update project state with the parameters (or take it from cache). /// </summary> public async Task <(ProjectStateDTO dto, FdaStatsDTO stats, string reportUrl)> DoSmartUpdateAsync(InventorParameters parameters, string projectId, bool bForceUpdate = false) { var hash = Crypto.GenerateObjectHashString(parameters); _logger.LogInformation($"Incoming parameters hash is {hash}"); var storage = await _userResolver.GetProjectStorageAsync(projectId); FdaStatsDTO stats; var localNames = storage.GetLocalNames(hash); string reportUrl; // check if the data cached already if (Directory.Exists(localNames.SvfDir) && !bForceUpdate) { _logger.LogInformation("Found cached data."); // restore statistics var bucket = await _userResolver.GetBucketAsync(); var statsNative = await bucket.DeserializeAsync <List <Statistics> >(storage.GetOssNames(hash).StatsUpdate); stats = FdaStatsDTO.CreditsOnly(statsNative); reportUrl = null; } else { string resultingHash; (resultingHash, stats, reportUrl) = await UpdateAsync(storage, parameters, hash, bForceUpdate); if (!hash.Equals(resultingHash, StringComparison.Ordinal)) { _logger.LogInformation($"Update returned different parameters. Hash is {resultingHash}."); await CopyStateAsync(storage.Project, resultingHash, hash, storage.IsAssembly); // update hash = resultingHash; } } var dto = _dtoGenerator.MakeProjectDTO <ProjectStateDTO>(storage, hash); dto.Parameters = Json.DeserializeFile <InventorParameters>(localNames.Parameters); return(dto, stats, reportUrl); }
public void Run(Document doc) { LogTrace($"Run called with {doc.DisplayName}"); try { using (new HeartBeat()) { Parameters parameters; switch (doc.DocumentType) { case DocumentTypeEnum.kPartDocumentObject: parameters = ((PartDocument)doc).ComponentDefinition.Parameters; break; case DocumentTypeEnum.kAssemblyDocumentObject: parameters = ((AssemblyDocument)doc).ComponentDefinition.Parameters; break; default: LogError($"Unsupported document type: {doc.DocumentType}"); return; } // extract user parameters InventorParameters allParams = ExtractParameters(doc, parameters); // save current state LogTrace("Updating"); doc.Update2(); LogTrace("Saving"); doc.Save2(SaveDependents: true); // detect iLogic forms iLogicFormsReader reader = new iLogicFormsReader(doc, allParams); iLogicForm[] forms = reader.Extract(); LogTrace($"Found {forms.Length} iLogic forms"); foreach (var form in forms) { LogTrace($" - {form.Name}"); } // Choose set of parameters to use with the following algorithm: // - extract all iLogic forms from the document // - keep only 'user parameters' from a form // - use _first_ iLogic form with non-empty list of parameters // - if no forms - use UserParameters from the document InventorParameters resultingParameters; var candidate = forms.FirstOrDefault(form => form.Parameters.Count > 0); if (candidate != null) { LogTrace($"Using '{candidate.Name}' form as a parameter filter"); resultingParameters = candidate.Parameters; } else { LogTrace("No non-empty iLogic forms found. Using all user parameters."); resultingParameters = ExtractParameters(doc, parameters.UserParameters); } // generate resulting JSON. Note it's not formatted (to have consistent hash) string paramsJson = JsonConvert.SerializeObject(resultingParameters, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }); System.IO.File.WriteAllText("documentParams.json", paramsJson); LogTrace("Closing"); doc.Close(true); } } catch (Exception e) { LogError("Processing failed. " + e.ToString()); } }
/// <summary>Constructor.</summary> /// <param name="document">Inventor document.</param> /// <param name="allowedParameters">Map with Inventor parameters, which are allowed to be extracted.</param> public iLogicFormsReader(Document document, InventorParameters allowedParameters) { _allowedParameters = allowedParameters; _storage = UiStorageFactory.GetDocumentStorage(document); }
private async Task ScanBucket(List <MigrationJob> adoptJobs, List <MigrationJob> configJobs, string bucketKeyOld) { _logger.LogInformation($"Scanning bucket {bucketKeyOld}"); MigrationBucketKeyProvider bucketProvider; ProjectService projectService; using (var scope = _serviceScopeFactory.CreateScope()) { bucketProvider = scope.ServiceProvider.GetService <MigrationBucketKeyProvider>(); projectService = scope.ServiceProvider.GetService <ProjectService>(); } OssBucket bucketOld = _bucketFactory.CreateBucket(bucketKeyOld); OssBucket bucketNew = _bucketFactory.CreateBucket(bucketProvider.GetBucketKeyFromOld(bucketKeyOld)); List <string> projectNamesNew = new List <string>(); try { List <string> projectNamesNewFromOss = (List <string>) await projectService.GetProjectNamesAsync(bucketNew); foreach (string projectName in projectNamesNewFromOss) { var ossAttributes = new OssAttributes(projectName); string metadataFile = ossAttributes.Metadata; // if metadata file is missing for project we consider that project not migrated if (await bucketNew.ObjectExistsAsync(metadataFile)) { projectNamesNew.Add(projectName); } } } catch (ApiException e) when(e.ErrorCode == StatusCodes.Status404NotFound) { // swallow non existing item } // gather list of cache paramters files from the new bucket List <string> configKeysNew = new List <string>(); try { List <ObjectDetails> configODsNew = await bucketNew.GetObjectsAsync($"{ONC.CacheFolder}/"); foreach (ObjectDetails configODNew in configODsNew) { if (configODNew.ObjectKey.EndsWith(WebApplication.Utilities.LocalName.Parameters)) { configKeysNew.Add(configODNew.ObjectKey); } } } catch (ApiException e) when(e.ErrorCode == StatusCodes.Status404NotFound) { // swallow non existing item } // gather projects to migrate List <string> projectNamesOld = (List <string>) await projectService.GetProjectNamesAsync(bucketOld); foreach (string projectName in projectNamesOld) { if (!projectNamesNew.Contains(projectName)) { // new project list does not contain old project => lets copy and adopt var ossAttributes = new OssAttributes(projectName); string metadataFile = ossAttributes.Metadata; try { ProjectMetadata projectMetadata = await bucketOld.DeserializeAsync <ProjectMetadata>(metadataFile); ProjectInfo projectInfo = new ProjectInfo(); projectInfo.Name = projectName; projectInfo.TopLevelAssembly = projectMetadata.TLA; MigrationJob migrationJob; using (var scope = _serviceScopeFactory.CreateScope()) { migrationJob = scope.ServiceProvider.GetService <MigrationJob>(); } migrationJob.SetJob(JobType.CopyAndAdopt, bucketOld, projectInfo, ONC.ProjectUrl(projectName)); adoptJobs.Add(migrationJob); } catch (Exception e) { _logger.LogError(e, $"Project {projectName} in bucket {bucketKeyOld} does not have metadata file. Skipping it."); } } // process cached configurations List <ObjectDetails> configODs = await bucketOld.GetObjectsAsync($"{ONC.CacheFolder}/{projectName}/"); foreach (ObjectDetails configOD in configODs) { string configKey = configOD.ObjectKey; if (configKey.EndsWith(WebApplication.Utilities.LocalName.Parameters)) { // calculate parameter hash based on new algorithmes InventorParameters parameters = await bucketOld.DeserializeAsync <InventorParameters>(configKey); string newHash = Crypto.GenerateParametersHashString(parameters); OSSObjectNameProvider onp = new OSSObjectNameProvider(projectName, newHash); configKey = onp.Parameters; if (!configKeysNew.Contains(configKey)) { ProjectInfo projectInfo = new ProjectInfo(); projectInfo.Name = projectName; MigrationJob migrationJob; using (var scope = _serviceScopeFactory.CreateScope()) { migrationJob = scope.ServiceProvider.GetService <MigrationJob>(); } migrationJob.SetJob(JobType.GenerateConfiguration, bucketOld, projectInfo, ONC.ProjectUrl(projectName), parameters); configJobs.Add(migrationJob); } } } } // check if any of migrated projects were deleted in old bucket // (user deleted them after migration started) foreach (string projectName in projectNamesNew) { if (!projectNamesOld.Contains(projectName)) { MigrationJob migrationJob; using (var scope = _serviceScopeFactory.CreateScope()) { migrationJob = scope.ServiceProvider.GetService <MigrationJob>(); } migrationJob.SetJob(JobType.RemoveNew, bucketNew, new ProjectInfo(projectName), null); adoptJobs.Add(migrationJob); } } }
private FormExtractor(FormSpecification formSpec, InventorParameters allowedParameters) { _formSpec = formSpec; _allowedParameters = allowedParameters; }