pushing stuff

This commit is contained in:
nebula 2025-05-17 19:17:45 -05:00
parent cb4f70de6e
commit 8a38300cf1
15 changed files with 348 additions and 163 deletions

View File

@ -3,6 +3,8 @@ using Microsoft.UI.Xaml.Controls;
using System; using System;
using System.IO; using System.IO;
using WinUIEx; using WinUIEx;
using Microsoft.Windows.AppNotifications;
// To learn more about WinUI, the WinUI project structure, // To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info. // and more about our project templates, see: http://aka.ms/winui-project-info.

84
Bink.cs
View File

@ -1,4 +1,7 @@
using System.Collections.Generic; using Microsoft.UI.Xaml;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
@ -7,36 +10,89 @@ namespace wakka
public class BinkPost public class BinkPost
{ {
[JsonPropertyName("user")] [JsonPropertyName("user")]
public string? User { get; set; } public required string User { get; set; }
[JsonPropertyName("body")] [JsonPropertyName("body")]
public string? Body { get; set; } public required string Body { get; set; }
[JsonPropertyName("time")] [JsonPropertyName("time")]
public long Time { get; set; } public required long Time { get; set; }
public string TimeString { get; set; } = string.Empty; public string TimeString { get; set; } = string.Empty;
} }
public class Bink public static class Bink
{ {
private static SshConnection Ssh { get; set; } = new SshConnection(); private static DispatcherTimer? timer = null;
public static readonly ObservableCollection<BinkPost> LoadedBinks = [];
private static List<BinkPost>? BinkData = null;
public void PostBink(string message) public static void Initialize()
{ {
Ssh.RunCommandWithInput("town bink --pipe", message); if (timer == null)
StartTimer();
if (BinkData == null)
{
BinkData = AllBinks();
if (BinkData != null)
{
foreach (var bink in BinkData)
{
SetBinkDateString(bink);
LoadedBinks.Add(bink);
}
}
}
} }
public List<BinkPost>? AllBinks() public static void PostBink(string message)
{ {
return JsonSerializer.Deserialize<List<BinkPost>>(Ssh.RunCommand("town bink --dump")); SshConnection.RunCommandWithInput("town bink --pipe", message);
} }
public List<BinkPost>? BinksBefore(long TimeStamp) public static List<BinkPost>? AllBinks()
{ {
return JsonSerializer.Deserialize<List<BinkPost>>(Ssh.RunCommand($"town bink --dump-before {TimeStamp}")); return JsonSerializer.Deserialize<List<BinkPost>>(SshConnection.RunCommand("town bink --dump"));
} }
public List<BinkPost>? BinksAfter(long TimeStamp) public static List<BinkPost>? BinksBefore(long TimeStamp)
{ {
return JsonSerializer.Deserialize<List<BinkPost>>(Ssh.RunCommand($"town bink --dump-after {TimeStamp}")); return JsonSerializer.Deserialize<List<BinkPost>>(SshConnection.RunCommand($"town bink --dump-before {TimeStamp}"));
}
public static List<BinkPost>? BinksAfter(long TimeStamp)
{
return JsonSerializer.Deserialize<List<BinkPost>>(SshConnection.RunCommand($"town bink --dump-after {TimeStamp}"));
}
public static void SetBinkDateString(BinkPost bink)
{
var date = DateTimeOffset.FromUnixTimeSeconds(bink.Time / 1000000000).DateTime.ToLocalTime();
bink.TimeString = date.ToString("HH:mm (dddd, MMMM dd, yyyy)");
}
public static void GetNewBinks()
{
var BinkList = BinksAfter(LoadedBinks[0].Time);
if (BinkList != null)
{
BinkList.Reverse();
foreach (var bink in BinkList)
{
SetBinkDateString(bink);
LoadedBinks.Insert(0, bink);
}
}
}
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)
{
GetNewBinks();
} }
} }
} }

View File

@ -15,8 +15,8 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<CommandBar DefaultLabelPosition="Right" Grid.Row="0"> <CommandBar DefaultLabelPosition="Right" Grid.Row="0">
<AppBarButton Icon="Refresh" Label="Update" Click="GetNewBinksButton" /> <AppBarButton Icon="Refresh" Label="Update" Click="RefreshButton" />
<AppBarButton Icon="Add" Label="Post" Click="OnBinkCreate" /> <AppBarButton Icon="Add" Label="Post" Click="OnBinkCreateButton" />
</CommandBar> </CommandBar>
<ContentDialog <ContentDialog

