コード例 #1
0
        public async Task <KeyValuePair <bool, string> > ReadString(string sourceHttpUrl)
        {
            Uri sourceUri = new Uri(sourceHttpUrl);

            _logger.LogInformation("[ReadString] HttpClientHelper > " + sourceUri.Host + " ~ " + sourceHttpUrl);

            // allow whitelist and https only
            if (!_allowedDomains.Contains(sourceUri.Host) || sourceUri.Scheme != "https")
            {
                return
                    (new KeyValuePair <bool, string>(false, string.Empty));
            }

            try
            {
                using (HttpResponseMessage response = await _httpProvider.GetAsync(sourceHttpUrl))
                    using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
                    {
                        var reader = new StreamReader(streamToReadFrom, Encoding.UTF8);
                        var result = await reader.ReadToEndAsync();

                        return(new KeyValuePair <bool, string>(response.StatusCode == HttpStatusCode.OK, result));
                    }
            }
            catch (HttpRequestException exception)
            {
                return(new KeyValuePair <bool, string>(false, exception.Message));
            }
        }
コード例 #2
0
        public async Task <bool> DownloadExifTool(bool isWindows)
        {
            if (_appSettings.AddSwaggerExport == true && _appSettings.AddSwaggerExportExitAfter == true)
            {
                _logger.LogInformation("[DownloadExifTool] Skipped due AddSwaggerExportExitAfter setting");
                return(false);
            }

            if (isWindows &&
                !_hostFileSystemStorage.ExistFile(ExeExifToolWindowsFullFilePath()))
            {
                return(await StartDownloadForWindows());
            }

            if (!isWindows &&
                !_hostFileSystemStorage.ExistFile(ExeExifToolUnixFullFilePath()))
            {
                return(await StartDownloadForUnix());
            }

            if (_appSettings.IsVerbose())
            {
                var debugPath = isWindows ? ExeExifToolWindowsFullFilePath()
                                        : ExeExifToolUnixFullFilePath();
                _logger.LogInformation($"[DownloadExifTool] {debugPath}");
            }

            // When running deploy scripts rights might reset (only for unix)
            if (isWindows)
            {
                return(true);
            }

            return(await RunChmodOnExifToolUnixExe());
        }
コード例 #3
0
        public async Task <List <string> > CleanAllUnusedFilesAsync(int chunkSize = 50)
        {
            if (!_thumbnailStorage.ExistFolder("/"))
            {
                throw new DirectoryNotFoundException("Thumbnail folder not found");
            }

            var allThumbnailFiles = _thumbnailStorage
                                    .GetAllFilesInDirectory(null).ToList();

            _logger.LogDebug($"Total files in thumb dir: {allThumbnailFiles.Count}");

            var deletedFileHashes = new List <string>();

            foreach (var fileNamesInChunk in allThumbnailFiles.ChunkyEnumerable(chunkSize))
            {
                var itemsInChunk = GetFileNamesWithExtension(fileNamesInChunk.ToList());
                try
                {
                    await LoopThoughChunk(itemsInChunk, deletedFileHashes);
                }
                catch (Microsoft.EntityFrameworkCore.Storage.RetryLimitExceededException exception)
                {
                    _logger.LogInformation($"[CleanAllUnusedFiles] catch-ed and " +
                                           $"skip {string.Join(",", itemsInChunk.ToList())} ~ {exception.Message}", exception);
                }
            }
            return(deletedFileHashes);
        }
コード例 #4
0
        public async Task <FileIndexItem.ExifStatus> ManualSync(string subPath,
                                                                string operationId = null)
        {
            var fileIndexItem = await _query.GetObjectByFilePathAsync(subPath);

            // on a new database ->
            if (subPath == "/" && fileIndexItem == null)
            {
                fileIndexItem = new FileIndexItem();
            }
            if (fileIndexItem == null)
            {
                _logger.LogInformation($"[ManualSync] NotFoundNotInIndex skip for: {subPath}");
                return(FileIndexItem.ExifStatus.NotFoundNotInIndex);
            }

            if (_cache.TryGetValue(ManualSyncCacheName + subPath, out _))
            {
                // also used in removeCache
                _query.RemoveCacheParentItem(subPath);
                _logger.LogInformation($"[ManualSync] Cache hit skip for: {subPath}");
                return(FileIndexItem.ExifStatus.OperationNotSupported);
            }

            _cache.Set(ManualSyncCacheName + subPath, true,
                       new TimeSpan(0, 1, 0));

            _bgTaskQueue.QueueBackgroundWorkItem(async _ =>
            {
                await BackgroundTask(fileIndexItem.FilePath, operationId);
            });

            return(FileIndexItem.ExifStatus.Ok);
        }
