using Microsoft.UI.Xaml; using Renci.SshNet; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.Json.Serialization; using Windows.ApplicationModel.VoiceCommands; using Windows.Storage.Search; namespace wakka { public class FeelsPost { [JsonPropertyName("user")] public required string User { get; set; } [JsonPropertyName("path")] public required string Path { get; set; } [JsonPropertyName("m_time")] public required long M_Time { get; set; } [JsonPropertyName("reported_date")] public required long ReportedDate { get; set; } public string TimeString { get; set; } = string.Empty; public string Body { get; set; } = string.Empty; public int WordCount { get; set; } = 0; } public static class Feels { public static readonly ObservableCollection LoadedFeelsPosts = []; private static DispatcherTimer? Timer = null; private static List>? LoadTimeMetadata = null; private static int CurrentChunk = 0; public static void Initialize() { if (Timer == null) StartTimer(); if (LoadTimeMetadata == null) { var feels = AllFeels(); if (feels != null) { LoadTimeMetadata = (List>)feels.Chunk(10).Select(chunk => chunk.ToList()).ToList(); LoadFeelsChunk(); } } } public static void LoadFeelsChunk() { if (LoadTimeMetadata == null) return; var chunk = LoadTimeMetadata[CurrentChunk]; foreach (var feel in chunk) { ConstructFeel(feel); LoadedFeelsPosts.Add(feel); } CurrentChunk++; } private static void StartTimer() { Timer = new DispatcherTimer(); Timer.Interval = TimeSpan.FromSeconds(20); Timer.Tick += Timer_Tick; Timer.Start(); } private static void Timer_Tick(object? sender, object? e) { GetNewFeels(); } public static void GetNewFeels() { var newFeels = FeelsAfter(LoadedFeelsPosts[0].M_Time); if (newFeels != null) { var additions = new List(); foreach (var newFeel in newFeels) { ConstructFeel(newFeel); FeelsPost? toRemove = null; foreach (var liveFeel in LoadedFeelsPosts) { if (liveFeel.Path.Equals(newFeel.Path)) { toRemove = liveFeel; break; } } if (toRemove != null) LoadedFeelsPosts.Remove(toRemove); additions.Add(newFeel); } additions.Reverse(); foreach (var feel in additions) { LoadedFeelsPosts.Insert(0, feel); } } } public static string GetTodayFeelPath() { var dateString = DateTime.Now.ToString("yyyyMMdd"); return $"/home/{SshConnection.User}/.ttbp/entries/{dateString}.txt"; } public static string GetTodayFeelBody() { return SshConnection.RunCommand($"cat {GetTodayFeelPath()}"); } public static void PostFeel(string body) { SshConnection.RunCommandWithInput($"cat > {GetTodayFeelPath()}", body); } public static List? AllFeels() { return JsonSerializer.Deserialize>(SshConnection.RunCommand("~nebula/bin/dumpfeels")); } public static List? FeelsAfter(long TimeStamp) { return JsonSerializer.Deserialize>(SshConnection.RunCommand($"~nebula/bin/dumpfeels --after {TimeStamp}")); } public static List? FeelsFromUser(string User, List Feels) { return Feels.FindAll(i => i.User == User); } public static string GetFeelsBody(FeelsPost Post) { return SshConnection.RunCommand($"cat {Post.Path}"); } private static void ConstructFeel(FeelsPost feel) { var date = DateTimeOffset.FromUnixTimeSeconds(feel.M_Time).DateTime.ToLocalTime(); feel.TimeString = date.ToString("HH:mm (dddd, MMMM dd, yyyy)"); var body = GetFeelsBody(feel); char[] delimiters = new char[] { ' ', '\n' }; feel.WordCount = body.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).Length; feel.Body = body; } } }