예제 #1
0
        public void DataOceanPath_is_constructed_correctly()
        {
            const string rootFolder  = "rootFolder";
            var          customerUid = Guid.NewGuid().ToString();
            var          projectUid  = Guid.NewGuid().ToString();

            var strResult = DataOceanFileUtil.DataOceanPath(rootFolder, customerUid, projectUid);

            Assert.Equal($"{DataOceanUtil.PathSeparator}{rootFolder}{DataOceanUtil.PathSeparator}{customerUid}{DataOceanUtil.PathSeparator}{projectUid}", strResult);
        }
예제 #2
0
        /// <summary>
        /// Writes the importedFile to DataOcean as a create or update,
        ///       if it already exists, old version will be deleted first.
        /// </summary>
        public static async Task WriteFileToDataOcean(
            Stream fileContents, string rootFolder, string customerUid, string projectUid, string dataOceanFileName,
            ILogger log, IServiceExceptionHandler serviceExceptionHandler, IDataOceanClient dataOceanClient,
            ITPaaSApplicationAuthentication authn, Guid fileUid, IConfigurationStore configStore)
        {
            var dataOceanEnabled = configStore.GetValueBool("ENABLE_DATA_OCEAN", false);

            if (dataOceanEnabled)
            {
                if (!dataOceanFileName.StartsWith(fileUid.ToString()))
                {
                    throw new ServiceException(HttpStatusCode.InternalServerError,
                                               new ContractExecutionResult(ContractExecutionStatesEnum.InternalProcessingError,
                                                                           $"Invalid DataOcean file name {dataOceanFileName}"));
                }

                var customHeaders = authn.CustomHeaders();
                var dataOceanPath = DataOceanFileUtil.DataOceanPath(rootFolder, customerUid, projectUid);

                var ccPutFileResult     = false;
                var folderAlreadyExists = false;

                try
                {
                    log.LogInformation($"{nameof(WriteFileToDataOcean)}: dataOceanPath: '{dataOceanPath}', dataOceanFileName: '{dataOceanFileName}'");

                    folderAlreadyExists = await dataOceanClient.FolderExists(dataOceanPath, customHeaders);

                    if (!folderAlreadyExists)
                    {
                        await dataOceanClient.MakeFolder(dataOceanPath, customHeaders);
                    }

                    ccPutFileResult = await dataOceanClient.PutFile(dataOceanPath, dataOceanFileName, fileContents, customHeaders);
                }
                catch (Exception e)
                {
                    serviceExceptionHandler.ThrowServiceException(HttpStatusCode.InternalServerError, 57, "dataOceanClient.PutFile",
                                                                  e.Message);
                }

                if (!ccPutFileResult)
                {
                    serviceExceptionHandler.ThrowServiceException(HttpStatusCode.InternalServerError, 116);
                }

                log.LogInformation($"{nameof(WriteFileToDataOcean)}: dataOceanFileName '{dataOceanFileName}' written to DataOcean, folderAlreadyExists: {folderAlreadyExists}");
            }
            else
            {
                log.LogInformation($"{nameof(WriteFileToDataOcean)}: File not saved. DataOcean disabled");
            }
        }
예제 #3
0
        /// <summary>
        /// Deletes the importedFile from DataOcean
        /// </summary>
        public static async Task <ImportedFileInternalResult> DeleteFileFromDataOcean(
            string fileName, string rootFolder, string customerUid, Guid projectUid, Guid importedFileUid,
            ILogger log, IDataOceanClient dataOceanClient, ITPaaSApplicationAuthentication authn, IConfigurationStore configStore)
        {
            var dataOceanEnabled = configStore.GetValueBool("ENABLE_DATA_OCEAN", false);

            if (dataOceanEnabled)
            {
                var dataOceanPath = DataOceanFileUtil.DataOceanPath(rootFolder, customerUid, projectUid.ToString());
                var fullFileName  = $"{dataOceanPath}{Path.DirectorySeparatorChar}{fileName}";
                log.LogInformation($"{nameof(DeleteFileFromDataOcean)}: fullFileName {JsonConvert.SerializeObject(fullFileName)}");

                var  customHeaders = authn.CustomHeaders();
                bool ccDeleteFileResult;

                try
                {
                    ccDeleteFileResult = await dataOceanClient.DeleteFile(fullFileName, customHeaders);
                }
                catch (Exception e)
                {
                    log.LogError(e, $"{nameof(DeleteFileFromDataOcean)}: failed for {fileName} (importedFileUid:{importedFileUid}) with exception {e.Message}");
                    return(ImportedFileInternalResult.CreateImportedFileInternalResult(HttpStatusCode.InternalServerError, 57, "dataOceanClient.DeleteFile", e.Message));
                }

                if (!ccDeleteFileResult)
                {
                    log.LogWarning(
                        $"{nameof(DeleteFileFromDataOcean)}: failed to delete {fileName} (importedFileUid:{importedFileUid}).");
                    //Not an error if it doesn't delete the file?
                    //return ImportedFileInternalResult.CreateImportedFileInternalResult(HttpStatusCode.InternalServerError, 117);
                }
            }
            else
            {
                log.LogInformation($"{nameof(DeleteFileFromDataOcean)}: File not deleted. DataOcean disabled");
            }

            return(null);
        }