コード例 #5
0
        public bool FolderDelete(string path)
        {
            foreach (string directory in Directory.GetDirectories(path))
            {
                FolderDelete(directory);
            }

            try
            {
                Directory.Delete(path, true);
            }
            catch (IOException exception)
            {
                _logger?.LogInformation(exception,
                                        "[FolderDelete] catch-ed IOException");
                Directory.Delete(path, true);
            }
            catch (UnauthorizedAccessException exception)
            {
                _logger?.LogInformation(exception,
                                        "[FolderDelete] catch-ed UnauthorizedAccessException");
                Directory.Delete(path, true);
            }
            return(true);
        }
コード例 #6
0
        internal (ExifThumbnailDirectory, int, int, FileIndexItem.Rotation) ParseMetaThumbnail(List <Directory> allExifItems,
                                                                                               ExifThumbnailDirectory exifThumbnailDir, string reference = null)
        {
            if (exifThumbnailDir == null)
            {
                return(null, 0, 0, FileIndexItem.Rotation.DoNotChange);
            }

            var jpegTags = allExifItems.FirstOrDefault(p =>
                                                       p.Name == "JPEG")?.Tags;

            var rotation = ReadMetaExif.GetOrientationFromExifItem(
                allExifItems.FirstOrDefault(p => p.Name == "Exif IFD0"));

            int.TryParse(
                jpegTags?.FirstOrDefault(p => p.Name == "Image Height")?
                .Description.Replace(" pixels", string.Empty), out var height);

            int.TryParse(
                jpegTags?.FirstOrDefault(p => p.Name == "Image Width")?
                .Description.Replace(" pixels", string.Empty), out var width);

            if (height == 0 || width == 0)
            {
                _logger.LogInformation($"[] ${reference} has no height or width {width}x{height} ");
            }
            return(exifThumbnailDir, width, height, rotation);
        }
コード例 #7
0
        /// <summary>
        /// @see: https://docs.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher?view=netcore-3.1
        /// </summary>
        public void Watcher(string fullFilePath)
        {
            _webLogger.LogInformation($"[DiskWatcher] started {fullFilePath}" +
                                      $"{DateTimeDebug()}");

            // Create a new FileSystemWatcher and set its properties.

            _fileSystemWatcherWrapper.Path   = fullFilePath;
            _fileSystemWatcherWrapper.Filter = "*";
            _fileSystemWatcherWrapper.IncludeSubdirectories = true;
            _fileSystemWatcherWrapper.NotifyFilter          = NotifyFilters.FileName
                                                              | NotifyFilters.DirectoryName
                                                              | NotifyFilters.Attributes
                                                              | NotifyFilters.Size
                                                              | NotifyFilters.LastWrite
                                                              // NotifyFilters.LastAccess is removed
                                                              | NotifyFilters.CreationTime
                                                              | NotifyFilters.Security;

            // Watch for changes in LastAccess and LastWrite times, and
            // the renaming of files or directories.

            // Add event handlers.

            _fileSystemWatcherWrapper.Created += OnChanged;
            _fileSystemWatcherWrapper.Changed += OnChanged;
            _fileSystemWatcherWrapper.Deleted += OnChanged;
            _fileSystemWatcherWrapper.Renamed += OnRenamed;
            _fileSystemWatcherWrapper.Error   += OnError;

            // Begin watching.
            _fileSystemWatcherWrapper.EnableRaisingEvents = true;
        }
コード例 #8
0
ファイル: GeoController.cs プロジェクト: qdraw/starsky
        [ProducesResponseType(typeof(string), 200)]        // "Not found"
        public IActionResult GeoSyncFolder(
            string f   = "/",
            bool index = true,
            bool overwriteLocationNames = false
            )
        {
            if (_iStorage.IsFolderOrFile(f) == FolderOrFileModel.FolderOrFileTypeList.Deleted)
            {
                return(NotFound("Folder location is not found"));
            }

            var operationId = HttpContext.GetOperationId();

            _bgTaskQueue.QueueBackgroundWorkItem(async token =>
            {
                _logger.LogInformation($"{nameof(GeoSyncFolder)} started {f} {DateTime.UtcNow.ToShortTimeString()}");
                var operationHolder = RequestTelemetryHelper.GetOperationHolder(_serviceScopeFactory,
                                                                                nameof(GeoSyncFolder), operationId);

                var geoBackgroundTask = _serviceScopeFactory.CreateScope().ServiceProvider
                                        .GetService <IGeoBackgroundTask>();
                var result = await geoBackgroundTask.GeoBackgroundTaskAsync(f, index,
                                                                            overwriteLocationNames);

                operationHolder.SetData(_serviceScopeFactory, result);

                _logger.LogInformation($"{nameof(GeoSyncFolder)} end {f} {operationHolder.Telemetry?.Duration}");
            });

            return(Json("job started"));
        }