View File

@ -1,12 +1,6 @@
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Org.BouncyCastle.Tls;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Threading;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
// To learn more about WinUI, the WinUI project structure, // To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info. // and more about our project templates, see: http://aka.ms/winui-project-info.
@ -18,44 +12,12 @@ namespace wakka
/// </summary> /// </summary>
public sealed partial class BinkPage : Page public sealed partial class BinkPage : Page
{ {
private DispatcherTimer timer;
private readonly ObservableCollection<BinkPost> Binks = [];
private static Bink Bink { get; set; } = new Bink();
public BinkPage() public BinkPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
StartTimer(); binksListView.ItemsSource = Bink.LoadedBinks;
var BinkList = Bink.AllBinks();
if (BinkList != null)
{
foreach (var bink in BinkList)
{
SetBinkDateString(bink);
Binks.Add(bink);
}
}
binksListView.ItemsSource = Binks;
}
public void SetBinkDateString (BinkPost bink)
{
var date = DateTimeOffset.FromUnixTimeSeconds(bink.Time / 1000000000).DateTime.ToLocalTime();
bink.TimeString = date.ToString("HH:mm (dddd, MMMM dd, yyyy)");
}
public void GetNewBinks()
{
var BinkList = Bink.BinksAfter(Binks[0].Time);
if (BinkList != null)
{
BinkList.Reverse();
foreach (var bink in BinkList)
{
SetBinkDateString(bink);
Binks.Insert(0, bink);
}
}
} }
private void BinkSubmit(ContentDialog sender, ContentDialogButtonClickEventArgs args) private void BinkSubmit(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{ {
var message = binkComposeBox.Text; var message = binkComposeBox.Text;
@ -63,10 +25,10 @@ namespace wakka
{ {
Bink.PostBink(message); Bink.PostBink(message);
binkComposeBox.Text = string.Empty; binkComposeBox.Text = string.Empty;
GetNewBinks(); Bink.GetNewBinks();
}
} }
}
private void OnTextChanged(object sender, TextChangedEventArgs e) private void OnTextChanged(object sender, TextChangedEventArgs e)
{ {
if (string.IsNullOrEmpty(binkComposeBox.Text)) if (string.IsNullOrEmpty(binkComposeBox.Text))
@ -79,27 +41,16 @@ namespace wakka
} }
} }
private async void OnBinkCreate(object sender, RoutedEventArgs e) private async void OnBinkCreateButton(object sender, RoutedEventArgs e)
{ {
binkComposeDialog.IsPrimaryButtonEnabled = false; binkComposeDialog.IsPrimaryButtonEnabled = false;
await binkComposeDialog.ShowAsync(); await binkComposeDialog.ShowAsync();
} }
public void GetNewBinksButton(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) public void RefreshButton(object sender, RoutedEventArgs e)
{ {
GetNewBinks(); Bink.GetNewBinks();
} }
private void StartTimer()
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(20);
timer.Tick += Timer_Tick;
timer.Start();
}
private void Timer_Tick(object? sender, object? e)
{
GetNewBinks();
}
} }
} }

139
Feels.cs
View File

