mirror of
				https://github.com/9ParsonsB/Pulsar.git
				synced 2025-11-03 23:36:42 -05:00 
			
		
		
		
	Merge branch 'master' of https://github.com/Xjph/ObservatoryCore
This commit is contained in:
		@@ -30,8 +30,9 @@ namespace Observatory
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            var docPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
 | 
					            var docPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
 | 
				
			||||||
            var errorMessage = new System.Text.StringBuilder();
 | 
					            var errorMessage = new System.Text.StringBuilder();
 | 
				
			||||||
 | 
					            var timestamp = DateTime.Now.ToString("G");
 | 
				
			||||||
            errorMessage
 | 
					            errorMessage
 | 
				
			||||||
                .AppendLine($"Error encountered in Elite Observatory {context}.")
 | 
					                .AppendLine($"[{timestamp}] Error encountered in Elite Observatory {context}")
 | 
				
			||||||
                .AppendLine(FormatExceptionMessage(ex))
 | 
					                .AppendLine(FormatExceptionMessage(ex))
 | 
				
			||||||
                .AppendLine();
 | 
					                .AppendLine();
 | 
				
			||||||
            System.IO.File.AppendAllText(docPath + System.IO.Path.DirectorySeparatorChar + "ObservatoryErrorLog.txt", errorMessage.ToString());
 | 
					            System.IO.File.AppendAllText(docPath + System.IO.Path.DirectorySeparatorChar + "ObservatoryErrorLog.txt", errorMessage.ToString());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,14 @@ namespace Observatory.PluginManagement
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public string Version => System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
 | 
					        public string Version => System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Action<Exception, String> GetPluginErrorLogger(IObservatoryPlugin plugin)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return (ex, context) =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ObservatoryCore.LogError(ex, $"from plugin {plugin.ShortName} {context}");
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Status GetStatus()
 | 
					        public Status GetStatus()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            throw new NotImplementedException();
 | 
					            throw new NotImplementedException();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,9 +12,12 @@ namespace Observatory.Explorer
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        private Lua LuaState;
 | 
					        private Lua LuaState;
 | 
				
			||||||
        private List<LuaFunction> CriteriaFunctions;
 | 
					        private List<LuaFunction> CriteriaFunctions;
 | 
				
			||||||
 | 
					        Action<Exception, String> ErrorLogger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public CustomCriteriaManager()
 | 
					
 | 
				
			||||||
 | 
					        public CustomCriteriaManager(Action<Exception, String> errorLogger)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            ErrorLogger = errorLogger;
 | 
				
			||||||
            CriteriaFunctions = new();
 | 
					            CriteriaFunctions = new();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -174,8 +177,14 @@ namespace Observatory.Explorer
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                originalScript = originalScript.Remove(originalScript.LastIndexOf(Environment.NewLine));
 | 
					                originalScript = originalScript.Remove(originalScript.LastIndexOf(Environment.NewLine));
 | 
				
			||||||
                originalScript = originalScript[(originalScript.IndexOf(Environment.NewLine) + Environment.NewLine.Length)..];
 | 
					                originalScript = originalScript[(originalScript.IndexOf(Environment.NewLine) + Environment.NewLine.Length)..];
 | 
				
			||||||
 | 
					                originalScript = originalScript.Replace('\t', ' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                throw new CriteriaLoadException(e.Message, originalScript.Replace('\t', ' '));
 | 
					                StringBuilder errorDetail = new();
 | 
				
			||||||
 | 
					                errorDetail.AppendLine("Error Reading Custom Criteria File:")
 | 
				
			||||||
 | 
					                    .AppendLine(originalScript)
 | 
				
			||||||
 | 
					                    .AppendLine("NOTE: Custom criteria processing has been disable to prevent further errors.");
 | 
				
			||||||
 | 
					                ErrorLogger(e, errorDetail.ToString());
 | 
				
			||||||
 | 
					                throw new CriteriaLoadException(e.Message, originalScript);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -236,6 +245,12 @@ namespace Observatory.Explorer
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    settings.EnableCustomCriteria = false;
 | 
					                    settings.EnableCustomCriteria = false;
 | 
				
			||||||
                    results.Add((e.Message, scan.Json, false));
 | 
					                    results.Add((e.Message, scan.Json, false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    StringBuilder errorDetail = new();
 | 
				
			||||||
 | 
					                    errorDetail.AppendLine("while processing a custom criteria on scan:")
 | 
				
			||||||
 | 
					                        .AppendLine(scan.Json)
 | 
				
			||||||
 | 
					                        .AppendLine("NOTE: Custom criteria process has been disabled to prevent further errors.");
 | 
				
			||||||
 | 
					                    ErrorLogger(e, errorDetail.ToString());
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@ namespace Observatory.Explorer
 | 
				
			|||||||
            ExplorerWorker = explorerWorker;
 | 
					            ExplorerWorker = explorerWorker;
 | 
				
			||||||
            ObservatoryCore = core;
 | 
					            ObservatoryCore = core;
 | 
				
			||||||
            Results = results;
 | 
					            Results = results;
 | 
				
			||||||
            CustomCriteriaManager = new();
 | 
					            CustomCriteriaManager = new(core.GetPluginErrorLogger(explorerWorker));
 | 
				
			||||||
            CriteriaLastModified = new DateTime(0);
 | 
					            CriteriaLastModified = new DateTime(0);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -174,6 +174,13 @@ namespace Observatory.Framework.Interfaces
 | 
				
			|||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        public string Version { get; }
 | 
					        public string Version { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Returns a delegate for logging an error for the calling plugin. A plugin can wrap this method
 | 
				
			||||||
 | 
					        /// or pass it along to its collaborators.
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="plugin">The calling plugin</param>
 | 
				
			||||||
 | 
					        public Action<Exception, String> GetPluginErrorLogger (IObservatoryPlugin plugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Perform an action on the current Avalonia UI thread.
 | 
					        /// Perform an action on the current Avalonia UI thread.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,8 +53,9 @@ namespace Observatory.Herald
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        public void Load(IObservatoryCore observatoryCore)
 | 
					        public void Load(IObservatoryCore observatoryCore)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var speechManager = new SpeechRequestManager(heraldSettings, observatoryCore.HttpClient, observatoryCore.PluginStorageFolder);
 | 
					            var speechManager = new SpeechRequestManager(
 | 
				
			||||||
            heraldSpeech = new HeraldQueue(speechManager);
 | 
					                heraldSettings, observatoryCore.HttpClient, observatoryCore.PluginStorageFolder, observatoryCore.GetPluginErrorLogger(this));
 | 
				
			||||||
 | 
					            heraldSpeech = new HeraldQueue(speechManager, observatoryCore.GetPluginErrorLogger(this));
 | 
				
			||||||
            heraldSettings.Test = TestVoice;
 | 
					            heraldSettings.Test = TestVoice;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@ using System.Threading.Tasks;
 | 
				
			|||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using NetCoreAudio;
 | 
					using NetCoreAudio;
 | 
				
			||||||
using System.Threading;
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Diagnostics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Observatory.Herald
 | 
					namespace Observatory.Herald
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -17,13 +19,15 @@ namespace Observatory.Herald
 | 
				
			|||||||
        private byte volume;
 | 
					        private byte volume;
 | 
				
			||||||
        private SpeechRequestManager speechManager;
 | 
					        private SpeechRequestManager speechManager;
 | 
				
			||||||
        private Player audioPlayer;
 | 
					        private Player audioPlayer;
 | 
				
			||||||
 | 
					        private Action<Exception, String> ErrorLogger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public HeraldQueue(SpeechRequestManager speechManager)
 | 
					        public HeraldQueue(SpeechRequestManager speechManager, Action<Exception, String> errorLogger)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this.speechManager = speechManager;
 | 
					            this.speechManager = speechManager;
 | 
				
			||||||
            processing = false;
 | 
					            processing = false;
 | 
				
			||||||
            notifications = new();
 | 
					            notifications = new();
 | 
				
			||||||
            audioPlayer = new();
 | 
					            audioPlayer = new();
 | 
				
			||||||
 | 
					            ErrorLogger = errorLogger;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -56,36 +60,47 @@ namespace Observatory.Herald
 | 
				
			|||||||
        private void ProcessQueue()
 | 
					        private void ProcessQueue()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (notifications.Any())
 | 
					            NotificationArgs notification = null;
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                audioPlayer.SetVolume(volume).Wait();
 | 
					                while (notifications.Any())
 | 
				
			||||||
                var notification = notifications.Dequeue();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                Task<string>[] audioRequestTasks = new Task<string> [2];
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (string.IsNullOrWhiteSpace(notification.TitleSsml))
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    audioRequestTasks[0] = RetrieveAudioToFile(notification.Title);
 | 
					                    audioPlayer.SetVolume(volume).Wait();
 | 
				
			||||||
                }
 | 
					                    notification = notifications.Dequeue();
 | 
				
			||||||
                else
 | 
					                    Debug.WriteLine("Processing notification: {0} - {1}", notification.Title, notification.Detail);
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    audioRequestTasks[0] = RetrieveAudioSsmlToFile(notification.TitleSsml);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (string.IsNullOrWhiteSpace(notification.DetailSsml))
 | 
					                    Task<string>[] audioRequestTasks = new Task<string>[2];
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    audioRequestTasks[1] = RetrieveAudioToFile(notification.Detail);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    audioRequestTasks[1] = RetrieveAudioSsmlToFile(notification.DetailSsml);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                PlayAudioRequestsSequentially(audioRequestTasks);
 | 
					                    if (string.IsNullOrWhiteSpace(notification.TitleSsml))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        audioRequestTasks[0] = RetrieveAudioToFile(notification.Title);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        audioRequestTasks[0] = RetrieveAudioSsmlToFile(notification.TitleSsml);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (string.IsNullOrWhiteSpace(notification.DetailSsml))
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        audioRequestTasks[1] = RetrieveAudioToFile(notification.Detail);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        audioRequestTasks[1] = RetrieveAudioSsmlToFile(notification.DetailSsml);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    PlayAudioRequestsSequentially(audioRequestTasks);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Debug.WriteLine($"Failed to fetch/play notification: {notification?.Title} - {notification?.Detail}");
 | 
				
			||||||
 | 
					                ErrorLogger(ex, "while retrieving and playing audio for a notification");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            finally
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                processing = false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            processing = false;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private async Task<string> RetrieveAudioToFile(string text)
 | 
					        private async Task<string> RetrieveAudioToFile(string text)
 | 
				
			||||||
@@ -103,7 +118,15 @@ namespace Observatory.Herald
 | 
				
			|||||||
            foreach (var request in requestTasks)
 | 
					            foreach (var request in requestTasks)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                string file = request.Result;
 | 
					                string file = request.Result;
 | 
				
			||||||
                audioPlayer.Play(file).Wait();
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Debug.WriteLine($"Playing audio file: {file}");
 | 
				
			||||||
 | 
					                    audioPlayer.Play(file).Wait();
 | 
				
			||||||
 | 
					                } catch (Exception ex)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Debug.WriteLine($"Failed to play {file}: {ex.Message}");
 | 
				
			||||||
 | 
					                    ErrorLogger(ex, $"while playing: {file}");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while (audioPlayer.Playing)
 | 
					                while (audioPlayer.Playing)
 | 
				
			||||||
                    Thread.Sleep(50);
 | 
					                    Thread.Sleep(50);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,14 +19,17 @@ namespace Observatory.Herald
 | 
				
			|||||||
        private string ApiEndpoint;
 | 
					        private string ApiEndpoint;
 | 
				
			||||||
        private DirectoryInfo cacheLocation;
 | 
					        private DirectoryInfo cacheLocation;
 | 
				
			||||||
        private int cacheSize;
 | 
					        private int cacheSize;
 | 
				
			||||||
 | 
					        private Action<Exception, String> ErrorLogger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        internal SpeechRequestManager(HeraldSettings settings, HttpClient httpClient, string cacheFolder)
 | 
					        internal SpeechRequestManager(
 | 
				
			||||||
 | 
					            HeraldSettings settings, HttpClient httpClient, string cacheFolder, Action<Exception, String> errorLogger)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ApiKey = ObservatoryAPI.ApiKey;
 | 
					            ApiKey = ObservatoryAPI.ApiKey;
 | 
				
			||||||
            ApiEndpoint = settings.ApiEndpoint;
 | 
					            ApiEndpoint = settings.ApiEndpoint;
 | 
				
			||||||
            this.httpClient = httpClient;
 | 
					            this.httpClient = httpClient;
 | 
				
			||||||
            cacheSize = Math.Max(settings.CacheSize, 1);
 | 
					            cacheSize = Math.Max(settings.CacheSize, 1);
 | 
				
			||||||
            cacheLocation = new DirectoryInfo(cacheFolder);
 | 
					            cacheLocation = new DirectoryInfo(cacheFolder);
 | 
				
			||||||
 | 
					            ErrorLogger = errorLogger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!Directory.Exists(cacheLocation.FullName))
 | 
					            if (!Directory.Exists(cacheLocation.FullName))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -49,7 +52,19 @@ namespace Observatory.Herald
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var audioFilename = cacheLocation + ssmlHash + ".mp3";
 | 
					            var audioFilename = cacheLocation + ssmlHash + ".mp3";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!File.Exists(audioFilename))
 | 
					            FileInfo audioFileInfo = null;
 | 
				
			||||||
 | 
					            if (File.Exists(audioFilename))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                audioFileInfo = new FileInfo(audioFilename);
 | 
				
			||||||
 | 
					                if (audioFileInfo.Length == 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    File.Delete(audioFilename);
 | 
				
			||||||
 | 
					                    audioFileInfo = null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (audioFileInfo == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                using StringContent request = new(ssml)
 | 
					                using StringContent request = new(ssml)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -71,10 +86,10 @@ namespace Observatory.Herald
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    throw new PluginException("Herald", "Unable to retrieve audio data.", new Exception(response.StatusCode.ToString() + ": " + response.ReasonPhrase));
 | 
					                    throw new PluginException("Herald", "Unable to retrieve audio data.", new Exception(response.StatusCode.ToString() + ": " + response.ReasonPhrase));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                audioFileInfo = new FileInfo(audioFilename);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            UpdateAndPruneCache(new FileInfo(audioFilename));
 | 
					            UpdateAndPruneCache(audioFileInfo);
 | 
				
			||||||
                        
 | 
					                        
 | 
				
			||||||
            return audioFilename;
 | 
					            return audioFilename;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -231,6 +246,7 @@ namespace Observatory.Herald
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    Console.WriteLine(ex.Message);
 | 
					                    Console.WriteLine(ex.Message);
 | 
				
			||||||
                    cacheIndex = new();
 | 
					                    cacheIndex = new();
 | 
				
			||||||
 | 
					                    ErrorLogger(ex, "deserializing CacheIndex.json");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user