コード例 #9
0
        internal async Task <List <string> > AddParentCacheIfNotExistAsync(IEnumerable <string> updatedPaths)
        {
            var parentDirectoryList = new HashSet <string>();

            foreach (var path in updatedPaths)
            {
                parentDirectoryList.Add(FilenamesHelper.GetParentPath(path));
            }

            var shouldAddParentDirectoriesToCache = parentDirectoryList.Where(parentDirectory =>
                                                                              !_query.CacheGetParentFolder(parentDirectory).Item1).ToList();

            if (!shouldAddParentDirectoriesToCache.Any())
            {
                return(new List <string>());
            }

            var databaseQueryResult = await _query.GetAllObjectsAsync(shouldAddParentDirectoriesToCache);

            _logger.LogInformation("[AddParentCacheIfNotExist] files added to cache " +
                                   string.Join(",", shouldAddParentDirectoriesToCache));

            foreach (var directory in shouldAddParentDirectoriesToCache)
            {
                var byDirectory = databaseQueryResult.Where(p => p.ParentDirectory == directory).ToList();
                _query.AddCacheParentItem(directory, byDirectory);
            }
            return(shouldAddParentDirectoriesToCache);
        }
コード例 #10
0
ファイル: SwaggerExportHelper.cs プロジェクト: qdraw/starsky
        /// <summary>
        /// Export Values to Storage
        /// </summary>
        /// <param name="appSettings">App Settings</param>
        /// <param name="selectorStorage">Storage Provider</param>
        /// <param name="swaggerProvider">Swagger</param>
        /// <exception cref="ArgumentNullException">swaggerJsonText = null</exception>
        public bool Add03AppExport(AppSettings appSettings, ISelectorStorage selectorStorage, ISwaggerProvider swaggerProvider)
        {
            if (appSettings.AddSwagger != true || appSettings.AddSwaggerExport != true)
            {
                return(false);
            }

            var swaggerJsonText = GenerateSwagger(swaggerProvider, appSettings.Name);

            if (string.IsNullOrEmpty(swaggerJsonText))
            {
                throw new ArgumentException("swaggerJsonText = null", nameof(swaggerProvider));
            }

            var swaggerJsonFullPath =
                Path.Join(appSettings.TempFolder, appSettings.Name.ToLowerInvariant() + ".json");

            var storage = selectorStorage.Get(SelectorStorage.StorageServices.HostFilesystem);

            storage.FileDelete(swaggerJsonFullPath);
            storage.WriteStream(new PlainTextFileHelper().StringToStream(swaggerJsonText),
                                swaggerJsonFullPath);

            _logger?.LogInformation($"app__addSwaggerExport {swaggerJsonFullPath}");
            return(true);
        }
コード例 #11
0
ファイル: Query.cs プロジェクト: qdraw/starsky
        /// <summary>
        /// Returns a database object file or folder
        /// </summary>
        /// <param name="filePath">relative database path</param>
        /// <param name="cacheTime">time to have the cache present</param>
        /// <returns>FileIndex-objects with database data</returns>
        public async Task <FileIndexItem> GetObjectByFilePathAsync(
            string filePath, TimeSpan?cacheTime = null)
        {
            // cache code:
            if (cacheTime != null &&
                _appSettings?.AddMemoryCache == true &&
                _cache != null &&
                _cache.TryGetValue(
                    GetObjectByFilePathAsyncCacheName(filePath), out var data))
            {
                _logger.LogInformation("Get from cache " + GetObjectByFilePathAsyncCacheName(filePath));
                if (!(data is FileIndexItem fileIndexItem))
                {
                    return(null);
                }
                fileIndexItem.Status = FileIndexItem.ExifStatus.OkAndSame;
                return(fileIndexItem);
            }
            // end cache

            var result = (await GetObjectByFilePathQueryAsync(filePath));

            // cache code:
            if (cacheTime == null || _appSettings?.AddMemoryCache != true || result == null)
            {
                return(result);
            }

            SetGetObjectByFilePathCache(filePath, result.Clone(), cacheTime);

            return(result);
        }
コード例 #12
0
ファイル: StopWatchLogger.cs プロジェクト: qdraw/starsky
 public void StopUpdateReplaceStopWatch(string name, string f, bool collections, Stopwatch stopwatch)
 {
     // for debug
     stopwatch.Stop();
     _logger.LogInformation($"[{name}] f: {f} Stopwatch response collections: " +
                            $"{collections} {DateTime.UtcNow} duration: {stopwatch.Elapsed.TotalMilliseconds} ms or:" +
                            $" {stopwatch.Elapsed.TotalSeconds} sec");
 }