예제 #4
0
        /// <summary>
        /// Deletes file via Trex
        /// </summary>
        protected override async Task <ContractExecutionResult> ProcessAsyncEx <T>(T item)
        {
            var deleteImportedFile = CastRequestObjectTo <DeleteImportedFile>(item, errorCode: 68);

            await CheckIfUsedInFilter(deleteImportedFile);

            await CheckIfHasReferenceSurfacesAsync(deleteImportedFile);

            // DB change must be made before productivity3dV2ProxyNotification.DeleteFile is called as it calls back here to get list of Active files
            //Don't think the above comment applies any more !
            var deleteImportedFileEvent = await ImportedFileRequestDatabaseHelper.DeleteImportedFileInDb
                                              (deleteImportedFile.ProjectUid, deleteImportedFile.ImportedFileUid, serviceExceptionHandler, projectRepo);

            ImportedFileInternalResult importedFileInternalResult = null;

            if (deleteImportedFile.IsTRexDesignFileType)
            {
                //Now delete in TRex
                await ImportedFileRequestHelper.NotifyTRexDeleteFile(deleteImportedFile.ProjectUid,
                                                                     deleteImportedFile.ImportedFileType, deleteImportedFile.FileDescriptor.FileName,
                                                                     deleteImportedFile.ImportedFileUid,
                                                                     deleteImportedFile.SurveyedUtc,
                                                                     log, customHeaders, serviceExceptionHandler,
                                                                     tRexImportFileProxy);

                //and from s3 bucket
                ProjectRequestHelper.DeleteFileFromS3Repository(
                    deleteImportedFile.ProjectUid.ToString(), deleteImportedFile.FileDescriptor.FileName,
                    deleteImportedFile.ImportedFileType == ImportedFileType.SurveyedSurface, deleteImportedFile.SurveyedUtc,
                    log, serviceExceptionHandler, persistantTransferProxyFactory.NewProxy(TransferProxyType.DesignImport));
            }

            if (deleteImportedFile.ImportedFileType == ImportedFileType.Linework ||
                deleteImportedFile.ImportedFileType == ImportedFileType.GeoTiff)
            {
                var dataOceanFileName = DataOceanFileUtil.DataOceanFileName(deleteImportedFile.FileDescriptor.FileName,
                                                                            deleteImportedFile.ImportedFileType == ImportedFileType.SurveyedSurface || deleteImportedFile.ImportedFileType == ImportedFileType.GeoTiff,
                                                                            deleteImportedFile.ImportedFileUid, deleteImportedFile.SurveyedUtc);

                importedFileInternalResult = await DataOceanHelper.DeleteFileFromDataOcean(
                    dataOceanFileName, deleteImportedFile.DataOceanRootFolder, customerUid,
                    deleteImportedFile.ProjectUid, deleteImportedFile.ImportedFileUid, log, dataOceanClient, authn, configStore);

                var tasks = new List <Task>();
                //delete generated DXF tiles
                var dxfFileName   = DataOceanFileUtil.GeneratedFileName(dataOceanFileName, deleteImportedFile.ImportedFileType);
                var dataOceanPath = DataOceanFileUtil.DataOceanPath(deleteImportedFile.DataOceanRootFolder, customerUid, deleteImportedFile.ProjectUid.ToString());
                var fullFileName  = $"{dataOceanPath}{Path.DirectorySeparatorChar}{dxfFileName}";
                tasks.Add(pegasusClient.DeleteTiles(fullFileName, DataOceanHelper.CustomHeaders(authn)));

                await Task.WhenAll(tasks);
            }

            if (importedFileInternalResult != null)
            {
                await ImportedFileRequestDatabaseHelper.UndeleteImportedFile
                    (deleteImportedFile.ProjectUid, deleteImportedFile.ImportedFileUid, serviceExceptionHandler, projectRepo);

                serviceExceptionHandler.ThrowServiceException(importedFileInternalResult.StatusCode, importedFileInternalResult.ErrorNumber, importedFileInternalResult.ResultCode, importedFileInternalResult.ErrorMessage1);
            }

            return(new ContractExecutionResult());
        }