@ -1,44 +1,157 @@
using System.Collections.Generic; 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;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Windows.ApplicationModel.VoiceCommands;
using Windows.Storage.Search;
namespace wakka namespace wakka
{ {
public class FeelsPost public class FeelsPost
{ {
[JsonPropertyName("user")] [JsonPropertyName("user")]
public string? User { get; set; } public required string User { get; set; }
[JsonPropertyName("path")] [JsonPropertyName("path")]
public string? Path { get; set; } public required string Path { get; set; }
[JsonPropertyName("m_time")] [JsonPropertyName("m_time")]
public long M_Time { get; set; } 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 TimeString { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty; public string Body { get; set; } = string.Empty;
public int WordCount { get; set; } = 0; public int WordCount { get; set; } = 0;
} }
internal class Feels public static class Feels
{ {
private static SshConnection Ssh { get; set; } = new SshConnection(); public static readonly ObservableCollection<FeelsPost> LoadedFeelsPosts = [];
private static DispatcherTimer? Timer = null;
private static List<List<FeelsPost>>? LoadTimeMetadata = null;
private static int CurrentChunk = 0;
public List<FeelsPost>? AllFeels() public static void Initialize()
{ {
return JsonSerializer.Deserialize<List<FeelsPost>>(Ssh.RunCommand("~nebula/bin/dumpfeels")); if (Timer == null)
StartTimer();
if (LoadTimeMetadata == null)
{
var feels = AllFeels();
if (feels != null)
{
LoadTimeMetadata = (List<List<FeelsPost>>)feels.Chunk(10).Select(chunk => chunk.ToList()).ToList();
LoadFeelsChunk();
}
}
} }
public List<FeelsPost>? FeelsAfter(long TimeStamp) public static void LoadFeelsChunk()
{ {
return JsonSerializer.Deserialize<List<FeelsPost>>(Ssh.RunCommand($"~nebula/bin/dumpfeels --after {TimeStamp}")); if (LoadTimeMetadata == null)
return;
var chunk = LoadTimeMetadata[CurrentChunk];
foreach (var feel in chunk)
{
ConstructFeel(feel);
LoadedFeelsPosts.Add(feel);
}
CurrentChunk++;
} }
public List<FeelsPost>? FeelsFromUser(string User, List<FeelsPost> Feels) 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<FeelsPost>();
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<FeelsPost>? AllFeels()
{
return JsonSerializer.Deserialize<List<FeelsPost>>(SshConnection.RunCommand("~nebula/bin/dumpfeels"));
}
public static List<FeelsPost>? FeelsAfter(long TimeStamp)
{
return JsonSerializer.Deserialize<List<FeelsPost>>(SshConnection.RunCommand($"~nebula/bin/dumpfeels --after {TimeStamp}"));
}
public static List<FeelsPost>? FeelsFromUser(string User, List<FeelsPost> Feels)
{ {
return Feels.FindAll(i => i.User == User); return Feels.FindAll(i => i.User == User);
} }
public string GetFeelsBody(FeelsPost Post) public static string GetFeelsBody(FeelsPost Post)
{ {
return Ssh.RunCommand($"cat {Post.Path}"); 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;
} }
} }
} }

View File

@ -11,10 +11,10 @@
<Grid> <Grid>
<ScrollViewer x:Name="scrollViewer" ViewChanged="ViewChanged"> <ScrollViewer x:Name="scrollViewer" ViewChanged="ViewChanged">
<ListView Grid.Row="0" x:Name="feelsListView" SelectionMode="None"> <ListView x:Name="feelsListView" SelectionMode="None">
<ListView.ItemTemplate> <ListView.ItemTemplate>
<DataTemplate x:DataType="local:FeelsPost"> <DataTemplate x:DataType="local:FeelsPost">
<Expander Width="600" Margin="0,10,0,10" IsExpanded="True" CornerRadius="8"> <Expander HorizontalAlignment="Left" MaxWidth="1200" Margin="0,10,0,10" IsExpanded="True" CornerRadius="8">
<Expander.Header> <Expander.Header>
<StackPanel Margin="10,10,10,10" HorizontalAlignment="Left"> <StackPanel Margin="10,10,10,10" HorizontalAlignment="Left">
<StackPanel Padding="0,0,0,5" Orientation="Horizontal"> <StackPanel Padding="0,0,0,5" Orientation="Horizontal">

View File

@ -1,8 +1,10 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Microsoft.Windows.AppNotifications;
// To learn more about WinUI, the WinUI project structure, // To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info. // and more about our project templates, see: http://aka.ms/winui-project-info.
@ -14,34 +16,10 @@ namespace wakka
/// </summary> /// </summary>
public sealed partial class FeelsFeedPage : Page public sealed partial class FeelsFeedPage : Page
{ {
private readonly Feels Feels = new Feels();
private readonly ObservableCollection<FeelsPost> LiveFeelsPosts = [];
private readonly List<List<FeelsPost>> AllFeels;
private int CurrentChunk = 0;
public FeelsFeedPage() public FeelsFeedPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
var feels = Feels.AllFeels(); feelsListView.ItemsSource = Feels.LoadedFeelsPosts;
AllFeels = (List<List<FeelsPost>>)feels.Chunk(4).Select(chunk => chunk.ToList()).ToList();
LoadFeelsChunk();
feelsListView.ItemsSource = LiveFeelsPosts;
}
private void LoadFeelsChunk()
{
var chunk = AllFeels[CurrentChunk];
foreach (var feel in chunk)
{
var date = DateTimeOffset.FromUnixTimeSeconds(feel.M_Time).DateTime.ToLocalTime();
feel.TimeString = date.ToString("HH:mm (dddd, MMMM dd, yyyy)");
var body = Feels.GetFeelsBody(feel);
char[] delimiters = new char[] { ' ', '\n' };
feel.WordCount = body.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).Length;
feel.Body = body;
LiveFeelsPosts.Add(feel);
}
CurrentChunk++;
} }
private void ViewChanged(object sender, ScrollViewerViewChangedEventArgs e) private void ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
@ -51,7 +29,7 @@ namespace wakka
{ {
if (scrollViewer.VerticalOffset >= scrollViewer.ScrollableHeight) if (scrollViewer.VerticalOffset >= scrollViewer.ScrollableHeight)
{ {
LoadFeelsChunk(); Feels.LoadFeelsChunk();
} }
} }
} }