コード例 #13
0
        /// <summary>
        /// For Checking single items without querying the database
        /// </summary>
        /// <param name="subPath">path</param>
        /// <param name="dbItem">current item, can be null</param>
        /// <param name="updateDelegate">push updates realtime to the user and avoid waiting</param>
        /// <returns>updated item with status</returns>
        internal async Task <FileIndexItem> SingleFile(string subPath,
                                                       FileIndexItem dbItem,
                                                       ISynchronize.SocketUpdateDelegate updateDelegate = null)
        {
            // when item does not exist in db
            if (dbItem == null)
            {
                return(await SingleFile(subPath));
            }

            // Route without database check
            if (_appSettings.ApplicationType == AppSettings.StarskyAppType.WebController)
            {
                _logger.LogInformation($"[SingleFile/no-db] {subPath} - {DateTime.UtcNow.ToShortTimeString()}");
            }

            // Sidecar files are updated but ignored by the process
            await UpdateSidecarFile(subPath);

            var statusItem = CheckForStatusNotOk(subPath);

            if (statusItem.Status != FileIndexItem.ExifStatus.Ok)
            {
                _logger.LogInformation($"[SingleFile/no-db] status {statusItem.Status} for {subPath}");
                return(statusItem);
            }

            var(isSame, updatedDbItem) = await SizeFileHashIsTheSame(dbItem);

            if (!isSame)
            {
                if (updateDelegate != null)
                {
                    new Thread(() => updateDelegate(new List <FileIndexItem> {
                        dbItem
                    })).Start();
                }
                return(await UpdateItem(dbItem, updatedDbItem.Size, subPath));
            }

            // to avoid reSync
            updatedDbItem.Status = FileIndexItem.ExifStatus.OkAndSame;
            AddDeleteStatus(statusItem, FileIndexItem.ExifStatus.DeletedAndSame);

            return(updatedDbItem);
        }
コード例 #14
0
        internal TelemetryClient GetTelemetryClient()
        {
            var client = _serviceProvider != null?_serviceProvider.GetService <TelemetryClient>() : _app.ApplicationServices.GetService <TelemetryClient>();

            if (client == null && _appSettings != null && !string.IsNullOrEmpty(_appSettings.ApplicationInsightsInstrumentationKey))
            {
                _logger.LogInformation("TelemetryClient is null on exit");
            }
            return(client);
        }
コード例 #15
0
        /// <summary>
        /// Update ExifTool, Thumbnail, Database and if needed rotateClock
        /// </summary>
        /// <param name="fileIndexItem">output database object</param>
        /// <param name="comparedNamesList">name of fields updated by exifTool</param>
        /// <param name="rotateClock">rotation value (if needed)</param>
        private async Task UpdateWriteDiskDatabase(FileIndexItem fileIndexItem, List <string> comparedNamesList, int rotateClock = 0)
        {
            // do rotation on thumbs
            await RotationThumbnailExecute(rotateClock, fileIndexItem);

            if (fileIndexItem.IsDirectory != true &&
                ExtensionRolesHelper.IsExtensionExifToolSupported(fileIndexItem.FileName))
            {
                // feature to exif update
                var exifUpdateFilePaths = new List <string>
                {
                    fileIndexItem.FilePath
                };
                var exifTool = new ExifToolCmdHelper(_exifTool, _iStorage, _thumbnailStorage, _readMeta);

                // to avoid diskWatcher catch up
                _query.SetGetObjectByFilePathCache(fileIndexItem.FilePath, fileIndexItem, TimeSpan.FromSeconds(10));

                // Do an Exif Sync for all files, including thumbnails
                var(exifResult, newFileHashes) = await exifTool.UpdateAsync(fileIndexItem,
                                                                            exifUpdateFilePaths, comparedNamesList, true, true);

                await ApplyOrGenerateUpdatedFileHash(newFileHashes, fileIndexItem);

                _logger.LogInformation(string.IsNullOrEmpty(exifResult)
                                        ? $"[UpdateWriteDiskDatabase] ExifTool result is Nothing or " +
                                       $"Null for: path:{fileIndexItem.FilePath} {DateTime.UtcNow.ToShortTimeString()}"
                                        : $"[UpdateWriteDiskDatabase] ExifTool result: {exifResult} path:{fileIndexItem.FilePath}");
            }
            else
            {
                await new FileIndexItemJsonParser(_iStorage).WriteAsync(fileIndexItem);
            }

            // Do a database sync + cache sync
            // Clone to avoid reference when cache exist
            await _query.UpdateItemAsync(fileIndexItem.Clone());

            // > async > force you to read the file again
            // do not include thumbs in MetaCache
            // only the full path url of the source image
            _readMeta.RemoveReadMetaCache(fileIndexItem.FilePath);
        }
コード例 #16
0
        public static TelemetryClient?InitTelemetryClient(string appInsightsConnectionString, string roleName, IWebLogger?logger, TelemetryClient?telemetryClient)
        {
            TelemetryClient?Clean(Exception exception)
            {
                logger?.LogInformation($"catch-ed exception; {exception.Message} ", exception);
                logger?.LogInformation("run GC.Collect next -->");
                GC.Collect();
                return(null);
            }

            try
            {
                // Should skip to avoid memory issues
                if (telemetryClient == null)
                {
                    var telemetryConfiguration =
                        CreateTelemetryConfiguration(appInsightsConnectionString);
                    if (telemetryConfiguration == null)
                    {
                        return(null);
                    }
                    telemetryClient =
                        new TelemetryClient(telemetryConfiguration);
                    telemetryClient.Context.Cloud.RoleName     = roleName;
                    telemetryClient.Context.Cloud.RoleInstance =
                        Environment.MachineName;
                    logger?.LogInformation("Added TelemetryClient [should avoid due memory issues]");
                }

                var module = CreateDatabaseDependencyTrackingTelemetryModule();
                module.Initialize(telemetryClient.TelemetryConfiguration);
                return(telemetryClient);
            }
            catch (OutOfMemoryException exception)
            {
                return(Clean(exception));
            }
            catch (System.Threading.Tasks.TaskSchedulerException exception)
            {
                return(Clean(exception));
            }
        }