예제 #5
0
        protected override async Task <ContractExecutionResult> ProcessAsyncEx <T>(T item)
        {
            List <FileData>     files       = null;
            int                 zoomLevel   = 0;
            Point               topLeftTile = null;
            int                 numTiles    = 0;
            BoundingBox2DLatLon bbox        = null;

            if (item is DxfTileRequest request)
            {
                files = request.files?.ToList();
                bbox  = request.bbox;

                //Calculate zoom level
                zoomLevel = TileServiceUtils.CalculateZoomLevel(request.bbox.TopRightLat - request.bbox.BottomLeftLat,
                                                                request.bbox.TopRightLon - request.bbox.BottomLeftLon);
                log.LogDebug("DxfTileExecutor: BBOX differences {0} {1} {2}", request.bbox.TopRightLat - request.bbox.BottomLeftLat,
                             request.bbox.TopRightLon - request.bbox.BottomLeftLon, zoomLevel);
                numTiles = TileServiceUtils.NumberOfTiles(zoomLevel);
                Point topLeftLatLng = new Point(request.bbox.TopRightLat.LatRadiansToDegrees(),
                                                request.bbox.BottomLeftLon.LonRadiansToDegrees());
                topLeftTile = WebMercatorProjection.LatLngToTile(topLeftLatLng, numTiles);
                log.LogDebug($"DxfTileExecutor: zoomLevel={zoomLevel}, numTiles={numTiles}, xtile={topLeftTile.x}, ytile={topLeftTile.y}");
            }
            else if (item is DxfTile3dRequest request3d)
            {
                files = request3d.files?.ToList();

                zoomLevel   = request3d.zoomLevel;
                numTiles    = TileServiceUtils.NumberOfTiles(zoomLevel);
                topLeftTile = new Point {
                    x = request3d.xTile, y = request3d.yTile
                };
            }
            else
            {
                ThrowRequestTypeCastException <DxfTileRequest>();
            }

            log.LogDebug($"DxfTileExecutor: {files?.Count ?? 0} files");

            //Short circuit overlaying if there no files to overlay as ForAll is an expensive operation
            if (files == null || !files.Any())
            {
                byte[] emptyOverlayData;
                using (var bitmap = new Image <Rgba32>(WebMercatorProjection.TILE_SIZE, WebMercatorProjection.TILE_SIZE))
                {
                    emptyOverlayData = bitmap.BitmapToByteArray();
                }

                return(new TileResult(emptyOverlayData));
            }

            log.LogDebug(string.Join(",", files.Select(f => f.Name).ToList()));

            var          tileList = new List <byte[]>();
            const string DATA_OCEAN_ROOT_FOLDER_ID_KEY = "DATA_OCEAN_ROOT_FOLDER_ID";
            var          dataOceanRootFolder           = configStore.GetValueString(DATA_OCEAN_ROOT_FOLDER_ID_KEY);

            if (string.IsNullOrEmpty(dataOceanRootFolder))
            {
                throw new ArgumentException($"Missing environment variable {DATA_OCEAN_ROOT_FOLDER_ID_KEY}");
            }

            //For GeoTIFF files, use the latest version of a file
            var geoTiffFiles = files.Where(x => x.ImportedFileType == ImportedFileType.GeoTiff).ToList();

            if (geoTiffFiles.Any())
            {
                //Find any with multiple versions and remove old ones from the list
                var latestFiles = geoTiffFiles.GroupBy(g => g.Name).Select(g => g.OrderBy(o => o.SurveyedUtc).Last()).ToList();
                foreach (var geoTiffFile in geoTiffFiles)
                {
                    if (!latestFiles.Contains(geoTiffFile))
                    {
                        files.Remove(geoTiffFile);
                    }
                }
            }

            var fileTasks = files.Select(async file =>
            {
                //foreach (var file in request.files)
                //Check file type to see if it has tiles
                if (file.ImportedFileType == ImportedFileType.Linework ||
                    file.ImportedFileType == ImportedFileType.GeoTiff)
                {
                    var fullPath = DataOceanFileUtil.DataOceanPath(dataOceanRootFolder, file.CustomerUid, file.ProjectUid);
                    var fileName = DataOceanFileUtil.DataOceanFileName(file.Name,
                                                                       file.ImportedFileType == ImportedFileType.SurveyedSurface || file.ImportedFileType == ImportedFileType.GeoTiff,
                                                                       Guid.Parse(file.ImportedFileUid), file.SurveyedUtc);
                    fileName = DataOceanFileUtil.GeneratedFileName(fileName, file.ImportedFileType);

                    if (zoomLevel >= file.MinZoomLevel)
                    {
                        byte[] tileData = null;
                        if (zoomLevel <= file.MaxZoomLevel || file.MaxZoomLevel == 0) //0 means not calculated
                        {
                            tileData = await GetTileAtRequestedZoom(topLeftTile, zoomLevel, fullPath, fileName);
                        }
                        else if (zoomLevel - file.MaxZoomLevel <= 5) //Don't try to scale if the difference is too excessive
                        {
                            tileData = await GetTileAtHigherZoom(topLeftTile, zoomLevel, fullPath, fileName,
                                                                 file.MaxZoomLevel, numTiles);
                        }
                        else
                        {
                            log.LogDebug(
                                "DxfTileExecutor: difference between requested and maximum zooms too large; not even going to try to scale tile");
                        }

                        if (tileData != null && tileData.Length > 0)
                        {
                            tileList.Add(tileData);
                        }
                    }
                }
            });

            await Task.WhenAll(fileTasks);

            log.LogDebug($"DxfTileExecutor: Overlaying {tileList.Count} tiles");
            byte[] overlayData = TileOverlay.OverlayTiles(tileList);

            return(new TileResult(overlayData));
        }