View File

@ -14,11 +14,34 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<SelectorBar Grid.Row="0" x:Name="feelsSelectorBar" SelectionChanged="SelectorChanged"> <Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<SelectorBar Grid.Column="0" x:Name="feelsSelectorBar" SelectionChanged="SelectorChanged">
<SelectorBarItem x:Name="feedSelectorBarItem" Text="Feed" IsSelected="True" /> <SelectorBarItem x:Name="feedSelectorBarItem" Text="Feed" IsSelected="True" />
<!--<SelectorBarItem x:Name="usersSelectorBarItem" Text="Users" />--> <!--<SelectorBarItem x:Name="usersSelectorBarItem" Text="Users" />-->
</SelectorBar> </SelectorBar>
<CommandBar Grid.Column="1" DefaultLabelPosition="Right" HorizontalAlignment="Right" x:Name="feelsCommandBar">
<AppBarButton Icon="Add" Label="New Feel" Click="OnFeelsCreateButton"/>
</CommandBar>
</Grid>
<Frame Grid.Row="1" x:Name="FeelsNavigationFrame" IsNavigationStackEnabled="False" /> <Frame Grid.Row="1" x:Name="FeelsNavigationFrame" IsNavigationStackEnabled="False" />
<ContentDialog
x:Name="feelsComposeDialog"
Title="New Feels"
PrimaryButtonText="Post"
CloseButtonText="Cancel"
PrimaryButtonClick="OnFeelsSubmitButton">
<TextBox
PlaceholderText="Your feels here..."
Width="700"
Height="300"
TextWrapping="Wrap"
AcceptsReturn="True"
TextChanged="OnTextChanged"
x:Name="feelsComposeBox"/>
</ContentDialog>
</Grid> </Grid>
</Page> </Page>

View File

@ -1,18 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives; using System;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.UI.Xaml.Media.Animation;
// To learn more about WinUI, the WinUI project structure, // To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info. // and more about our project templates, see: http://aka.ms/winui-project-info.
@ -33,5 +20,44 @@ namespace wakka
{ {
FeelsNavigationFrame.Navigate(typeof(FeelsFeedPage)); FeelsNavigationFrame.Navigate(typeof(FeelsFeedPage));
} }
private async void OnFeelsCreateButton(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
var path = Feels.GetTodayFeelPath();
if (SshConnection.DoesFileExist(path))
{
feelsComposeBox.Text = SshConnection.RunCommand($"cat {path}");
feelsComposeDialog.IsPrimaryButtonEnabled = true;
}
else
{
feelsComposeBox.Text = string.Empty;
feelsComposeDialog.IsPrimaryButtonEnabled = false;
}
await feelsComposeDialog.ShowAsync();
}
private void OnFeelsSubmitButton(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
var message = feelsComposeBox.Text;
if (!string.IsNullOrEmpty(message))
{
Feels.PostFeel(message);
feelsComposeBox.Text = string.Empty;
Feels.GetNewFeels();
}
}
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
if (string.IsNullOrEmpty(feelsComposeBox.Text))
{
feelsComposeDialog.IsPrimaryButtonEnabled = false;
}
else
{
feelsComposeDialog.IsPrimaryButtonEnabled = true;
}
}
} }
} }

View File