コード例 #17
0
        /// <summary>
        /// Run Transformation on Import to the files in the database && Update fileHash in database
        /// </summary>
        /// <param name="queryUpdateDelegate"></param>
        /// <param name="fileIndexItem">information</param>
        /// <param name="colorClassTransformation">change colorClass</param>
        /// <param name="dateTimeParsedFromFileName">is date time parsed from fileName</param>
        /// <param name="indexMode">should update database</param>
        internal async Task <FileIndexItem> UpdateTransformations(QueryUpdateDelegate queryUpdateDelegate, FileIndexItem fileIndexItem,
                                                                  int colorClassTransformation, bool dateTimeParsedFromFileName, bool indexMode)
        {
            if (!ExtensionRolesHelper.IsExtensionExifToolSupported(fileIndexItem.FileName))
            {
                return(fileIndexItem);
            }

            var comparedNamesList = new List <string>();

            if (dateTimeParsedFromFileName)
            {
                _logger.LogInformation($"[Import] DateTimeParsedFromFileName ExifTool Sync {fileIndexItem.FilePath}");
                comparedNamesList = DateTimeParsedComparedNamesList();
            }

            if (colorClassTransformation >= 0)
            {
                _logger.LogInformation($"[Import] ColorClassComparedNamesList ExifTool Sync {fileIndexItem.FilePath}");
                comparedNamesList = ColorClassComparedNamesList(comparedNamesList);
            }

            if (!comparedNamesList.Any())
            {
                return(fileIndexItem);
            }

            await new ExifToolCmdHelper(_exifTool, _subPathStorage, _thumbnailStorage,
                                        new ReadMeta(_subPathStorage, _appSettings)).UpdateAsync(fileIndexItem, comparedNamesList);

            // Only update database when indexMode is true
            if (!indexMode || queryUpdateDelegate == null)
            {
                return(fileIndexItem);
            }

            // Hash is changed after transformation
            fileIndexItem.FileHash = (await new FileHash(_subPathStorage).GetHashCodeAsync(fileIndexItem.FilePath)).Key;
            await queryUpdateDelegate(fileIndexItem);

            return(fileIndexItem.Clone());
        }
コード例 #18
0
ファイル: ProcessTaskQueue.cs プロジェクト: qdraw/starsky
        public static async Task ProcessTaskQueueAsync(IBaseBackgroundTaskQueue taskQueue, IWebLogger logger, CancellationToken stoppingToken)
        {
            logger.LogInformation($"Queued Hosted Service {taskQueue.GetType().Name} is " +
                                  $"starting on {Environment.MachineName}");
            while (!stoppingToken.IsCancellationRequested)
            {
                var workItem = await taskQueue.DequeueAsync(stoppingToken);

                try
                {
                    await workItem(stoppingToken);
                }
                catch (Exception exception)
                {
                    logger.LogError(exception,
                                    $"Error occurred executing workItem ", nameof(workItem));
                }
            }
            logger.LogInformation("Queued Hosted Service has stopped");
        }
コード例 #19
0
        internal async Task WorkItem(string subPath, IStorage subPathStorage,
                                     IStorage thumbnailStorage)
        {
            try
            {
                _logger.LogInformation($"[ThumbnailGenerationController] start {subPath}");
                var thumbnail = new Thumbnail(subPathStorage,
                                              thumbnailStorage, _logger);
                var thumbs = await thumbnail.CreateThumb(subPath);

                var getAllFilesAsync = await _query.GetAllFilesAsync(subPath);

                var result = new List <FileIndexItem>();
                foreach (var item in
                         getAllFilesAsync.Where(item => thumbs.FirstOrDefault(p => p.Item1 == item.FilePath).Item2))
                {
                    if (item.Tags.Contains("!delete!"))
                    {
                        continue;
                    }

                    item.SetLastEdited();
                    result.Add(item);
                }

                if (!result.Any())
                {
                    return;
                }

                var webSocketResponse =
                    new ApiNotificationResponseModel <List <FileIndexItem> >(result, ApiNotificationType.ThumbnailGeneration);
                await _connectionsService.SendToAllAsync(webSocketResponse, CancellationToken.None);

                _logger.LogInformation($"[ThumbnailGenerationController] done {subPath}");
            }
            catch (UnauthorizedAccessException e)
            {
                _logger.LogError($"[ThumbnailGenerationController] catch-ed exception {e.Message}", e);
            }
        }
