ok

alphons <alphons@heijden.com> 10 Jan 2025, 16:48
a2e69d5479b90930c65c1750e36191e78b2cdafd
8 files changed
  • RedisGui/FormMain.Designer.cs
  • RedisGui/FormMain.cs
  • RedisGui/FormMain.resx
  • RedisGui/Properties/Resources.Designer.cs
  • RedisGui/Properties/Resources.resx
  • RedisGui/RedisGui.csproj
  • RedisGui/Resources/blue.png
  • RedisGui/Resources/green.png
diff --git a/RedisGui/FormMain.Designer.cs b/RedisGui/FormMain.Designer.cs
index 950bbc3..9f0d9b2 100644
--- a/RedisGui/FormMain.Designer.cs
+++ b/RedisGui/FormMain.Designer.cs
@@ -33,6 +33,7 @@
fileToolStripMenuItem = new ToolStripMenuItem();
exitToolStripMenuItem = new ToolStripMenuItem();
statusStrip1 = new StatusStrip();
+ toolStripStatusLabel1 = new ToolStripStatusLabel();
splitContainer1 = new SplitContainer();
splitContainer2 = new SplitContainer();
treeView1 = new TreeView();
@@ -52,7 +53,9 @@
showConfigurationToolStripMenuItem = new ToolStripMenuItem();
toolStripSeparator1 = new ToolStripSeparator();
closeConnectionToolStripMenuItem = new ToolStripMenuItem();
+ timer1 = new System.Windows.Forms.Timer(components);
menuStrip1.SuspendLayout();
+ statusStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
splitContainer1.Panel1.SuspendLayout();
splitContainer1.Panel2.SuspendLayout();
@@ -89,12 +92,20 @@
//
// statusStrip1
//
+ statusStrip1.Items.AddRange(new ToolStripItem[] { toolStripStatusLabel1 });
statusStrip1.Location = new Point(0, 474);
statusStrip1.Name = "statusStrip1";
statusStrip1.Size = new Size(1034, 22);
statusStrip1.TabIndex = 1;
statusStrip1.Text = "statusStrip1";
//
+ // toolStripStatusLabel1
+ //
+ toolStripStatusLabel1.Image = Properties.Resources.blue;
+ toolStripStatusLabel1.Name = "toolStripStatusLabel1";
+ toolStripStatusLabel1.RightToLeftAutoMirrorImage = true;
+ toolStripStatusLabel1.Size = new Size(16, 17);
+ //
// splitContainer1
//
splitContainer1.Dock = DockStyle.Fill;
@@ -199,10 +210,11 @@
listView1.GridLines = true;
listView1.Location = new Point(12, 79);
listView1.Name = "listView1";
- listView1.Size = new Size(651, 233);
+ listView1.Size = new Size(615, 233);
listView1.TabIndex = 0;
listView1.UseCompatibleStateImageBehavior = false;
listView1.View = View.Details;
+ listView1.SelectedIndexChanged += ListView_SelectedIndexChanged;
//
// columnHeader1
//
@@ -225,7 +237,7 @@
txtData.Name = "txtData";
txtData.ReadOnly = true;
txtData.ScrollBars = ScrollBars.Both;
- txtData.Size = new Size(1019, 113);
+ txtData.Size = new Size(1019, 77);
txtData.TabIndex = 5;
//
// contextMenuStrip1
@@ -273,6 +285,11 @@
closeConnectionToolStripMenuItem.Text = "Close Connection";
closeConnectionToolStripMenuItem.Click += closeConnectionToolStripMenuItem_Click;
//
+ // timer1
+ //
+ timer1.Interval = 5000;
+ timer1.Tick += Timer_Tick;
+ //
// FormMain
//
AutoScaleDimensions = new SizeF(7F, 15F);
@@ -287,6 +304,8 @@
Load += Form_Load;
menuStrip1.ResumeLayout(false);
menuStrip1.PerformLayout();
+ statusStrip1.ResumeLayout(false);
+ statusStrip1.PerformLayout();
splitContainer1.Panel1.ResumeLayout(false);
splitContainer1.Panel2.ResumeLayout(false);
splitContainer1.Panel2.PerformLayout();
@@ -328,5 +347,8 @@
private ToolStripMenuItem showInformationToolStripMenuItem;
private ToolStripSeparator toolStripSeparator1;
private ToolStripMenuItem closeConnectionToolStripMenuItem;
+ private System.Windows.Forms.Timer timer1;
+ private ToolStripSplitButton toolStripSplitButton1;
+ private ToolStripStatusLabel toolStripStatusLabel1;
}
}
diff --git a/RedisGui/FormMain.cs b/RedisGui/FormMain.cs
index a80997f..281cf7d 100644
--- a/RedisGui/FormMain.cs
+++ b/RedisGui/FormMain.cs
@@ -1,7 +1,10 @@
+using RedisGui.Properties;
using StackExchange.Redis;
+using System.Buffers.Binary;
using System.Diagnostics;
using System.Net;
+using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
@@ -48,6 +51,8 @@ namespace RedisGui
var node = this.treeView1.Nodes.Add("", endPoint.ToString(), 1, 1);
LoadKeys(node);
+
+ this.timer1.Start();
}
private void LoadKeys(TreeNode node)
@@ -119,7 +124,7 @@ namespace RedisGui
{
if (i % 32 == 0)
{
- hexBuilder.Append(i.ToString("X4"));
+ hexBuilder.Append(i.ToString("X6"));
hexBuilder.Append(" - ");
}
hexBuilder.Append(byteArray[i].ToString("X2"));
@@ -146,7 +151,7 @@ namespace RedisGui
var todo = (32 * 3) - 3 * last + 2;
if (last < 16)
todo += 2;
- if(todo>0)
+ if (todo > 0)
{
for (int i = 0; i < todo; i++)
hexBuilder.Append(' ');
@@ -156,6 +161,32 @@ namespace RedisGui
return hexBuilder.ToString();
}
+
+ public static Int16 ReadInt16(byte[] b, int index) => BinaryPrimitives.ReadInt16BigEndian(b.AsSpan(index, 2));
+ public static Int32 ReadInt32(byte[] b, int index) => BinaryPrimitives.ReadInt32BigEndian(b.AsSpan(index, 4));
+
+ private static void SessionDecoder(ListView lv, byte[] b)
+ {
+ lv.Items.Add(new ListViewItem(["Version", $"{b[0]}.{b[1]}"]));
+ var count = ReadInt16(b, 2);
+ lv.Items.Add(new ListViewItem(["Keys", $"{count}"]));
+ var guid = new Guid(b.AsSpan(4, 16));
+ lv.Items.Add(new ListViewItem(["Guid", $"{guid}"]));
+ var index = 20;
+ for (int i = 0; i < count; i++)
+ {
+ var lenName = ReadInt16(b, index);
+ index += 2;
+ var name = Encoding.UTF8.GetString(b.AsSpan(index, lenName));
+ index += lenName;
+ var lenVal = ReadInt32(b, index);
+ index += 4;
+ var val = Encoding.UTF8.GetString(b.AsSpan(index, lenVal));
+ index += lenVal;
+ lv.Items.Add(new ListViewItem([name, val]));
+ }
+ }
+
private void ShowValue(RedisKey key)
{
this.lblType.Text = "";
@@ -201,11 +232,13 @@ namespace RedisGui
case "data":
if (val.StartsWith('{') && val.EndsWith('}'))
this.txtData.Text = Regex.Unescape(PrettyPrintJson(val));
- if (val[0]<0x10)
+ if (val[0] == 0x02)
{
- if(entry.Value.Box() is byte[] buffer)
+ if (entry.Value.Box() is byte[] buffer)
{
- this.txtData.Text = ConvertByteArrayToHexText(buffer);
+ //this.txtData.Text = ConvertByteArrayToHexText(buffer);
+ SessionDecoder(this.listView1, buffer);
+ val = $"*binary* (len {buffer.Length})";
}
}
break;
@@ -300,6 +333,7 @@ namespace RedisGui
TreeNode node = this.treeView1.GetNodeAt(e.Location);
if (node != null)
{
+ this.treeView1.SelectedNode = node;
if (node.Parent == null)
this.contextMenuStrip2.Show(this.treeView1, e.Location);
return;
@@ -314,9 +348,56 @@ namespace RedisGui
this.treeView1.SelectedNode.Remove();
this.db = null;
this.server = null;
- if(this.connection != null)
+ if (this.connection != null)
await this.connection.CloseAsync();
this.connection = null;
}
+
+ private void ListView_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ if (this.listView1.SelectedIndices.Count != 1)
+ return;
+
+ var lvi = this.listView1.Items[this.listView1.SelectedIndices[0]];
+
+ if (lvi == null)
+ return;
+
+ var val = lvi.SubItems[1].Text;
+ if ((val.StartsWith('{') && val.EndsWith('}')) || (val.StartsWith('[') && val.EndsWith(']')))
+ this.txtData.Text = Regex.Unescape(PrettyPrintJson(val));
+ else
+ this.txtData.Text = val;
+ }
+
+ private void Timer_Tick(object sender, EventArgs e)
+ {
+ if (this.server == null)
+ return;
+
+ this.toolStripStatusLabel1.Image = Resources.green;
+
+ var keys = this.server.Keys(pattern: "*").Select(x => x.ToString()).ToList();
+
+ foreach (TreeNode connectionNode in this.treeView1.Nodes)
+ {
+ for(int j= connectionNode.Nodes.Count -1; j>=0; j--)
+ {
+ TreeNode keyNode = connectionNode.Nodes[j];
+
+ if (keys.Contains(keyNode.Text))
+ keys.Remove(keyNode.Text);
+ else
+ keyNode.Remove();
+ }
+ foreach(var newKey in keys)
+ {
+ connectionNode.Nodes.Add("", newKey, 2, 2);
+ }
+ }
+
+ this.toolStripStatusLabel1.Image = Resources.blue;
+
+ }
}
}
diff --git a/RedisGui/FormMain.resx b/RedisGui/FormMain.resx
index 68ec561..2b5d210 100644
--- a/RedisGui/FormMain.resx
+++ b/RedisGui/FormMain.resx
@@ -132,6 +132,9 @@
<metadata name="contextMenuStrip2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>618, 17</value>
</metadata>
+ <metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <value>773, 17</value>
+ </metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>99</value>
</metadata>
diff --git a/RedisGui/Properties/Resources.Designer.cs b/RedisGui/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..13db01d
--- /dev/null
+++ b/RedisGui/Properties/Resources.Designer.cs
@@ -0,0 +1,83 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace RedisGui.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RedisGui.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ /// </summary>
+ internal static System.Drawing.Bitmap blue {
+ get {
+ object obj = ResourceManager.GetObject("blue", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ /// </summary>
+ internal static System.Drawing.Bitmap green {
+ get {
+ object obj = ResourceManager.GetObject("green", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+ }
+}
diff --git a/RedisGui/Properties/Resources.resx b/RedisGui/Properties/Resources.resx
new file mode 100644
index 0000000..0ba568a
--- /dev/null
+++ b/RedisGui/Properties/Resources.resx
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+ <data name="green" type="System.Resources.ResXFileRef, System.Windows.Forms">
+ <value>..\Resources\green.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+ </data>
+ <data name="blue" type="System.Resources.ResXFileRef, System.Windows.Forms">
+ <value>..\Resources\blue.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+ </data>
+</root>
\ No newline at end of file
diff --git a/RedisGui/RedisGui.csproj b/RedisGui/RedisGui.csproj
index a0053aa..e57bd68 100644
--- a/RedisGui/RedisGui.csproj
+++ b/RedisGui/RedisGui.csproj
@@ -12,4 +12,19 @@
<PackageReference Include="StackExchange.Redis" Version="2.8.24" />
</ItemGroup>
+ <ItemGroup>
+ <Compile Update="Properties\Resources.Designer.cs">
+ <DesignTime>True</DesignTime>
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ </ItemGroup>
+
+ <ItemGroup>
+ <EmbeddedResource Update="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ </ItemGroup>
+
</Project>
\ No newline at end of file
diff --git a/RedisGui/Resources/blue.png b/RedisGui/Resources/blue.png
new file mode 100644
index 0000000..8918a10
Binary files /dev/null and b/RedisGui/Resources/blue.png differ
diff --git a/RedisGui/Resources/green.png b/RedisGui/Resources/green.png
new file mode 100644
index 0000000..caaab6c
Binary files /dev/null and b/RedisGui/Resources/green.png differ