@ -13,18 +13,19 @@ namespace wakka
public sealed partial class MainWindow : Window public sealed partial class MainWindow : Window
{ {
private static SshConnection Ssh { get; set; } = new SshConnection();
public Frame RootFrame; public Frame RootFrame;
public MainWindow() public MainWindow()
{ {
this.InitializeComponent(); this.InitializeComponent();
RootFrame = rootFrame; RootFrame = rootFrame;
Ssh.DeleteSshKey(); //Ssh.DeleteSshKey();
if (Ssh.KeyExists() & (string)App.LocalSettingsData.Values["username"] != null) if (SshConnection.KeyExists() & (string)App.LocalSettingsData.Values["username"] != null)
{ {
try try
{ {
Ssh.InitializeConnection((string)App.LocalSettingsData.Values["username"]); SshConnection.InitializeConnection((string)App.LocalSettingsData.Values["username"]);
Bink.Initialize();
Feels.Initialize();
RootFrame.Content = new NavigationPage(); RootFrame.Content = new NavigationPage();
} }
catch (Renci.SshNet.Common.SshAuthenticationException) catch (Renci.SshNet.Common.SshAuthenticationException)

View File

@ -34,10 +34,12 @@ namespace wakka
{ {
if (selectedItem == binkPageNav) if (selectedItem == binkPageNav)
{ {
Bink.GetNewBinks();
navigationFrame.Navigate(typeof(BinkPage)); navigationFrame.Navigate(typeof(BinkPage));
} }
else if (selectedItem == feelsPageNav) else if (selectedItem == feelsPageNav)
{ {
Feels.GetNewFeels();
navigationFrame.Navigate(typeof(FeelsNavigationPage)); navigationFrame.Navigate(typeof(FeelsNavigationPage));
} }
} }

View File

@ -5,12 +5,14 @@
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
IgnorableNamespaces="uap rescap"> IgnorableNamespaces="uap rescap">
<Identity <Identity
Name="8edc9fec-3276-4986-bbf6-5074643d2fdc" Name="8edc9fec-3276-4986-bbf6-5074643d2fdc"
Publisher="CN=helix" Publisher="CN=helixnebula"
Version="1.0.0.0" /> Version="0.0.1.0" />
<mp:PhoneIdentity PhoneProductId="8edc9fec-3276-4986-bbf6-5074643d2fdc" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> <mp:PhoneIdentity PhoneProductId="8edc9fec-3276-4986-bbf6-5074643d2fdc" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
@ -42,6 +44,23 @@
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square71x71Logo="Assets\SmallTile.png" Square310x310Logo="Assets\LargeTile.png"/> <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square71x71Logo="Assets\SmallTile.png" Square310x310Logo="Assets\LargeTile.png"/>
<uap:SplashScreen Image="Assets\SplashScreen.png" /> <uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements> </uap:VisualElements>
<Extensions>
<!--Specify which CLSID to activate when notification is clicked-->
<desktop:Extension Category="windows.toastNotificationActivation">
<desktop:ToastNotificationActivation ToastActivatorCLSID="9DF6E26B-F9A8-40B3-AD41-AF83E4A07921" />
</desktop:Extension>
<!--Register COM CLSID-->
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="SampleApp\SampleApp.exe" DisplayName="SampleApp" Arguments="----AppNotificationActivated:">
<com:Class Id="9DF6E26B-F9A8-40B3-AD41-AF83E4A07921" />
</com:ExeServer>
</com:ComServer>
</com:Extension>
</Extensions>
</Application> </Application>
</Applications> </Applications>

View File

@ -1,19 +1,14 @@
using Org.BouncyCastle.Crypto; using Renci.SshNet;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Renci.SshNet;
using Renci.SshNet.Common; using Renci.SshNet.Common;
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Windows.Media.Protection.PlayReady;
namespace wakka namespace wakka
{ {
public class SshConnection public static class SshConnection
{ {
public static string User { get; set; } = string.Empty; public static string User { get; set; } = string.Empty;
@ -25,9 +20,9 @@ namespace wakka
public static string? PublicKey { get; set; } = null; public static string? PublicKey { get; set; } = null;
public bool KeyExists() => File.Exists(SshKeyPath); public static bool KeyExists() => File.Exists(SshKeyPath);
public void InitializeConnection(string user) public static void InitializeConnection(string user)
{ {
if (!File.Exists(SshKeyPath) || user == string.Empty) if (!File.Exists(SshKeyPath) || user == string.Empty)
{ {
@ -50,7 +45,7 @@ namespace wakka
} }
} }
public string RunCommand(string command) public static string RunCommand(string command)
{ {
if (Client == null || !Client.IsConnected) if (Client == null || !Client.IsConnected)
{ {
@ -60,7 +55,18 @@ namespace wakka
return rc.Result; return rc.Result;
} }
public async void RunCommandWithInput(string command, string input) public static bool DoesFileExist(string path)
{
if (Client == null || !Client.IsConnected)
{
throw new InvalidOperationException("SSH client is not connected.");
}
var command = Client.CreateCommand($"test -e {path} && echo 1 || echo 0");
var result = command.Execute();
return result.Trim() == "1";
}
public static async void RunCommandWithInput(string command, string input)
{ {
if (Client == null || !Client.IsConnected) if (Client == null || !Client.IsConnected)
{ {
@ -79,7 +85,7 @@ namespace wakka
} }
} }
public string CreateSshKey() public static string CreateSshKey()
{ {
var keygen = new SshKeyGenerator.SshKeyGenerator(2048); var keygen = new SshKeyGenerator.SshKeyGenerator(2048);
var privateKey = keygen.ToPrivateKey(); var privateKey = keygen.ToPrivateKey();
@ -87,7 +93,7 @@ namespace wakka
return keygen.ToRfcPublicKey("wakka"); return keygen.ToRfcPublicKey("wakka");
} }
public void DeleteSshKey() public static void DeleteSshKey()
{ {
if (File.Exists(SshKeyPath)) if (File.Exists(SshKeyPath))
{ {

View File

@ -2,12 +2,10 @@ using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Renci.SshNet.Common; using Renci.SshNet.Common;
using System; using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer; using Windows.ApplicationModel.DataTransfer;
using Windows.Storage; using Windows.Storage;
using Windows.Storage.Pickers; using Windows.Storage.Pickers;
using WinRT.Interop; using WinRT.Interop;
using static System.Net.Mime.MediaTypeNames;
// To learn more about WinUI, the WinUI project structure, // To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info. // and more about our project templates, see: http://aka.ms/winui-project-info.
@ -19,8 +17,6 @@ namespace wakka
public sealed partial class StartupSshPage : Page public sealed partial class StartupSshPage : Page
{ {
private static SshConnection Ssh { get; set; } = new SshConnection();
public StartupSshPage() public StartupSshPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
@ -58,7 +54,7 @@ namespace wakka
private void CreateSshKey(object sender, RoutedEventArgs e) private void CreateSshKey(object sender, RoutedEventArgs e)
{ {
var publicKey = Ssh.CreateSshKey(); var publicKey = SshConnection.CreateSshKey();
if (publicKey != null) if (publicKey != null)
{ {
var dataPackage = new DataPackage(); var dataPackage = new DataPackage();
@ -66,7 +62,6 @@ namespace wakka
Clipboard.SetContent(dataPackage); Clipboard.SetContent(dataPackage);
sshKeyCreateButton.Content = "Public key copied!"; sshKeyCreateButton.Content = "Public key copied!";
} }
} }
private void OnTextChanged(object sender, TextChangedEventArgs e) private void OnTextChanged(object sender, TextChangedEventArgs e)
@ -98,7 +93,9 @@ namespace wakka
{ {
try try
{ {
Ssh.InitializeConnection((string)App.LocalSettingsData.Values["username"]); SshConnection.InitializeConnection((string)App.LocalSettingsData.Values["username"]);
Bink.Initialize();
Feels.Initialize();
var mainWindow = (App.Current as App)?.m_window; var mainWindow = (App.Current as App)?.m_window;
if (mainWindow != null) if (mainWindow != null)
{ {

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework> <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
@ -94,5 +94,16 @@
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun> <PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed> <PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed> <PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<PackageCertificateThumbprint>158AC0CEA4875FEA7A385A58844BE2EA095E5FCE</PackageCertificateThumbprint>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundle>Always</AppxBundle>
<AppxBundlePlatforms>x86|x64|arm64</AppxBundlePlatforms>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
<LangVersion>12.0</LangVersion>
</PropertyGroup> </PropertyGroup>
</Project> </Project>