コード例 #20
0
        public async Task <bool> WriteAndCropFile(string fileHash,
                                                  OffsetModel offsetData, int sourceWidth,
                                                  int sourceHeight, FileIndexItem.Rotation rotation,
                                                  string reference = null)
        {
            try
            {
                using (var thumbnailStream = new MemoryStream(offsetData.Data, offsetData.Index, offsetData.Count))
                    using (var smallImage = await Image.LoadAsync(thumbnailStream))
                        using (var outputStream = new MemoryStream())
                        {
                            var smallImageWidth  = smallImage.Width;
                            var smallImageHeight = smallImage.Height;

                            var result = NewImageSize.NewImageSizeCalc(smallImageWidth,
                                                                       smallImageHeight, sourceWidth, sourceHeight);

                            smallImage.Mutate(
                                i => i.Resize(smallImageWidth, smallImageHeight, KnownResamplers.Lanczos3)
                                .Crop(new Rectangle(result.DestX, result.DestY, result.DestWidth, result.DestHeight)));

                            var larger = (int)Math.Round(result.DestWidth * 1.2, 0);

                            smallImage.Mutate(
                                i => i.Resize(larger, 0, KnownResamplers.Lanczos3));

                            var rotate = RotateEnumToDegrees(rotation);
                            smallImage.Mutate(
                                i => i.Rotate(rotate));

                            await smallImage.SaveAsJpegAsync(outputStream);

                            await _thumbnailStorage.WriteStreamAsync(outputStream, ThumbnailNameHelper.Combine(fileHash, ThumbnailSize.TinyMeta));

                            if (_appSettings.ApplicationType == AppSettings.StarskyAppType.WebController)
                            {
                                _logger.LogInformation($"[WriteAndCropFile] fileHash: {fileHash} is written");
                            }
                        }

                return(true);
            }
            catch (Exception ex)
            {
                var message = ex.Message;
                if (message.StartsWith("Image cannot be loaded"))
                {
                    message = "Image cannot be loaded";
                }
                _logger.LogError($"[WriteFile@meta] Exception {reference} {message}", ex);
                return(false);
            }
        }
コード例 #21
0
        /// <summary>
        /// This method is triggered by BackgroundService
        /// </summary>
        /// <param name="stoppingToken">ignored but required</param>
        /// <returns>Task/nothing</returns>
        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation((_appSettings.UseDiskWatcher != false ? $"UseDiskWatcher is enabled"
                                : "UseDiskWatcher is disabled") + $" on {Environment.MachineName}");
            if (_appSettings.UseDiskWatcher == false &&
                _appSettings.ApplicationType == AppSettings.StarskyAppType.WebController)
            {
                return(Task.CompletedTask);
            }

            _diskWatcher.Watcher(_appSettings.StorageFolder);
            return(Task.CompletedTask);
        }
コード例 #22
0
ファイル: ImportController.cs プロジェクト: qdraw/starsky
        internal async Task <List <ImportIndexItem> > ImportPostBackgroundTask(List <string> tempImportPaths,
                                                                               ImportSettingsModel importSettings, bool isVerbose = false)
        {
            List <ImportIndexItem> importedFiles;

            using (var scope = _scopeFactory.CreateScope())
            {
                var selectorStorage          = scope.ServiceProvider.GetRequiredService <ISelectorStorage>();
                var importQuery              = scope.ServiceProvider.GetRequiredService <IImportQuery>();
                var exifTool                 = scope.ServiceProvider.GetRequiredService <IExifTool>();
                var query                    = scope.ServiceProvider.GetRequiredService <IQuery>();
                var console                  = scope.ServiceProvider.GetRequiredService <IConsole>();
                var metaExifThumbnailService = scope.ServiceProvider.GetRequiredService <IMetaExifThumbnailService>();
                var memoryCache              = scope.ServiceProvider.GetRequiredService <IMemoryCache>();

                // use of IImport direct does not work
                importedFiles = await new Import(selectorStorage, _appSettings,
                                                 importQuery, exifTool, query, console,
                                                 metaExifThumbnailService, _logger, memoryCache).Importer(tempImportPaths, importSettings);
            }

            if (isVerbose)
            {
                foreach (var file in importedFiles)
                {
                    _logger.LogInformation(
                        $"[ImportPostBackgroundTask] import {file.Status} " +
                        $"=> {file.FilePath} ~ {file.FileIndexItem?.FilePath}");
                }
            }

            // Remove source files
            foreach (var toDelPath in tempImportPaths)
            {
                RemoveTempAndParentStreamFolder(toDelPath);
            }

            return(importedFiles);
        }
コード例 #23
0
ファイル: PublishController.cs プロジェクト: qdraw/starsky
        public IActionResult PublishCreate(string f, string itemName,
                                           string publishProfileName, bool force = false)
        {
            _webLogger.LogInformation($"[/api/publish/create] Press publish: {itemName} {f} {DateTime.UtcNow}");
            var inputFilePaths = PathHelper.SplitInputFilePaths(f).ToList();
            var info           = _metaInfo.GetInfo(inputFilePaths, false);

            if (info.All(p => p.Status != FileIndexItem.ExifStatus.Ok && p.Status != FileIndexItem.ExifStatus.ReadOnly))
            {
                return(NotFound(info));
            }

            var slugItemName = _appSettings.GenerateSlug(itemName, true);
            var location     = Path.Combine(_appSettings.TempFolder, slugItemName);

            if (CheckIfNameExist(slugItemName))
            {
                if (!force)
                {
                    return(Conflict($"name {slugItemName} exist"));
                }
                ForceCleanPublishFolderAndZip(location);
            }

            // todo: check if overlay image path: WebHtmlPublish/EmbeddedViews/default.png or something else exists

            // Creating Publish is a background task
            _bgTaskQueue.QueueBackgroundWorkItem(async token =>
            {
                var renderCopyResult = await _publishService.RenderCopy(info,
                                                                        publishProfileName, itemName, location);
                await _publishService.GenerateZip(_appSettings.TempFolder, itemName,
                                                  renderCopyResult, true);
                _webLogger.LogInformation($"[/api/publish/create] done: {itemName} {DateTime.UtcNow}");
            });

            // Get the zip  by	[HttpGet("/export/zip/{f}.zip")]
            return(Json(slugItemName));
        }
コード例 #24
0
ファイル: MetaUpdateController.cs プロジェクト: qdraw/starsky
        public async Task <IActionResult> UpdateAsync(FileIndexItem inputModel, string f, bool append,
                                                      bool collections = true, int rotateClock = 0)
        {
            var stopwatch = StopWatchLogger.StartUpdateReplaceStopWatch();

            var inputFilePaths = PathHelper.SplitInputFilePaths(f);

            var(fileIndexResultsList, changedFileIndexItemName) = await _metaPreflight.Preflight(inputModel,
                                                                                                 inputFilePaths, append, collections, rotateClock);

            var operationId = HttpContext.GetOperationId();

            // Update >
            _bgTaskQueue.QueueBackgroundWorkItem(async _ =>
            {
                var operationHolder = RequestTelemetryHelper.GetOperationHolder(_scopeFactory,
                                                                                nameof(UpdateAsync), operationId);

                var metaUpdateService = _scopeFactory.CreateScope()
                                        .ServiceProvider.GetRequiredService <IMetaUpdateService>();

                var data = await metaUpdateService.UpdateAsync(
                    changedFileIndexItemName, fileIndexResultsList, null,
                    collections, append, rotateClock);
                operationHolder.SetData(_scopeFactory, data);
            });

            // before sending not founds
            new StopWatchLogger(_logger).StopUpdateReplaceStopWatch("update", f, collections, stopwatch);

            // When all items are not found
            if (fileIndexResultsList.All(p => p.Status != FileIndexItem.ExifStatus.Ok &&
                                         p.Status != FileIndexItem.ExifStatus.Deleted))
            {
                return(NotFound(fileIndexResultsList));
            }

            // Clone an new item in the list to display
            var returnNewResultList = fileIndexResultsList.Select(item => item.Clone()).ToList();

            // when switching very fast between images the background task has not run yet
            _metaUpdateService.UpdateReadMetaCache(returnNewResultList);

            // Push direct to socket when update or replace to avoid undo after a second
            _logger.LogInformation($"[UpdateController] send to socket {f}");

            await Task.Run(async() => await TaskRun(fileIndexResultsList));

            return(Json(returnNewResultList));
        }
コード例 #25
0
ファイル: RunMigrations.cs プロジェクト: qdraw/starsky
        public static async Task Run(ApplicationDbContext dbContext, IWebLogger logger, AppSettings appSettings, int retryCount = 2)
        {
            async Task <bool> Migrate()
            {
                if (appSettings.DatabaseType == AppSettings.DatabaseTypeList.InMemoryDatabase)
                {
                    return(true);
                }


                await dbContext.Database.MigrateAsync();

                if (appSettings.DatabaseType !=
                    AppSettings.DatabaseTypeList.Mysql)
                {
                    return(true);
                }

                var connection    = new MySqlConnection(appSettings.DatabaseConnection);
                var databaseFixes =
                    new MySqlDatabaseFixes(connection, appSettings);
                await databaseFixes.OpenConnection();

                var tableNames = dbContext.Model.GetEntityTypes()
                                 .Select(t => t.GetTableName())
                                 .Distinct()
                                 .ToList();
                await databaseFixes.FixUtf8Encoding(tableNames);

                await databaseFixes.FixAutoIncrement("Notifications");

                return(true);
            }

            try
            {
                await RetryHelper.DoAsync(Migrate, TimeSpan.FromSeconds(2), retryCount);
            }
            catch (AggregateException exception)
            {
                logger.LogInformation("[RunMigrations] start migration failed");
                logger.LogError(exception.Message);
                logger.LogError(exception.InnerException?.Message);
                logger.LogError("[RunMigrations] end catch-ed");
            }
        }
コード例 #26
0
		public Task SendToAllAsync(string message, CancellationToken cancellationToken)
		{
			List<Task> connectionsTasks = new List<Task>();
			foreach (WebSocketConnection connection in _connections.Values)
			{
				try
				{
					connectionsTasks.Add(connection.SendAsync(message, cancellationToken));
				}
				catch ( WebSocketException exception)
				{
					// if the client is closing the socket the wrong way
					_logger.LogInformation(exception, "catch-ed exception socket");
				}
			}

			return Task.WhenAll(connectionsTasks);
		}
コード例 #27
0
        /// <summary>
        /// Test the connection if this is mysql
        /// </summary>
        /// <param name="context">database context</param>
        /// <param name="logger">logger</param>
        /// <returns>bool, true if connection is there</returns>
        /// <exception cref="ArgumentNullException">When AppSettings is null</exception>
        public static bool TestConnection(this DbContext context, IWebLogger logger)
        {
            if (context?.Database == null)
            {
                return(false);
            }

            try
            {
                context.Database.CanConnect();
            }
            catch (MySqlException e)
            {
                logger.LogInformation($"[TestConnection] WARNING >>> \n{e}\n <<<");
                return(false);
            }
            return(true);
        }
コード例 #28
0
        /// <summary>
        /// Based on the preflight create a Zip Export
        /// </summary>
        /// <param name="fileIndexResultsList">Result of Preflight</param>
        /// <param name="thumbnail">isThumbnail?</param>
        /// <param name="zipOutputFileName">filename of zip file (no extension)</param>
        /// <returns>nothing</returns>
        public async Task CreateZip(List <FileIndexItem> fileIndexResultsList, bool thumbnail,
                                    string zipOutputFileName)
        {
            var filePaths = await CreateListToExport(fileIndexResultsList, thumbnail);

            var fileNames = FilePathToFileName(filePaths, thumbnail);

            new Zipper().CreateZip(_appSettings.TempFolder, filePaths, fileNames, zipOutputFileName);

            // Write a single file to be sure that writing is ready
            var doneFileFullPath = Path.Combine(_appSettings.TempFolder, zipOutputFileName) + ".done";
            await _hostFileSystemStorage.
            WriteStreamAsync(new PlainTextFileHelper().StringToStream("OK"), doneFileFullPath);

            if (_appSettings.IsVerbose())
            {
                _logger.LogInformation("[CreateZip] Zip done: " + doneFileFullPath);
            }
        }
コード例 #29
0
ファイル: SetupDatebaseTypes.cs プロジェクト: qdraw/starsky
        public void BuilderDb(string?foundationDatabaseName = "")
        {
            if (_services == null)
            {
                throw new AggregateException("services is missing");
            }
            if (_logger != null && _appSettings.IsVerbose())
            {
                _logger.LogInformation($"Database connection: {_appSettings.DatabaseConnection}");
                _logger?.LogInformation($"Application Insights Database tracking is {IsDatabaseTrackingEnabled()}");
            }

#if ENABLE_DEFAULT_DATABASE
            // dirty hack
            _services.AddDbContext <ApplicationDbContext>(options =>
                                                          options.UseSqlite(_appSettings.DatabaseConnection,
                                                                            b =>
            {
                if (!string.IsNullOrWhiteSpace(foundationDatabaseName))
                {
                    b.MigrationsAssembly(foundationDatabaseName);
                }
            }));
#endif
#if ENABLE_MYSQL_DATABASE
            // dirty hack

            _services.AddDbContext <ApplicationDbContext>(options =>
                                                          options.UseMySql(_appSettings.DatabaseConnection, GetServerVersionMySql(),
                                                                           b =>
            {
                if (!string.IsNullOrWhiteSpace(foundationDatabaseName))
                {
                    b.MigrationsAssembly(foundationDatabaseName);
                }
            }));
#endif

            _services.AddScoped(provider => new ApplicationDbContext(BuilderDbFactorySwitch(foundationDatabaseName)));
        }
コード例 #30
0
        public async Task <NotificationItem> AddNotification(string content)
        {
            var item = new NotificationItem
            {
                DateTime = DateTime.UtcNow,
                Content  = content
            };

            try
            {
                await _context.Notifications.AddAsync(item);

                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException concurrencyException)
            {
                _logger.LogInformation("[AddNotification] try to fix DbUpdateConcurrencyException", concurrencyException);
                SolveConcurrency.SolveConcurrencyExceptionLoop(concurrencyException.Entries);
                await _context.SaveChangesAsync();
            }

            return(item);
        }