├── .gitignore
├── LICENSE
├── PoshRedisViewer
├── .gitignore
├── Directory.Build.props
├── Directory.Build.targets
├── Directory.Packages.props
├── PoshRedisViewer.sln
├── PoshRedisViewer
│ ├── App.fs
│ ├── AsyncEnumerable.fs
│ ├── PoshRedisViewer.fsproj
│ ├── Redis.fs
│ ├── Tasks.fs
│ ├── UI.fs
│ ├── UILogic.fs
│ └── UIUtil.fs
├── PoshRedisViewerHost
│ ├── PoshRedisViewerHost.fsproj
│ └── Program.fs
├── PoshRedisViewerModule
│ ├── GetRedisViewerCommand.fs
│ ├── PoshRedisViewerModule.fsproj
│ └── PoshRedisViewerModule.psd1
└── global.json
├── README.md
├── Releases
├── 0.0.5
│ ├── En3Tho.FSharp.ComputationExpressions.dll
│ ├── En3Tho.FSharp.Extensions.dll
│ ├── FSharp.Core.dll
│ ├── NStack.dll
│ ├── Pipelines.Sockets.Unofficial.dll
│ ├── Ply.dll
│ ├── PoshRedisViewer.dll
│ ├── PoshRedisViewerModule.dll
│ ├── PoshRedisViewerModule.psd1
│ ├── StackExchange.Redis.dll
│ ├── System.IO.Pipelines.dll
│ └── Terminal.Gui.dll
├── 0.0.6
│ ├── En3Tho.FSharp.ComputationExpressions.dll
│ ├── En3Tho.FSharp.Extensions.dll
│ ├── FSharp.Core.dll
│ ├── NStack.dll
│ ├── Pipelines.Sockets.Unofficial.dll
│ ├── PoshRedisViewer.dll
│ ├── PoshRedisViewerModule.dll
│ ├── PoshRedisViewerModule.psd1
│ ├── StackExchange.Redis.dll
│ ├── System.IO.Pipelines.dll
│ └── Terminal.Gui.dll
├── 0.0.7
│ ├── En3Tho.FSharp.ComputationExpressions.dll
│ ├── En3Tho.FSharp.Extensions.dll
│ ├── FSharp.Core.dll
│ ├── NStack.dll
│ ├── Pipelines.Sockets.Unofficial.dll
│ ├── PoshRedisViewer.dll
│ ├── PoshRedisViewerModule.dll
│ ├── PoshRedisViewerModule.psd1
│ ├── StackExchange.Redis.dll
│ ├── System.IO.Pipelines.dll
│ └── Terminal.Gui.dll
└── 0.0.8
│ ├── En3Tho.FSharp.ComputationExpressions.dll
│ ├── En3Tho.FSharp.Extensions.dll
│ ├── FSharp.Core.dll
│ ├── NStack.dll
│ ├── Pipelines.Sockets.Unofficial.dll
│ ├── PoshRedisViewer.dll
│ ├── PoshRedisViewerModule.dll
│ ├── PoshRedisViewerModule.psd1
│ ├── StackExchange.Redis.dll
│ ├── System.IO.Pipelines.dll
│ └── Terminal.Gui.dll
├── fish-haddock.png
└── img.png
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | .idea/
40 |
41 | # Visual Studio 2017 auto generated files
42 | Generated\ Files/
43 |
44 | # MSTest test Results
45 | [Tt]est[Rr]esult*/
46 | [Bb]uild[Ll]og.*
47 |
48 | # NUnit
49 | *.VisualState.xml
50 | TestResult.xml
51 | nunit-*.xml
52 |
53 | # Build Results of an ATL Project
54 | [Dd]ebugPS/
55 | [Rr]eleasePS/
56 | dlldata.c
57 |
58 | # Benchmark Results
59 | BenchmarkDotNet.Artifacts/
60 |
61 | # .NET Core
62 | project.lock.json
63 | project.fragment.lock.json
64 | artifacts/
65 |
66 | # StyleCop
67 | StyleCopReport.xml
68 |
69 | # Files built by Visual Studio
70 | *_i.c
71 | *_p.c
72 | *_h.h
73 | *.ilk
74 | *.meta
75 | *.obj
76 | *.iobj
77 | *.pch
78 | *.pdb
79 | *.ipdb
80 | *.pgc
81 | *.pgd
82 | *.rsp
83 | *.sbr
84 | *.tlb
85 | *.tli
86 | *.tlh
87 | *.tmp
88 | *.tmp_proj
89 | *_wpftmp.csproj
90 | *.log
91 | *.vspscc
92 | *.vssscc
93 | .builds
94 | *.pidb
95 | *.svclog
96 | *.scc
97 |
98 | # Chutzpah Test files
99 | _Chutzpah*
100 |
101 | # Visual C++ cache files
102 | ipch/
103 | *.aps
104 | *.ncb
105 | *.opendb
106 | *.opensdf
107 | *.sdf
108 | *.cachefile
109 | *.VC.db
110 | *.VC.VC.opendb
111 |
112 | # Visual Studio profiler
113 | *.psess
114 | *.vsp
115 | *.vspx
116 | *.sap
117 |
118 | # Visual Studio Trace Files
119 | *.e2e
120 |
121 | # TFS 2012 Local Workspace
122 | $tf/
123 |
124 | # Guidance Automation Toolkit
125 | *.gpState
126 |
127 | # ReSharper is a .NET coding add-in
128 | _ReSharper*/
129 | *.[Rr]e[Ss]harper
130 | *.DotSettings.user
131 |
132 | # TeamCity is a build add-in
133 | _TeamCity*
134 |
135 | # DotCover is a Code Coverage Tool
136 | *.dotCover
137 |
138 | # AxoCover is a Code Coverage Tool
139 | .axoCover/*
140 | !.axoCover/settings.json
141 |
142 | # Visual Studio code coverage results
143 | *.coverage
144 | *.coveragexml
145 |
146 | # NCrunch
147 | _NCrunch_*
148 | .*crunch*.local.xml
149 | nCrunchTemp_*
150 |
151 | # MightyMoose
152 | *.mm.*
153 | AutoTest.Net/
154 |
155 | # Web workbench (sass)
156 | .sass-cache/
157 |
158 | # Installshield output folder
159 | [Ee]xpress/
160 |
161 | # DocProject is a documentation generator add-in
162 | DocProject/buildhelp/
163 | DocProject/Help/*.HxT
164 | DocProject/Help/*.HxC
165 | DocProject/Help/*.hhc
166 | DocProject/Help/*.hhk
167 | DocProject/Help/*.hhp
168 | DocProject/Help/Html2
169 | DocProject/Help/html
170 |
171 | # Click-Once directory
172 | publish/
173 |
174 | # Publish Web Output
175 | *.[Pp]ublish.xml
176 | *.azurePubxml
177 | # Note: Comment the next line if you want to checkin your web deploy settings,
178 | # but database connection strings (with potential passwords) will be unencrypted
179 | *.pubxml
180 | *.publishproj
181 |
182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
183 | # checkin your Azure Web App publish settings, but sensitive information contained
184 | # in these scripts will be unencrypted
185 | PublishScripts/
186 |
187 | # NuGet Packages
188 | *.nupkg
189 | # NuGet Symbol Packages
190 | *.snupkg
191 | # The packages folder can be ignored because of Package Restore
192 | **/[Pp]ackages/*
193 | # except build/, which is used as an MSBuild target.
194 | !**/[Pp]ackages/build/
195 | # Uncomment if necessary however generally it will be regenerated when needed
196 | #!**/[Pp]ackages/repositories.config
197 | # NuGet v3's project.json files produces more ignorable files
198 | *.nuget.props
199 | *.nuget.targets
200 |
201 | # Microsoft Azure Build Output
202 | csx/
203 | *.build.csdef
204 |
205 | # Microsoft Azure Emulator
206 | ecf/
207 | rcf/
208 |
209 | # Windows Store app package directories and files
210 | AppPackages/
211 | BundleArtifacts/
212 | Package.StoreAssociation.xml
213 | _pkginfo.txt
214 | *.appx
215 | *.appxbundle
216 | *.appxupload
217 |
218 | # Visual Studio cache files
219 | # files ending in .cache can be ignored
220 | *.[Cc]ache
221 | # but keep track of directories ending in .cache
222 | !?*.[Cc]ache/
223 |
224 | # Others
225 | ClientBin/
226 | ~$*
227 | *~
228 | *.dbmdl
229 | *.dbproj.schemaview
230 | *.jfm
231 | *.pfx
232 | *.publishsettings
233 | orleans.codegen.cs
234 |
235 | # Including strong name files can present a security risk
236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
237 | #*.snk
238 |
239 | # Since there are multiple workflows, uncomment next line to ignore bower_components
240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
241 | #bower_components/
242 |
243 | # RIA/Silverlight projects
244 | Generated_Code/
245 |
246 | # Backup & report files from converting an old project file
247 | # to a newer Visual Studio version. Backup files are not needed,
248 | # because we have git ;-)
249 | _UpgradeReport_Files/
250 | Backup*/
251 | UpgradeLog*.XML
252 | UpgradeLog*.htm
253 | ServiceFabricBackup/
254 | *.rptproj.bak
255 |
256 | # SQL Server files
257 | *.mdf
258 | *.ldf
259 | *.ndf
260 |
261 | # Business Intelligence projects
262 | *.rdl.data
263 | *.bim.layout
264 | *.bim_*.settings
265 | *.rptproj.rsuser
266 | *- [Bb]ackup.rdl
267 | *- [Bb]ackup ([0-9]).rdl
268 | *- [Bb]ackup ([0-9][0-9]).rdl
269 |
270 | # Microsoft Fakes
271 | FakesAssemblies/
272 |
273 | # GhostDoc plugin setting file
274 | *.GhostDoc.xml
275 |
276 | # Node.js Tools for Visual Studio
277 | .ntvs_analysis.dat
278 | node_modules/
279 |
280 | # Visual Studio 6 build log
281 | *.plg
282 |
283 | # Visual Studio 6 workspace options file
284 | *.opt
285 |
286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
287 | *.vbw
288 |
289 | # Visual Studio LightSwitch build output
290 | **/*.HTMLClient/GeneratedArtifacts
291 | **/*.DesktopClient/GeneratedArtifacts
292 | **/*.DesktopClient/ModelManifest.xml
293 | **/*.Server/GeneratedArtifacts
294 | **/*.Server/ModelManifest.xml
295 | _Pvt_Extensions
296 |
297 | # Paket dependency manager
298 | .paket/paket.exe
299 | paket-files/
300 |
301 | # FAKE - F# Make
302 | .fake/
303 |
304 | # CodeRush personal settings
305 | .cr/personal
306 |
307 | # Python Tools for Visual Studio (PTVS)
308 | __pycache__/
309 | *.pyc
310 |
311 | # Cake - Uncomment if you are using it
312 | # tools/**
313 | # !tools/packages.config
314 |
315 | # Tabs Studio
316 | *.tss
317 |
318 | # Telerik's JustMock configuration file
319 | *.jmconfig
320 |
321 | # BizTalk build output
322 | *.btp.cs
323 | *.btm.cs
324 | *.odx.cs
325 | *.xsd.cs
326 |
327 | # OpenCover UI analysis results
328 | OpenCover/
329 |
330 | # Azure Stream Analytics local run output
331 | ASALocalRun/
332 |
333 | # MSBuild Binary and Structured Log
334 | *.binlog
335 |
336 | # NVidia Nsight GPU debugger configuration file
337 | *.nvuser
338 |
339 | # MFractors (Xamarin productivity tool) working folder
340 | .mfractor/
341 |
342 | # Local History for Visual Studio
343 | .localhistory/
344 |
345 | # BeatPulse healthcheck temp database
346 | healthchecksdb
347 |
348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
349 | MigrationBackup/
350 |
351 | # Ionide (cross platform F# VS Code tools) working folder
352 | .ionide/
353 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Igor Bagdamyan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PoshRedisViewer/.gitignore:
--------------------------------------------------------------------------------
1 | .artifacts/
2 |
--------------------------------------------------------------------------------
/PoshRedisViewer/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | 0.0.12
6 |
7 |
8 |
9 | false
10 |
11 | 9,
12 | 0760,
13 | 96 ,
14 | 3535,
15 | 42,
16 | 77,
17 | 3513,
18 | 1204
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/PoshRedisViewer/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(ModuleVersion)
5 | $(ModuleVersion)
6 | $(ModuleVersion)
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PoshRedisViewer/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PoshRedisViewer", "PoshRedisViewer\PoshRedisViewer.fsproj", "{BA3A07AF-CB3B-47BB-B373-36A139ED3249}"
4 | EndProject
5 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PoshRedisViewerHost", "PoshRedisViewerHost\PoshRedisViewerHost.fsproj", "{D24C16C7-1D8E-4510-82F1-F1B6A6EC1F89}"
6 | EndProject
7 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PoshRedisViewerModule", "PoshRedisViewerModule\PoshRedisViewerModule.fsproj", "{9519E9D2-FF3C-4D41-9E24-BC832B66EAB7}"
8 | EndProject
9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{226CB7CF-2C39-4603-8C69-4E64A1259F78}"
10 | ProjectSection(SolutionItems) = preProject
11 | ..\.gitignore = ..\.gitignore
12 | ..\LICENSE = ..\LICENSE
13 | ..\README.md = ..\README.md
14 | Directory.Packages.props = Directory.Packages.props
15 | Directory.Build.props = Directory.Build.props
16 | Directory.Build.targets = Directory.Build.targets
17 | global.json = global.json
18 | EndProjectSection
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {BA3A07AF-CB3B-47BB-B373-36A139ED3249}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {BA3A07AF-CB3B-47BB-B373-36A139ED3249}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {BA3A07AF-CB3B-47BB-B373-36A139ED3249}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {BA3A07AF-CB3B-47BB-B373-36A139ED3249}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {D24C16C7-1D8E-4510-82F1-F1B6A6EC1F89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {D24C16C7-1D8E-4510-82F1-F1B6A6EC1F89}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {D24C16C7-1D8E-4510-82F1-F1B6A6EC1F89}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {D24C16C7-1D8E-4510-82F1-F1B6A6EC1F89}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {9519E9D2-FF3C-4D41-9E24-BC832B66EAB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {9519E9D2-FF3C-4D41-9E24-BC832B66EAB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {9519E9D2-FF3C-4D41-9E24-BC832B66EAB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {9519E9D2-FF3C-4D41-9E24-BC832B66EAB7}.Release|Any CPU.Build.0 = Release|Any CPU
38 | EndGlobalSection
39 | EndGlobal
40 |
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer/App.fs:
--------------------------------------------------------------------------------
1 | module PoshRedisViewer.App
2 |
3 | open System.Threading
4 | open En3Tho.FSharp.ComputationExpressions.GenericTaskBuilder.Tasks.SemaphoreSlimTask
5 | open En3Tho.FSharp.ComputationExpressions.GenericTaskBuilder.Tasks.SynchronizationContextTask
6 | open PoshRedisViewer.UIUtil
7 | open StackExchange.Redis
8 | open Terminal.Gui
9 |
10 | let run(multiplexer: IConnectionMultiplexer) =
11 | Application.Init()
12 |
13 | UITask.Builder <- SynchronizationContextTaskBuilder(SynchronizationContext.Current)
14 | RedisTask.Builder <- SemaphoreSlimTaskBuilder(SemaphoreSlim(1))
15 | Clipboard.MiniClipboard <- MiniClipboard(Application.Driver.Clipboard)
16 |
17 | UI.makeViews()
18 | |> UI.setupViewsPosition
19 | |> UILogic.setupViewsLogic multiplexer
20 | |> fun views ->
21 | let handler = UILogic.makeErrorHandler views
22 | Application.Run(views.Top, handler)
23 |
24 | let shutdown() = Application.Shutdown()
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer/AsyncEnumerable.fs:
--------------------------------------------------------------------------------
1 | module PoshRedisViewer.AsyncEnumerable
2 | open System
3 | open System.Threading
4 | open System.Threading.Tasks
5 | open En3Tho.FSharp.Extensions
6 | open En3Tho.FSharp.ComputationExpressions.Tasks
7 | open System.Collections.Generic
8 |
9 | let toResizeArray (enumerable: IAsyncEnumerable<'a>) = vtask {
10 | let result = ResizeArray()
11 | use enumerator = enumerable.GetAsyncEnumerator()
12 |
13 | let mutable goNext = true
14 | while goNext do
15 | match! enumerator.MoveNextAsync() with
16 | | true ->
17 | result.Add enumerator.Current
18 | | _ ->
19 | goNext <- false
20 |
21 | return result
22 | }
23 |
24 | let dispose2 (enumerator1: #IAsyncEnumerator<'a>)(enumerator2: #IAsyncEnumerator<'b>) = uvtask {
25 | let mutable exn1 = null
26 | let mutable exn2 = null
27 | try
28 | do! enumerator1.DisposeAsync()
29 | with e ->
30 | exn1 <- e
31 | try
32 | do! enumerator2.DisposeAsync()
33 | with e ->
34 | exn2 <- e
35 |
36 | match exn1, exn2 with
37 | | null, null ->
38 | ()
39 | | exn, null
40 | | null, exn ->
41 | Exception.reraise exn
42 | | _ ->
43 | raise ^ AggregateException(exn1, exn2)
44 | }
45 |
46 | type [] private EmptyAsyncEnumerator<'a> =
47 | interface IAsyncEnumerator<'a> with
48 | member this.Current = invalidOp "Current should not be used with empty async enumerable"
49 | member this.DisposeAsync() = ValueTask()
50 | member this.MoveNextAsync() = ValueTask.FromResult(false)
51 |
52 | type private EmptyAsyncEnumerable<'a>() =
53 | static let cachedEnumerator = EmptyAsyncEnumerator<'a>() :> IAsyncEnumerator<'a>
54 | static let cachedInstance = EmptyAsyncEnumerable<'a>()
55 | static member Empty = cachedInstance
56 |
57 | interface IAsyncEnumerable<'a> with
58 | member this.GetAsyncEnumerator(_) = cachedEnumerator
59 |
60 | type private MapAsyncEnumerableEnumerator<'a, 'b>(source1: IAsyncEnumerable<'a>, map: 'a -> 'b) =
61 | let enumerator = source1.GetAsyncEnumerator()
62 |
63 | interface IAsyncEnumerator<'b> with
64 | member this.Current = enumerator.Current |> map
65 | member this.DisposeAsync() = enumerator.DisposeAsync()
66 | member this.MoveNextAsync() = enumerator.MoveNextAsync()
67 |
68 | type private AppendAsyncEnumerableEnumerator<'a>(source1: IAsyncEnumerable<'a>, source2: IAsyncEnumerable<'a>, cancellationToken: CancellationToken) =
69 | let mutable enumerator = source1.GetAsyncEnumerator()
70 | let mutable enumerator2 = source2.GetAsyncEnumerator()
71 | let mutable state = 0
72 |
73 | interface IAsyncEnumerator<'a> with
74 | member this.Current =
75 | match state with
76 | | 0 ->
77 | enumerator.Current
78 | | _ ->
79 | enumerator2.Current
80 |
81 | member this.DisposeAsync() = dispose2 enumerator enumerator2
82 |
83 | member this.MoveNextAsync() = vtask {
84 | cancellationToken.ThrowIfCancellationRequested()
85 | match state with
86 | | 0 ->
87 | match! enumerator.MoveNextAsync() with
88 | | true -> return true
89 | | _ ->
90 | state <- 1
91 | return! enumerator2.MoveNextAsync()
92 | | _ ->
93 | return! enumerator2.MoveNextAsync()
94 | }
95 |
96 | type private AppendAsyncEnumerable<'a>(source1: IAsyncEnumerable<'a>, source2: IAsyncEnumerable<'a>) =
97 | interface IAsyncEnumerable<'a> with
98 | member this.GetAsyncEnumerator(cancellationToken) = AppendAsyncEnumerableEnumerator<'a>(source1, source2, cancellationToken)
99 |
100 | let empty<'a> = EmptyAsyncEnumerable<'a>.Empty :> IAsyncEnumerable<'a>
101 |
102 | let append source1 source2 =
103 | AppendAsyncEnumerable<'a>(source1, source2) :> IAsyncEnumerable<'a>
104 |
105 | let map map source = { new IAsyncEnumerable<'b> with member _.GetAsyncEnumerator(_) = MapAsyncEnumerableEnumerator<'a, 'b>(source, map) }
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer/PoshRedisViewer.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PowershellModule
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer/Redis.fs:
--------------------------------------------------------------------------------
1 | module PoshRedisViewer.Redis
2 |
3 | open System
4 | open System.Diagnostics
5 | open StackExchange.Redis
6 | open En3Tho.FSharp.Extensions
7 | open En3Tho.FSharp.ComputationExpressions.Tasks
8 |
9 | type StackExchangeRedisResult = RedisResult
10 |
11 | let inline toString x = x.ToString()
12 | let inline toStringOrEmpty x = if Object.ReferenceEquals(x, null) then "" else x.ToString()
13 |
14 | type RedisHashMember = {
15 | Field: string
16 | Value: string
17 | }
18 |
19 | type RedisSortedSetMember = {
20 | Score: float
21 | Value: string
22 | }
23 |
24 | type RedisListMember = {
25 | Index: int
26 | Value: string
27 | }
28 |
29 | type RedisResult =
30 | | RedisString of string
31 | | RedisList of RedisListMember array
32 | | RedisHash of RedisHashMember array
33 | | RedisSet of string array
34 | | RedisSortedSet of RedisSortedSetMember array
35 | | RedisStream
36 | | RedisError of exn
37 | | RedisMultiResult of RedisResult array
38 | | RedisNone
39 |
40 | module RedisResult =
41 |
42 | let fromRedisKey (redisKey: RedisKey) =
43 | RedisString (toString redisKey)
44 |
45 | let rec fromStackExchangeRedisResult (redisResult: StackExchangeRedisResult) =
46 | if redisResult.IsNull then
47 | RedisResult.RedisNone
48 | else
49 | match redisResult.Resp2Type with
50 | | ResultType.SimpleString ->
51 | RedisString (toString redisResult)
52 | | ResultType.None ->
53 | RedisNone
54 | | ResultType.Error ->
55 | RedisError (Exception(toString redisResult))
56 | | ResultType.Integer ->
57 | RedisString (toString redisResult)
58 | | ResultType.BulkString ->
59 | RedisString (toString redisResult)
60 | | ResultType.Array ->
61 | let results = ecast<_, StackExchangeRedisResult[]> redisResult
62 | RedisMultiResult (results |> Array.map fromStackExchangeRedisResult)
63 | | _ ->
64 | RedisError (Exception("Unknown type of Enum"))
65 |
66 | type KeySearchDatabase =
67 | | Single of Database: int
68 | | Range of From: int * To: int
69 |
70 | module KeyFormatter =
71 | let getFormattedKeyString database redisKey = $"{database}. {toString redisKey}"
72 |
73 | let getDatabaseFromHeader (formattedKey: string) =
74 | let indexOfDot = formattedKey.IndexOf('.')
75 | match indexOfDot with
76 | | -1 ->
77 | Debug.Fail("Should not be happening")
78 | 0
79 | | _ ->
80 | Int32.Parse(formattedKey.AsSpan(0, indexOfDot))
81 |
82 | let trimDatabaseHeader (formattedKey: string) =
83 | let indexOfDot = formattedKey.IndexOf('.')
84 | match indexOfDot with
85 | | -1 ->
86 | Debug.Fail("Should not be happening")
87 | formattedKey
88 | | _ ->
89 | formattedKey.Substring(indexOfDot + 2)
90 |
91 | let getDatabaseAndOriginalKeyFromFormattedKeyString (formattedKey: string) =
92 | getDatabaseFromHeader formattedKey, trimDatabaseHeader formattedKey
93 |
94 | module RedisReader =
95 |
96 | let connect (user: string option) (password: string option) (endPoint: string) = redisTask {
97 | let connectionOptions = ConfigurationOptions()
98 | connectionOptions.EndPoints.Add endPoint
99 |
100 | user |> Option.iter ^ fun user -> connectionOptions.User <- user
101 | password |> Option.iter ^ fun password -> connectionOptions.Password <- password
102 |
103 | return! ConnectionMultiplexer.ConnectAsync(connectionOptions)
104 | }
105 |
106 | let getKeys (multiplexer: IConnectionMultiplexer) (database: KeySearchDatabase) (pattern: string) = redisTask {
107 | try
108 | // always 1 endpoint in this version
109 | let server = multiplexer.GetServer(multiplexer.GetEndPoints()[0])
110 |
111 | let getKeys database =
112 | server.KeysAsync(database, RedisValue pattern)
113 | |> AsyncEnumerable.map (KeyFormatter.getFormattedKeyString database)
114 |
115 | let! keys =
116 | match database with
117 | | Single database ->
118 | getKeys database
119 | | Range(from, to') ->
120 | seq {
121 | for database = from to to' do
122 | getKeys database
123 | }
124 | |> Seq.fold AsyncEnumerable.append AsyncEnumerable.empty
125 |
126 | |> AsyncEnumerable.toResizeArray
127 |
128 | return
129 | keys.ToArray()
130 | |> RedisSet
131 | with
132 | | e ->
133 | return RedisError e
134 | }
135 |
136 | let execCommand (multiplexer: IConnectionMultiplexer) database (command: string) = redisTask {
137 | try
138 | let database = multiplexer.GetDatabase database
139 | let commandAndArgs = command.Split(" ", StringSplitOptions.RemoveEmptyEntries)
140 | let command = commandAndArgs[0]
141 | let args = commandAndArgs[1..] |> Array.map box
142 |
143 | let! result = database.ExecuteAsync(command, args)
144 | return RedisResult.fromStackExchangeRedisResult result
145 | with
146 | | e ->
147 | return RedisError e
148 | }
149 |
150 | let getKeyType (multiplexer: IConnectionMultiplexer) database (key: string) = redisTask {
151 | let key = RedisKey key
152 | let database = multiplexer.GetDatabase database
153 | return! database.KeyTypeAsync(key).AsResult()
154 | }
155 |
156 | let getKeyValue (multiplexer: IConnectionMultiplexer) database (key: string) = redisTask {
157 | match! getKeyType multiplexer database key with
158 | | Ok keyType ->
159 | let key = RedisKey key
160 | let database = multiplexer.GetDatabase database
161 | match keyType with
162 | | RedisType.Hash ->
163 | let! hashFields = database.HashGetAllAsync key
164 | return
165 | hashFields
166 | |> Array.map ^ fun hashField ->
167 | { Field = toString hashField.Name; Value = toString hashField.Value }
168 | |> RedisHash
169 |
170 | | RedisType.Set ->
171 | let! setMembers = database.SetMembersAsync key
172 | return
173 | setMembers
174 | |> Array.map toString
175 | |> RedisSet
176 |
177 | | RedisType.String ->
178 | let! str = database.StringGetAsync key
179 | return
180 | toString str
181 | |> RedisString
182 |
183 | | RedisType.List ->
184 | let! listMembers = database.ListRangeAsync key
185 | return
186 | listMembers
187 | |> Array.mapi ^ fun i value ->
188 | { Index = i; Value = toString value }
189 | |> RedisList
190 |
191 | | RedisType.SortedSet ->
192 | let! setMembers = database.SortedSetScanAsync(key) |> AsyncEnumerable.toResizeArray
193 | return
194 | setMembers
195 | |> Seq.map ^ fun setMember ->
196 | { Score = setMember.Score; Value = toString setMember.Element }
197 | |> Seq.toArray
198 | |> RedisSortedSet
199 |
200 | | RedisType.None ->
201 | return RedisNone
202 |
203 | | RedisType.Stream ->
204 | return RedisError (NotSupportedException("Redis streams are not supported"))
205 |
206 | | RedisType.Unknown ->
207 | return RedisError (Exception("Unknown entity"))
208 |
209 | | _ ->
210 | return RedisError (Exception("Unrecognized enum value"))
211 | | Error exn ->
212 | return RedisError exn
213 | }
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer/Tasks.fs:
--------------------------------------------------------------------------------
1 | namespace PoshRedisViewer
2 |
3 | open En3Tho.FSharp.Extensions
4 | open En3Tho.FSharp.ComputationExpressions.GenericTaskBuilder.Tasks.SemaphoreSlimTask
5 | open En3Tho.FSharp.ComputationExpressions.GenericTaskBuilder.Tasks.SynchronizationContextTask
6 |
7 | []
8 | type UITask() =
9 | static member val Builder = nullRef with get, set
10 |
11 | []
12 | type RedisTask() =
13 | static member val Builder = nullRef with get, set
14 |
15 | []
16 | type Tasks() =
17 |
18 | static member uiTask = UITask.Builder
19 | static member redisTask = RedisTask.Builder
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer/UI.fs:
--------------------------------------------------------------------------------
1 | module PoshRedisViewer.UI
2 |
3 | open FSharp.Reflection
4 | open En3Tho.FSharp.Extensions
5 | open En3Tho.FSharp.ComputationExpressions
6 | open En3Tho.FSharp.ComputationExpressions.SCollectionBuilder
7 | open NStack
8 | open PoshRedisViewer.UIUtil
9 | open Terminal.Gui
10 |
11 | type Views = {
12 | CommandFrameView: FrameView
13 | CommandTextField: TextField
14 | DbPickerCheckBox: CheckBox
15 | DbPickerComboBox: ComboBox
16 | DbPickerFrameView: FrameView
17 | KeyQueryFilterFrameView: FrameView
18 | KeyQueryFilterTextField: TextField
19 | KeyQueryFilterTypeComboBox: ComboBox
20 | KeyQueryFilterTypeFrameView: FrameView
21 | KeyQueryFrameView: FrameView
22 | KeyQueryTextField: TextField
23 | KeysFrameView: FrameView
24 | KeysListView: ListView
25 | ResultFilterFrameView: FrameView
26 | ResultFilterTextField: TextField
27 | ResultsFrameView: FrameView
28 | ResultsListView: ListView
29 | Top: Toplevel
30 | Window: Window
31 | }
32 |
33 | let makeViews() =
34 | let window = Window(
35 | Width = Dim.Fill(),
36 | Height = Dim.Fill()
37 | )
38 |
39 | let keyQueryFrameView = FrameView(ustr "KeyQuery",
40 | Width = Dim.Percent(45f),
41 | Height = Dim.Sized 3
42 | )
43 |
44 | let keyQueryTextField = TextField(
45 | Width = Dim.Fill(),
46 | Height = Dim.Fill(),
47 | Text = ustr "*"
48 | )
49 |
50 | let keyQueryFilterFrameView = FrameView(ustr "Keys Filter",
51 | X = Pos.Right keyQueryFrameView,
52 | Width = Dim.Percent(30f),
53 | Height = Dim.Sized 3
54 | )
55 |
56 | let keyQueryFilterTextField = TextField(
57 | Width = Dim.Fill(),
58 | Height = Dim.Fill(),
59 | Text = ustr ""
60 | )
61 |
62 | let keyQueryFilterTypeFrameView = FrameView(ustr "Filter Type",
63 | X = Pos.Right keyQueryFilterFrameView,
64 | Width = Dim.Percent(10f),
65 | Height = Dim.Sized 3
66 | )
67 |
68 | let keyQueryFilterTypeComboBox = ComboBox(ustr "Contains",
69 | X = Pos.Left keyQueryFilterTypeFrameView + Pos.At 1,
70 | Y = Pos.Top keyQueryFilterTypeFrameView + Pos.At 1,
71 | Width = Dim.Width keyQueryFilterTypeFrameView - Dim.Sized 2,
72 | Height = Dim.Sized (FSharpType.GetUnionCases(typeof).Length + 1),
73 | ReadOnly = true
74 | )
75 |
76 | keyQueryFilterTypeComboBox.SetSource([|
77 | FilterType.Contains
78 | FilterType.Regex
79 | |])
80 |
81 | let dbPickerFrameView = FrameView(ustr "DB",
82 | X = Pos.Right keyQueryFilterTypeFrameView,
83 | Width = Dim.Percent(15.f),
84 | Height = Dim.Sized 3
85 | )
86 |
87 | let dbPickerComboBox = ComboBox(ustr "0",
88 | X = Pos.Left dbPickerFrameView + Pos.At 1,
89 | Y = Pos.Top dbPickerFrameView + Pos.At 1,
90 | Width = Dim.Width dbPickerFrameView - Dim.Sized 15,
91 | Height = Dim.Sized 17,
92 | ReadOnly = true
93 | )
94 |
95 | dbPickerComboBox.SetSource([|
96 | for i = 0 to 15 do ustr (string i)
97 | |])
98 |
99 | let dbPickerCheckBox = CheckBox(ustr "Query All",
100 | X = Pos.Right dbPickerComboBox + Pos.At 1,
101 | Y = Pos.Top dbPickerComboBox
102 | )
103 |
104 | let keysFrameView = FrameView(ustr "Keys",
105 | Y = Pos.Bottom keyQueryFrameView,
106 | Width = Dim.Fill(),
107 | Height = Dim.Percent(50.f) - Dim.Sized 3
108 | )
109 |
110 | let keysListView = ListView(
111 | Width = Dim.Fill(),
112 | Height = Dim.Fill()
113 | )
114 |
115 | let resultsFrameView = FrameView(ustr "Results",
116 | Y = Pos.Bottom keysFrameView,
117 | Width = Dim.Fill(),
118 | Height = Dim.Fill() - Dim.Sized 3
119 | )
120 |
121 | let resultsListView = ListView(
122 | Width = Dim.Fill(),
123 | Height = Dim.Fill()
124 | )
125 |
126 | let commandFrameView = FrameView(ustr "Command",
127 | Y = Pos.Bottom resultsFrameView,
128 | Width = Dim.Percent(70.f),
129 | Height = Dim.Sized 3
130 | )
131 |
132 | let commandTextField = TextField(
133 | Width = Dim.Fill(),
134 | Height = Dim.Fill(),
135 | Text = ustring.Empty
136 | )
137 |
138 | let resultFilterFrameView = FrameView(ustr "Results Filter",
139 | X = Pos.Right commandFrameView,
140 | Y = Pos.Bottom resultsFrameView,
141 | Width = Dim.Percent(30.f),
142 | Height = Dim.Sized 3
143 | )
144 |
145 | let resultFilterTextField = TextField(
146 | Width = Dim.Fill(),
147 | Height = Dim.Fill(),
148 | Text = ustr ""
149 | )
150 |
151 | let views: Views = {
152 | Top = Application.Top
153 | Window = window
154 | KeyQueryFrameView = keyQueryFrameView
155 | KeyQueryTextField = keyQueryTextField
156 | KeyQueryFilterFrameView = keyQueryFilterFrameView
157 | KeyQueryFilterTextField = keyQueryFilterTextField
158 | KeyQueryFilterTypeFrameView = keyQueryFilterTypeFrameView
159 | KeyQueryFilterTypeComboBox = keyQueryFilterTypeComboBox
160 | DbPickerFrameView = dbPickerFrameView
161 | DbPickerComboBox = dbPickerComboBox
162 | DbPickerCheckBox = dbPickerCheckBox
163 | KeysFrameView = keysFrameView
164 | KeysListView = keysListView
165 | ResultsFrameView = resultsFrameView
166 | ResultsListView = resultsListView
167 | CommandFrameView = commandFrameView
168 | CommandTextField = commandTextField
169 | ResultFilterFrameView = resultFilterFrameView
170 | ResultFilterTextField = resultFilterTextField
171 | }
172 |
173 | views
174 |
175 | let setupViewsPosition (views: Views) =
176 | views.Top {
177 | views.Window {
178 | views.KeyQueryFrameView {
179 | views.KeyQueryTextField
180 | }
181 |
182 | views.KeyQueryFilterFrameView {
183 | views.KeyQueryFilterTextField
184 | }
185 |
186 | views.KeyQueryFilterTypeFrameView
187 | views.KeyQueryFilterTypeComboBox
188 |
189 | views.DbPickerFrameView
190 | views.DbPickerComboBox
191 | views.DbPickerCheckBox
192 |
193 | views.KeysFrameView {
194 | views.KeysListView
195 | }
196 |
197 | views.ResultsFrameView {
198 | views.ResultsListView
199 | }
200 |
201 | views.CommandFrameView {
202 | views.CommandTextField
203 | }
204 |
205 | views.ResultFilterFrameView {
206 | views.ResultFilterTextField
207 | }
208 | }
209 | } |> ignore
210 |
211 | // what do to with ui?
212 | // something that tzind suggested?
213 | views.Window.Subviews[0].BringSubviewToFront(views.KeyQueryFilterTypeComboBox)
214 | views.Window.Subviews[0].BringSubviewToFront(views.DbPickerComboBox)
215 | views.Window.Subviews[0].BringSubviewToFront(views.DbPickerCheckBox)
216 |
217 | views
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer/UILogic.fs:
--------------------------------------------------------------------------------
1 | module PoshRedisViewer.UILogic
2 |
3 | open System
4 | open En3Tho.FSharp.Extensions
5 | open PoshRedisViewer.Redis
6 | open PoshRedisViewer.UI
7 | open PoshRedisViewer.UIUtil
8 | open Terminal.Gui
9 |
10 | let makeErrorHandler (views: Views) =
11 | fun (exn: Exception) ->
12 | views.ResultsListView.SetSource(exn.ToString().Split(Environment.NewLine))
13 | true
14 |
15 | let getFilter (views: Views) =
16 | let filterType =
17 | match views.KeyQueryFilterTypeComboBox.SelectedItem with
18 | | 0 | 1 as idx ->
19 | views.KeyQueryFilterTypeComboBox.Source.ToList()[idx] :?> FilterType
20 | | _ ->
21 | FilterType.Contains
22 |
23 | match filterType with
24 | | FilterType.Contains ->
25 | Filter.stringContains
26 | | FilterType.Regex ->
27 | Filter.regex
28 |
29 | let filterBy query (views: Views) keys =
30 | match query with
31 | | String.NullOrWhiteSpace ->
32 | keys
33 | | _ ->
34 | let filter = getFilter views
35 | keys |> Array.filter (filter query)
36 |
37 | let filterKeyQueryResult results views =
38 | let query = Ustr.toString views.KeyQueryFilterTextField.Text
39 | results |> filterBy query views
40 |
41 | let filterCommandResult (views: Views) results =
42 | let query = Ustr.toString views.ResultFilterTextField.Text
43 | results |> filterBy query views
44 |
45 | let updateKeyQueryFieldsWithNewState (uiState: UIState) (views: Views) state =
46 | uiState.KeyQueryResultState <- state
47 | views.KeysFrameView.Title <- uiState.KeyQueryResultState |> KeyQueryResultState.toString |> ustr
48 | views.KeysListView.SetSource state.Keys
49 |
50 | let updateResultsFieldsWithNewState (uiState: UIState) (views: Views) state =
51 | uiState.ResultsState <- state
52 | views.ResultsFrameView.Title <- state |> ResultsState.toString |> ustr
53 | views.ResultsListView.SetSource state.Result
54 |
55 | let getDataBase (views: Views) =
56 | if views.DbPickerCheckBox.Checked then
57 | KeySearchDatabase.Range (0, 15)
58 | else
59 | KeySearchDatabase.Single views.DbPickerComboBox.SelectedItem
60 |
61 | module KeyQueryTextField =
62 |
63 | let addKeyDownEvenProcessing (uiState: UIState) (views: Views) (keyQueryTextField: TextField) =
64 | let filterSourceAndSetKeyQueryResultFromHistory keyQuery keys time =
65 | keyQueryTextField.Text <- ustr keyQuery
66 | let newKeyQueryState =
67 | { uiState.KeyQueryResultState with
68 | Keys = views |> filterKeyQueryResult keys
69 | FromHistory = true
70 | Time = time
71 | }
72 | updateKeyQueryFieldsWithNewState uiState views newKeyQueryState
73 |
74 | keyQueryTextField.add_KeyDown (fun keyDownEvent ->
75 | match keyDownEvent.KeyEvent.Key with
76 | | Key.Enter -> ignore ^ uiTask {
77 | use _ = defer(keyQueryTextField, fun it -> it.Enabled <- true)
78 |
79 | keyQueryTextField.Enabled <- false
80 | views.KeysFrameView.Title <- ustr "Keys (processing)"
81 | let database = getDataBase views
82 | let pattern = keyQueryTextField.Text.ToString()
83 |
84 | let! keys =
85 | pattern
86 | |> RedisReader.getKeys uiState.Multiplexer database
87 | |> Task.map RedisResult.toStringArray
88 | keys |> Array.sortInPlace
89 |
90 | let time = DateTimeOffset.Now
91 | uiState.KeyQueryHistory.Add(pattern, (keys, time))
92 |
93 | let newKeyQueryResultState =
94 | { uiState.KeyQueryResultState with
95 | Keys = views |> filterKeyQueryResult keys
96 | FromHistory = false
97 | Time = time
98 | }
99 |
100 | updateKeyQueryFieldsWithNewState uiState views newKeyQueryResultState
101 | }
102 | | Key.CursorUp ->
103 | match uiState.KeyQueryHistory.Up() with
104 | | ValueSome { Key = keyQuery; Value = source, time; } ->
105 | filterSourceAndSetKeyQueryResultFromHistory keyQuery source time
106 | | _ -> ()
107 |
108 | | Key.CursorDown ->
109 | match uiState.KeyQueryHistory.Down() with
110 | | ValueSome { Key = keyQuery; Value = source, time; } ->
111 | filterSourceAndSetKeyQueryResultFromHistory keyQuery source time
112 | | _ -> ()
113 |
114 | | _ -> ()
115 | )
116 | keyQueryTextField
117 |
118 | module KeyQueryFilterTextField =
119 |
120 | let private processEnterKey (uiState: UIState) (views: Views) (keyQueryFilterTextField: TextField) =
121 | match uiState.KeyQueryHistory.TryReadCurrent() with
122 | | ValueSome { Value = keys, time } ->
123 | let filter = Ustr.toString keyQueryFilterTextField.Text
124 | let newKeyQueryResultState =
125 | { uiState.KeyQueryResultState with
126 | Keys = views |> filterKeyQueryResult keys
127 | Filtered = not ^ String.IsNullOrEmpty filter
128 | Time = time
129 | }
130 | updateKeyQueryFieldsWithNewState uiState views newKeyQueryResultState
131 | | _ -> ()
132 |
133 | let addKeyDownEventProcessing (uiState: UIState) (views: Views) (keyQueryFilterTextField: TextField) =
134 | keyQueryFilterTextField.add_KeyDown (fun keyDownEvent ->
135 | match keyDownEvent.KeyEvent.Key with
136 | | Key.Enter ->
137 | processEnterKey uiState views keyQueryFilterTextField
138 | keyDownEvent.Handled <- true
139 | | _ -> ()
140 | )
141 | keyQueryFilterTextField
142 |
143 | module KeysListView =
144 |
145 | let private fetchNewKeyInfo (uiState: UIState) (views: Views) key = ignore ^ uiTask {
146 | let database, key = key.ToString() |> KeyFormatter.getDatabaseAndOriginalKeyFromFormattedKeyString
147 | views.ResultsFrameView.Title <- ustr "Results (processing)"
148 |
149 | let! keyValue = key |> RedisReader.getKeyValue uiState.Multiplexer database
150 | let results = keyValue |> RedisResult.toStringArray
151 |
152 | uiState.ResultsFromKeyQuery <- ValueSome results
153 | { uiState.ResultsState with
154 | Result = results |> filterCommandResult views
155 | ResultType = RedisResult.getInformationText keyValue
156 | FromHistory = false
157 | Time = DateTimeOffset.Now
158 | } |> updateResultsFieldsWithNewState uiState views
159 | }
160 |
161 |
162 | let addSelectedItemChangedEventProcessing (uiState: UIState) (views: Views) (keysListView: ListView) =
163 | keysListView.add_SelectedItemChanged (fun selectedItemChangedEvent ->
164 | match selectedItemChangedEvent.Value with
165 | | null ->
166 | ()
167 | | value ->
168 | fetchNewKeyInfo uiState views value
169 | )
170 | keysListView
171 |
172 | module CommandTextField =
173 |
174 | let private filterSourceAndSetCommandResultFromHistory (uiState: UIState) (views: Views) (commandTextField: TextField)
175 | command commandResult time =
176 | commandTextField.Text <- ustr command
177 | let newResultsState =
178 | { uiState.ResultsState with
179 | Result = commandResult |> filterCommandResult views
180 | ResultType = "Command"
181 | FromHistory = true
182 | Time = time
183 | }
184 |
185 | updateResultsFieldsWithNewState uiState views newResultsState
186 |
187 | let private processEnterKey (uiState: UIState) (views: Views) (commandTextField: TextField) = ignore ^ uiTask {
188 | use _ = defer(commandTextField, fun it -> it.Enabled <- true)
189 |
190 | commandTextField.Enabled <- false
191 | views.ResultsFrameView.Title <- ustr "Results (Processing)"
192 | let database = views.DbPickerComboBox.SelectedItem
193 | let command = commandTextField.Text.ToString()
194 |
195 | let! commandResult =
196 | command
197 | |> RedisReader.execCommand uiState.Multiplexer database
198 | |> Task.map RedisResult.toStringArray
199 |
200 | let time = DateTimeOffset.Now
201 | uiState.ResultsHistory.Add(command, (commandResult, time))
202 | uiState.ResultsFromKeyQuery <- ValueNone
203 |
204 | let filter = Ustr.toString views.ResultFilterTextField.Text
205 | let newResultsState =
206 | { uiState.ResultsState with
207 | Result = commandResult |> filterCommandResult views
208 | ResultType = "Command"
209 | Filtered = not ^ String.IsNullOrEmpty filter
210 | Time = time
211 | }
212 | updateResultsFieldsWithNewState uiState views newResultsState
213 | }
214 |
215 | let private processCursorUpKey (uiState: UIState) (views: Views) (commandTextField: TextField) =
216 | match uiState.ResultsHistory.Up() with
217 | | ValueSome { Key = command; Value = results, time } ->
218 | filterSourceAndSetCommandResultFromHistory uiState views commandTextField command results time
219 | | _ -> ()
220 |
221 | let private processCursorDownKey (uiState: UIState) (views: Views) (commandTextField: TextField) =
222 | match uiState.ResultsHistory.Down() with
223 | | ValueSome { Key = command; Value = results, time } ->
224 | filterSourceAndSetCommandResultFromHistory uiState views commandTextField command results time
225 | | _ -> ()
226 |
227 | let addKeyDownEventProcessing (uiState: UIState) (views: Views) (commandTextField: TextField) =
228 | commandTextField.add_KeyDown (fun keyDownEvent ->
229 | match keyDownEvent.KeyEvent.Key with
230 | | Key.Enter ->
231 | processEnterKey uiState views commandTextField
232 | keyDownEvent.Handled <- true
233 |
234 | | Key.CursorUp ->
235 | processCursorUpKey uiState views commandTextField
236 | keyDownEvent.Handled <- true
237 |
238 | | Key.CursorDown ->
239 | processCursorDownKey uiState views commandTextField
240 | keyDownEvent.Handled <- true
241 |
242 | | _ -> ()
243 | )
244 | commandTextField
245 |
246 | module ResultFilterTextField =
247 |
248 | let private processEnterKey (uiState: UIState) (views: Views) (resultFilterTextField: TextField) =
249 | match uiState.ResultsFromKeyQuery, uiState.ResultsHistory.TryReadCurrent() with
250 | | ValueSome commandResult, _
251 | | _, ValueSome { Value = commandResult, _ } ->
252 | let filter = Ustr.toString resultFilterTextField.Text
253 | let newResultState =
254 | { uiState.ResultsState with
255 | Result = commandResult |> filterCommandResult views
256 | Filtered = not ^ String.IsNullOrEmpty filter
257 | }
258 | updateResultsFieldsWithNewState uiState views newResultState
259 | | _ -> ()
260 |
261 | let addKeyDownEventProcessing (uiState: UIState) (views: Views) (resultFilterTextField: TextField) =
262 | resultFilterTextField.add_KeyDown (fun keyDownEvent ->
263 | match keyDownEvent.KeyEvent.Key with
264 | | Key.Enter ->
265 | processEnterKey uiState views resultFilterTextField
266 | keyDownEvent.Handled <- true
267 | | _ -> ()
268 | )
269 | resultFilterTextField
270 |
271 | let setupViewsLogic multiplexer (views: Views) =
272 |
273 | let uiState = {
274 | Multiplexer = multiplexer
275 | KeyQueryResultState = { KeyQueryResultState.Keys = [||]; Filtered = false; FromHistory = false; Time = DateTimeOffset() }
276 | ResultsState = { ResultsState.Result = [||]; ResultType = ""; Filtered = false; FromHistory = false; Time = DateTimeOffset() }
277 | ResultsFromKeyQuery = ValueSome [||]
278 | KeyQueryHistory = ResultHistoryCache(100)
279 | ResultsHistory = ResultHistoryCache(100)
280 | }
281 |
282 | views.KeyQueryTextField
283 | |> View.preventCursorUpDownKeyPressedEvents
284 | |> TextField.addCopyPasteSupportWithMiniClipboard
285 | |> KeyQueryTextField.addKeyDownEvenProcessing uiState views
286 | |> ignore
287 |
288 | views.KeyQueryFilterTextField
289 | |> View.preventCursorUpDownKeyPressedEvents
290 | |> TextField.addCopyPasteSupportWithMiniClipboard
291 | |> KeyQueryFilterTextField.addKeyDownEventProcessing uiState views
292 | |> ignore
293 |
294 | views.DbPickerComboBox
295 | |> View.preventCursorUpDownKeyPressedEvents
296 | |> ignore
297 |
298 | views.KeysListView
299 | |> ListView.addValueCopyOnRightClick KeyFormatter.trimDatabaseHeader
300 | |> ListView.addValueCopyOnCopyHotKey KeyFormatter.trimDatabaseHeader
301 | |> KeysListView.addSelectedItemChangedEventProcessing uiState views
302 | |> ignore
303 |
304 | views.ResultsListView
305 | |> ListView.addValueCopyOnRightClick id
306 | |> ListView.addValueCopyOnCopyHotKey id
307 | |> ListView.addDetailedViewOnEnterKey
308 | |> ignore
309 |
310 | views.CommandTextField
311 | |> View.preventCursorUpDownKeyPressedEvents
312 | |> TextField.addCopyPasteSupportWithMiniClipboard
313 | |> CommandTextField.addKeyDownEventProcessing uiState views
314 | |> ignore
315 |
316 | views.ResultFilterTextField
317 | |> View.preventCursorUpDownKeyPressedEvents
318 | |> TextField.addCopyPasteSupportWithMiniClipboard
319 | |> ResultFilterTextField.addKeyDownEventProcessing uiState views
320 | |> ignore
321 |
322 | views
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewer/UIUtil.fs:
--------------------------------------------------------------------------------
1 | module PoshRedisViewer.UIUtil
2 |
3 | open System
4 | open System.ComponentModel
5 | open System.Runtime.CompilerServices
6 | open System.Text.RegularExpressions
7 | open En3Tho.FSharp.Extensions
8 | open En3Tho.FSharp.ComputationExpressions
9 | open En3Tho.FSharp.ComputationExpressions.SStringBuilderBuilder
10 | open NStack
11 | open PoshRedisViewer.Redis
12 |
13 | open Terminal.Gui
14 |
15 | type HistorySlot<'a, 'b> = {
16 | Key: 'a
17 | Value: 'b
18 | }
19 |
20 | type KeyQueryResultState = {
21 | Keys: string[]
22 | FromHistory: bool
23 | Filtered: bool
24 | Time: DateTimeOffset
25 | }
26 |
27 | module KeyQueryResultState =
28 | let toString (result: KeyQueryResultState) =
29 | let flags =
30 | seq {
31 | toString result.Keys.Length
32 | if result.FromHistory then "From History"
33 | if result.Filtered then "Filtered"
34 | result.Time.ToString()
35 | } |> String.concat ", "
36 | $"Keys ({flags})"
37 |
38 | type ResultsState = {
39 | ResultType: string
40 | Result: string[]
41 | FromHistory: bool
42 | Filtered: bool
43 | Time: DateTimeOffset
44 | }
45 |
46 | module ResultsState =
47 | let toString (result: ResultsState) =
48 | let flags =
49 | seq {
50 | result.ResultType
51 | if result.FromHistory then "From History"
52 | if result.Filtered then "Filtered"
53 | result.Time.ToString()
54 | } |> String.concat ", "
55 |
56 | $"Results ({flags})"
57 |
58 | []
59 | type ViewExtensions() =
60 | []
61 | static member inline Run(value: #View, [] runExpr: CollectionCode) = runExpr(); value
62 |
63 | type ResultHistoryCache<'a, 'b when 'a: equality>(capacity: int) =
64 | let syncRoot = obj()
65 | let items = ResizeArray>(capacity)
66 | let mutable index = 0
67 |
68 | member _.Up() =
69 | lock syncRoot ^ fun() ->
70 | match items.Count, index - 1 with
71 | | 0, _ ->
72 | ValueNone
73 | | currentCount, newIndex ->
74 | if uint newIndex >= uint currentCount then
75 | ValueNone
76 | else
77 | index <- newIndex
78 | ValueSome items[newIndex]
79 |
80 | member _.Down() =
81 | lock syncRoot ^ fun() ->
82 | match items.Count, index + 1 with
83 | | 0, _ ->
84 | ValueNone
85 | | currentCount, newIndex ->
86 | if uint newIndex >= uint currentCount then
87 | ValueNone
88 | else
89 | index <- newIndex
90 | ValueSome items[newIndex]
91 |
92 | member _.Add(key, value) =
93 | lock syncRoot ^ fun() ->
94 | if items.Count = 0 then
95 | ()
96 | else
97 | match items.FindIndex(fun slot -> slot.Key = key) with
98 | | -1 -> ()
99 | | index ->
100 | items.RemoveAt index
101 |
102 | items.Add { Key = key; Value = value }
103 | if items.Count > capacity then
104 | items.RemoveAt 0
105 | index <- items.Count - 1
106 |
107 | member _.TryReadCurrent() =
108 | lock syncRoot ^ fun() ->
109 | let index = index
110 | if uint index >= uint items.Count then
111 | ValueNone
112 | else
113 | ValueSome items[index]
114 |
115 | type UIState = {
116 | Multiplexer: StackExchange.Redis.IConnectionMultiplexer
117 | mutable KeyQueryResultState: KeyQueryResultState
118 | mutable ResultsState: ResultsState
119 | mutable ResultsFromKeyQuery: ValueOption
120 | KeyQueryHistory: ResultHistoryCache
121 | ResultsHistory: ResultHistoryCache
122 | }
123 |
124 | module rec RedisResult =
125 |
126 | let toStringArray (value: RedisResult) =
127 | match value with
128 | | RedisString str ->
129 | [| str |]
130 | | RedisList strings ->
131 | strings
132 | |> Array.map ^ fun member' -> $"Index: {member'.Index} | Value: {member'.Value}"
133 | | RedisError e ->
134 | e.ToString().Split(Environment.NewLine)
135 | | RedisHash members ->
136 | members
137 | |> Array.map ^ fun member' -> $"Field: {member'.Field} | Value: {member'.Value}"
138 | | RedisNone ->
139 | [| "None" |]
140 | | RedisSet strings ->
141 | strings
142 | | RedisSortedSet members ->
143 | members
144 | |> Array.map ^ fun member' -> $"Score: {member'.Score} | Value: {member'.Value}"
145 | | RedisStream ->
146 | [| "RedisStream is not supported" |]
147 | | RedisMultiResult values ->
148 | values
149 | |> Array.map toStringArray
150 | |> Array.concat
151 |
152 | let getInformationText (value: RedisResult) =
153 | match value with
154 | | RedisString _ ->
155 | "RedisString"
156 | | RedisList strings ->
157 | $"RedisList ({strings.Length})"
158 | | RedisError _ ->
159 | "RedisError"
160 | | RedisHash members ->
161 | $"RedisHash ({members.Length})"
162 | | RedisNone ->
163 | "RedisNone"
164 | | RedisSet strings ->
165 | $"RedisSet ({strings.Length})"
166 | | RedisSortedSet members ->
167 | $"RedisSortedSet ({members.Length})"
168 | | RedisStream ->
169 | "RedisStream"
170 | | RedisMultiResult values ->
171 | $"RedisMultiResult ({values.Length})"
172 |
173 | let ustr str = icast str
174 | module Ustr =
175 |
176 | let toString (utext: ustring) =
177 | match utext with
178 | | null -> ""
179 | | _ -> utext.ToString()
180 |
181 | let fromString (text: string) =
182 | match text with
183 | | null | "" -> ustring.Empty
184 | | _ -> ustr text
185 |
186 | module Key =
187 | let private copyKey = Key.CtrlMask ||| Key.C
188 | let private pasteKey = Key.CtrlMask ||| Key.V
189 |
190 | let private is flag (key: Key) = key |> Enum.hasFlag flag |> Option.ofBool
191 |
192 | let (|CopyCommand|_|) key = key |> is copyKey
193 | let (|PasteCommand|_|) key = key |> is pasteKey
194 |
195 | []
196 | type FilterType =
197 | | Contains
198 | | Regex
199 |
200 | module Filter =
201 | let stringContains (pattern: string) (value: string) =
202 | value.Contains(pattern, StringComparison.OrdinalIgnoreCase)
203 |
204 | let regex (pattern: string) (value: string) =
205 | let regex = Regex(pattern, RegexOptions.Compiled)
206 | regex.IsMatch(value)
207 |
208 | module View =
209 | let preventKeyPressedEvents (events: Key[]) (view: #View) =
210 | view.add_KeyPress(fun keyPressEvent ->
211 | match keyPressEvent.KeyEvent.Key with
212 | | key when events |> Array.contains key ->
213 | keyPressEvent.Handled <- true
214 | | _ -> ()
215 | )
216 | view
217 |
218 | let preventCursorUpDownKeyPressedEvents (view: #View) =
219 | view |> preventKeyPressedEvents [| Key.CursorUp; Key.CursorDown |]
220 |
221 | type MiniClipboard(clipboard: IClipboard) =
222 | let mutable current = ""
223 |
224 | interface IClipboard with
225 | member this.GetClipboardData() =
226 | let original = try' { clipboard.GetClipboardData() }
227 | original |> String.defaultValue current
228 |
229 | member this.SetClipboardData(text) =
230 | current <- text
231 | try' { clipboard.SetClipboardData(current) }
232 |
233 | member this.TryGetClipboardData(result) =
234 | if not (clipboard.TryGetClipboardData(&result)) then
235 | result <- current
236 | true
237 |
238 | member this.TrySetClipboardData(text) =
239 | current <- text
240 | clipboard.TrySetClipboardData(text) |> ignore
241 | true
242 |
243 | member this.IsSupported = true
244 |
245 | module Clipboard =
246 |
247 | let mutable MiniClipboard = nullRef
248 |
249 | let saveToClipboard text =
250 | let text = if Object.ReferenceEquals(text, null) then "" else text.ToString()
251 | MiniClipboard.TrySetClipboardData text |> ignore
252 |
253 | let getFromClipboard() =
254 | let mutable text = nullRef
255 | MiniClipboard.TryGetClipboardData(&text) |> ignore
256 | text |> String.defaultValue ""
257 |
258 | module ListView =
259 |
260 | type ListView with
261 | member this.TrySelectedItem() =
262 | match this.Source, this.SelectedItem with
263 | | (NotNull & source), (GtEq 0 & selectedItem) when source.Count >= 0 ->
264 | let value = source.ToList()[selectedItem]
265 | value |> ValueOption.ofObj
266 | | _ ->
267 | ValueNone
268 |
269 | let private copySelectedItemTextToClipboard (textMapper: string -> string) (listView: ListView) =
270 | match listView.TrySelectedItem() with
271 | | ValueSome selectedItem ->
272 | selectedItem
273 | |> toString
274 | |> textMapper
275 | |> Clipboard.saveToClipboard
276 | | _ -> ()
277 |
278 | let addValueCopyOnRightClick textMapper (listView: ListView) =
279 | listView.add_MouseClick(fun mouseClickEvent ->
280 | if listView.HasFocus then
281 | match mouseClickEvent.MouseEvent.Flags with
282 | | Enum.HasFlag MouseFlags.Button3Released ->
283 | copySelectedItemTextToClipboard textMapper listView
284 | mouseClickEvent.Handled <- true
285 | | _ -> ()
286 | )
287 | listView
288 |
289 | let addValueCopyOnCopyHotKey textMapper (listView: ListView) =
290 | listView.add_KeyDown(fun keyDownEvent ->
291 | match keyDownEvent.KeyEvent.Key with
292 | | Key.CopyCommand ->
293 | copySelectedItemTextToClipboard textMapper listView
294 | keyDownEvent.Handled <- true
295 | | _ -> ()
296 | )
297 | listView
298 |
299 | let addDetailedViewOnEnterKey (listView: ListView) =
300 | listView.add_KeyDown (fun keyDownEvent ->
301 | match keyDownEvent.KeyEvent.Key, listView.TrySelectedItem() with
302 | | Key.Enter, ValueSome selectedItem ->
303 | MessageBox.Query("Value", selectedItem.ToString(), "Ok")
304 | |> ignore
305 | keyDownEvent.Handled <- true
306 | | _ -> ()
307 | )
308 | listView
309 |
310 | module TextField =
311 |
312 | let addCopyPasteSupportWithMiniClipboard (textField: TextField) =
313 | textField.add_KeyDown(fun keyDownEvent ->
314 | match keyDownEvent.KeyEvent.Key with
315 | | Key.CopyCommand ->
316 | textField.SelectedText |> Clipboard.saveToClipboard
317 | keyDownEvent.Handled <- true
318 |
319 | | Key.PasteCommand ->
320 | let newText, newCursorPosition =
321 | let clipboardText = Clipboard.getFromClipboard()
322 |
323 | match textField.SelectedLength, textField.CursorPosition with
324 | | 0, 0 ->
325 | clipboardText |> Ustr.fromString,
326 | clipboardText.Length
327 |
328 | | 0, cursor ->
329 | let text = textField.Text |> Ustr.toString
330 | let left = text.Substring(0, cursor)
331 | let right = text.Substring(cursor)
332 |
333 | left + clipboardText + right |> Ustr.fromString,
334 | textField.CursorPosition + clipboardText.Length
335 |
336 | | _, cursor ->
337 | let text = textField.Text
338 | text.Replace(textField.SelectedText, clipboardText |> Ustr.fromString, maxReplacements = 1),
339 | if textField.SelectedStart < cursor then
340 | textField.SelectedStart + clipboardText.Length
341 | else
342 | cursor + clipboardText.Length
343 |
344 | textField.Text <- newText
345 | textField.CursorPosition <- newCursorPosition
346 | keyDownEvent.Handled <- true
347 | | _ -> ()
348 | )
349 | textField
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewerHost/PoshRedisViewerHost.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewerHost/Program.fs:
--------------------------------------------------------------------------------
1 | open System
2 | open System.Threading.Tasks
3 | open En3Tho.FSharp.Extensions
4 | open PoshRedisViewer
5 | open PoshRedisViewer.Redis
6 |
7 | []
8 | let main argv =
9 | try
10 | "localhost:6379"
11 | |> RedisReader.connect None None
12 | |> Task.RunSynchronously
13 | |> App.run
14 | |> App.shutdown
15 | finally
16 | if not Console.IsInputRedirected then
17 | Console.Write("\u001b[?1h\u001b[?1003l") // fixes an issue with certain terminals, same as ocgv
18 | 0
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewerModule/GetRedisViewerCommand.fs:
--------------------------------------------------------------------------------
1 | namespace PoshRedisViewerModule
2 |
3 | open System
4 | open System.Management.Automation
5 | open System.Threading.Tasks
6 | open PoshRedisViewer
7 | open PoshRedisViewer.Redis
8 | open En3Tho.FSharp.Extensions
9 |
10 | []
11 | type GetRedisViewerCommand() =
12 | inherit Cmdlet()
13 |
14 | []
15 | []
16 | member val ConnectionString = "" with get, set
17 |
18 | []
19 | member val User = "" with get, set
20 |
21 | []
22 | member val Password = "" with get, set
23 |
24 | override this.ProcessRecord() =
25 | let connectionString = this.ConnectionString
26 | let user = this.User |> Option.ofString
27 | let password = this.Password |> Option.ofString
28 |
29 | let dispose() =
30 | if not Console.IsInputRedirected then
31 | Console.Write("\u001b[?1h\u001b[?1003l") // fixes an issue with certain terminals, same as ocgv
32 |
33 | use _ = defer dispose
34 |
35 | connectionString
36 | |> RedisReader.connect user password
37 | |> Task.RunSynchronously
38 | |> App.run
39 | |> App.shutdown
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewerModule/PoshRedisViewerModule.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PowershellModule
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/PoshRedisViewer/PoshRedisViewerModule/PoshRedisViewerModule.psd1:
--------------------------------------------------------------------------------
1 | #
2 | # Module manifest for module 'PoshRedisViewerModule'
3 | #
4 | # Generated by: Rzrl
5 | #
6 | # Generated on: 25.09.2021
7 | #
8 |
9 | @{
10 |
11 | # Script module or binary module file associated with this manifest.
12 | RootModule = 'PoshRedisViewerModule.dll'
13 |
14 | # Version number of this module.
15 | ModuleVersion = '0.0.11'
16 |
17 | # Supported PSEditions
18 | # CompatiblePSEditions = @()
19 |
20 | # ID used to uniquely identify this module
21 | GUID = '0c79ae41-ea88-4f75-94f4-17a31572e263'
22 |
23 | # Author of this module
24 | Author = 'Igor Bagdamyan'
25 |
26 | # Company or vendor of this module
27 | CompanyName = 'Igor Bagdamyan'
28 |
29 | # Copyright statement for this module
30 | Copyright = '(c) Igor Bagdamyan. All rights reserved.'
31 |
32 | # Description of the functionality provided by this module
33 | Description = 'A simple Redis viewer capable of reading values, issuing commands, filtering fetched data in memory, keeping history'
34 |
35 | # Minimum version of the PowerShell engine required by this module
36 | PowerShellVersion = '7.1.3'
37 |
38 | # Name of the PowerShell host required by this module
39 | # PowerShellHostName = ''
40 |
41 | # Minimum version of the PowerShell host required by this module
42 | # PowerShellHostVersion = ''
43 |
44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45 | # DotNetFrameworkVersion = ''
46 |
47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48 | # ClrVersion = ''
49 |
50 | # Processor architecture (None, X86, Amd64) required by this module
51 | # ProcessorArchitecture = ''
52 |
53 | # Modules that must be imported into the global environment prior to importing this module
54 | # RequiredModules = @()
55 |
56 | # Assemblies that must be loaded prior to importing this module
57 | # RequiredAssemblies = @()
58 |
59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module.
60 | # ScriptsToProcess = @()
61 |
62 | # Type files (.ps1xml) to be loaded when importing this module
63 | # TypesToProcess = @()
64 |
65 | # Format files (.ps1xml) to be loaded when importing this module
66 | # FormatsToProcess = @()
67 |
68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69 | # NestedModules = @()
70 |
71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72 | FunctionsToExport = @()
73 |
74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75 | CmdletsToExport = @('Get-RedisViewer')
76 |
77 | # Variables to export from this module
78 | VariablesToExport = '*'
79 |
80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81 | AliasesToExport = @()
82 |
83 | # DSC resources to export from this module
84 | # DscResourcesToExport = @()
85 |
86 | # List of all modules packaged with this module
87 | # ModuleList = @()
88 |
89 | # List of all files packaged with this module
90 | # FileList = @()
91 |
92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
93 | PrivateData = @{
94 |
95 | PSData = @{
96 |
97 | # Tags applied to this module. These help with module discovery in online galleries.
98 | # Tags = @()
99 |
100 | # A URL to the license for this module.
101 | LicenseUri = 'https://github.com/En3Tho/PoshRedisViewer/blob/main/LICENSE'
102 |
103 | # A URL to the main website for this project.
104 | ProjectUri = 'https://github.com/En3Tho/PoshRedisViewer'
105 |
106 | # A URL to an icon representing this module.
107 | # IconUri = ''
108 |
109 | # ReleaseNotes of this module
110 | # ReleaseNotes = ''
111 |
112 | # Prerelease string of this module
113 | # Prerelease = ''
114 |
115 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save
116 | # RequireLicenseAcceptance = $false
117 |
118 | # External dependent modules of this module
119 | # ExternalModuleDependencies = @()
120 |
121 | } # End of PSData hashtable
122 |
123 | } # End of PrivateData hashtable
124 |
125 | # HelpInfo URI of this module
126 | # HelpInfoURI = ''
127 |
128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
129 | # DefaultCommandPrefix = ''
130 |
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/PoshRedisViewer/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "8.0",
4 | "rollForward": "latestMajor",
5 | "allowPrerelease": false
6 | }
7 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PoshRedisViewer
2 | A compact redis browser for powershell powered by https://github.com/StackExchange/StackExchange.Redis and https://github.com/migueldeicaza/gui.cs
3 |
4 | https://www.powershellgallery.com/packages/PoshRedisViewerModule
5 |
6 | 
7 |
8 | It allows you to:
9 | 1. Look for Redis Keys via Scan/Keys (depending on Redis version)
10 | 2. View the type and contents of specified key
11 | 3. Filter keys without requerying them from Redis
12 | 4. Filter results to look for useful information
13 | 5. Execute custom commands
14 | 6. Select DB index
15 |
16 | Copy and Paste is allowed:
17 | - Windows: Ctrl+C | Ctrl+V
18 | - Linux: Ctrl+Y | Ctrl+V
19 | - Keys and Results list views support copying by right-clicking on them
20 | - In case when OS clipboard (clip/xclip) is not available, pasting from internal mini-clipboard is available with Ctrl+B combination
21 |
22 | Query, command and filter execution require "Enter" key press.
23 |
24 | Also, keys and commands support history mode using CursorUp and CursorDown keys.
25 |
26 | Powershell module exports "Get-RedisViewer" command:
27 | - [0, Mandatory] ConnectionString
28 | - [Optional] User
29 | - [Optional] Password
30 |
31 | Example:
32 | ```
33 | Install-Module -Name PoshRedisViewerModule
34 | Import-Module -Name PoshRedisViewerModule
35 | ```
36 | then
37 | ```
38 | Get-RedisViewer "localhost:6379"
39 | ```
40 | or
41 | ```
42 | Get-RedisViewer "localhost:6379" -User me -Password myPassword
43 | ```
44 |
45 | ## Development
46 |
47 | 1. Install power shell
48 | 2. Clone the GitHub repository
49 |
50 | ### Testing application
51 |
52 | The easiest way to test the module is to run the PoshRedisViewerHost project
53 |
54 | ```
55 | cd .\PoshRedisViewer\PoshRedisViewerHost\
56 | dotnet run
57 | ```
58 |
59 | ### Testing as a Powershell Module
60 |
61 | To test running as a powershell module
62 |
63 | 1. Build the repository (if building on linux use `-r linux-x64`)
64 | ```
65 | cd PoshRedisViewer
66 | dotnet publish -o .artifacts -r win-x64
67 | ```
68 | 2. Copy the psd1 file into the build directory
69 | ```
70 | cp .\PoshRedisViewerModule\PoshRedisViewerModule.psd1 .\.artifacts\
71 | ```
72 | 3. Start a new powershell instance (prevents stale modules sitting around etc)
73 | ```
74 | pwsh –noprofile
75 | ```
76 | 4. Import the module
77 | ```
78 | Import-Module -Name ".\.artifacts\PoshRedisViewerModule.psd1"
79 | ```
80 |
81 | ## Testing With Redis Docker Image
82 |
83 | 1. Start a new Redis via docker:
84 |
85 | ```
86 | docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest
87 | ```
88 |
89 | 2. Connect using PoshRedisViewer
90 |
91 | ```
92 | Get-RedisViewer "localhost:6379"
93 | ```
94 |
95 | 3. Create a Redis key entry by clicking in the 'Command' window and enter
96 | ```
97 | set fish haddock
98 | ```
99 |
100 | 4. Query the Redis to see the key by clicking in 'KeyQuery' and pressing enter
101 |
102 | 
103 |
104 |
105 | TODO:
106 | - Tabs/add to favorites
107 | - Results filter history
108 | - Quick commands to change/set values
--------------------------------------------------------------------------------
/Releases/0.0.5/En3Tho.FSharp.ComputationExpressions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/En3Tho.FSharp.ComputationExpressions.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/En3Tho.FSharp.Extensions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/En3Tho.FSharp.Extensions.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/FSharp.Core.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/FSharp.Core.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/NStack.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/NStack.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/Pipelines.Sockets.Unofficial.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/Pipelines.Sockets.Unofficial.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/Ply.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/Ply.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/PoshRedisViewer.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/PoshRedisViewer.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/PoshRedisViewerModule.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/PoshRedisViewerModule.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/PoshRedisViewerModule.psd1:
--------------------------------------------------------------------------------
1 | #
2 | # Module manifest for module 'PoshRedisViewerModule'
3 | #
4 | # Generated by: Rzrl
5 | #
6 | # Generated on: 25.09.2021
7 | #
8 |
9 | @{
10 |
11 | # Script module or binary module file associated with this manifest.
12 | RootModule = 'PoshRedisViewerModule.dll'
13 |
14 | # Version number of this module.
15 | ModuleVersion = '0.0.5'
16 |
17 | # Supported PSEditions
18 | # CompatiblePSEditions = @()
19 |
20 | # ID used to uniquely identify this module
21 | GUID = '0c79ae41-ea88-4f75-94f4-17a31572e263'
22 |
23 | # Author of this module
24 | Author = 'Igor Bagdmamyan'
25 |
26 | # Company or vendor of this module
27 | CompanyName = 'Igor Bagdmamyan'
28 |
29 | # Copyright statement for this module
30 | Copyright = '(c) Igor Bagdmamyan. All rights reserved.'
31 |
32 | # Description of the functionality provided by this module
33 | Description = 'A simple Redis viewer capable of readonly operations'
34 |
35 | # Minimum version of the PowerShell engine required by this module
36 | PowerShellVersion = '7.1.3'
37 |
38 | # Name of the PowerShell host required by this module
39 | # PowerShellHostName = ''
40 |
41 | # Minimum version of the PowerShell host required by this module
42 | # PowerShellHostVersion = ''
43 |
44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45 | # DotNetFrameworkVersion = ''
46 |
47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48 | # ClrVersion = ''
49 |
50 | # Processor architecture (None, X86, Amd64) required by this module
51 | # ProcessorArchitecture = ''
52 |
53 | # Modules that must be imported into the global environment prior to importing this module
54 | # RequiredModules = @()
55 |
56 | # Assemblies that must be loaded prior to importing this module
57 | # RequiredAssemblies = @()
58 |
59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module.
60 | # ScriptsToProcess = @()
61 |
62 | # Type files (.ps1xml) to be loaded when importing this module
63 | # TypesToProcess = @()
64 |
65 | # Format files (.ps1xml) to be loaded when importing this module
66 | # FormatsToProcess = @()
67 |
68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69 | # NestedModules = @()
70 |
71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72 | FunctionsToExport = @()
73 |
74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75 | CmdletsToExport = @('Get-RedisViewer')
76 |
77 | # Variables to export from this module
78 | VariablesToExport = '*'
79 |
80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81 | AliasesToExport = @()
82 |
83 | # DSC resources to export from this module
84 | # DscResourcesToExport = @()
85 |
86 | # List of all modules packaged with this module
87 | # ModuleList = @()
88 |
89 | # List of all files packaged with this module
90 | # FileList = @()
91 |
92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
93 | PrivateData = @{
94 |
95 | PSData = @{
96 |
97 | # Tags applied to this module. These help with module discovery in online galleries.
98 | # Tags = @()
99 |
100 | # A URL to the license for this module.
101 | LicenseUri = 'https://github.com/En3Tho/PoshRedisViewer/blob/main/LICENSE'
102 |
103 | # A URL to the main website for this project.
104 | ProjectUri = 'https://github.com/En3Tho/PoshRedisViewer'
105 |
106 | # A URL to an icon representing this module.
107 | # IconUri = ''
108 |
109 | # ReleaseNotes of this module
110 | # ReleaseNotes = ''
111 |
112 | # Prerelease string of this module
113 | # Prerelease = ''
114 |
115 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save
116 | # RequireLicenseAcceptance = $false
117 |
118 | # External dependent modules of this module
119 | # ExternalModuleDependencies = @()
120 |
121 | } # End of PSData hashtable
122 |
123 | } # End of PrivateData hashtable
124 |
125 | # HelpInfo URI of this module
126 | # HelpInfoURI = ''
127 |
128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
129 | # DefaultCommandPrefix = ''
130 |
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/Releases/0.0.5/StackExchange.Redis.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/StackExchange.Redis.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/System.IO.Pipelines.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/System.IO.Pipelines.dll
--------------------------------------------------------------------------------
/Releases/0.0.5/Terminal.Gui.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.5/Terminal.Gui.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/En3Tho.FSharp.ComputationExpressions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/En3Tho.FSharp.ComputationExpressions.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/En3Tho.FSharp.Extensions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/En3Tho.FSharp.Extensions.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/FSharp.Core.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/FSharp.Core.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/NStack.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/NStack.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/Pipelines.Sockets.Unofficial.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/Pipelines.Sockets.Unofficial.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/PoshRedisViewer.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/PoshRedisViewer.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/PoshRedisViewerModule.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/PoshRedisViewerModule.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/PoshRedisViewerModule.psd1:
--------------------------------------------------------------------------------
1 | #
2 | # Module manifest for module 'PoshRedisViewerModule'
3 | #
4 | # Generated by: Rzrl
5 | #
6 | # Generated on: 25.09.2021
7 | #
8 |
9 | @{
10 |
11 | # Script module or binary module file associated with this manifest.
12 | RootModule = 'PoshRedisViewerModule.dll'
13 |
14 | # Version number of this module.
15 | ModuleVersion = '0.0.6'
16 |
17 | # Supported PSEditions
18 | # CompatiblePSEditions = @()
19 |
20 | # ID used to uniquely identify this module
21 | GUID = '0c79ae41-ea88-4f75-94f4-17a31572e263'
22 |
23 | # Author of this module
24 | Author = 'Igor Bagdmamyan'
25 |
26 | # Company or vendor of this module
27 | CompanyName = 'Igor Bagdmamyan'
28 |
29 | # Copyright statement for this module
30 | Copyright = '(c) Igor Bagdmamyan. All rights reserved.'
31 |
32 | # Description of the functionality provided by this module
33 | Description = 'A simple Redis viewer capable of readonly operations'
34 |
35 | # Minimum version of the PowerShell engine required by this module
36 | PowerShellVersion = '7.1.3'
37 |
38 | # Name of the PowerShell host required by this module
39 | # PowerShellHostName = ''
40 |
41 | # Minimum version of the PowerShell host required by this module
42 | # PowerShellHostVersion = ''
43 |
44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45 | # DotNetFrameworkVersion = ''
46 |
47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48 | # ClrVersion = ''
49 |
50 | # Processor architecture (None, X86, Amd64) required by this module
51 | # ProcessorArchitecture = ''
52 |
53 | # Modules that must be imported into the global environment prior to importing this module
54 | # RequiredModules = @()
55 |
56 | # Assemblies that must be loaded prior to importing this module
57 | # RequiredAssemblies = @()
58 |
59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module.
60 | # ScriptsToProcess = @()
61 |
62 | # Type files (.ps1xml) to be loaded when importing this module
63 | # TypesToProcess = @()
64 |
65 | # Format files (.ps1xml) to be loaded when importing this module
66 | # FormatsToProcess = @()
67 |
68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69 | # NestedModules = @()
70 |
71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72 | FunctionsToExport = @()
73 |
74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75 | CmdletsToExport = @('Get-RedisViewer')
76 |
77 | # Variables to export from this module
78 | VariablesToExport = '*'
79 |
80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81 | AliasesToExport = @()
82 |
83 | # DSC resources to export from this module
84 | # DscResourcesToExport = @()
85 |
86 | # List of all modules packaged with this module
87 | # ModuleList = @()
88 |
89 | # List of all files packaged with this module
90 | # FileList = @()
91 |
92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
93 | PrivateData = @{
94 |
95 | PSData = @{
96 |
97 | # Tags applied to this module. These help with module discovery in online galleries.
98 | # Tags = @()
99 |
100 | # A URL to the license for this module.
101 | LicenseUri = 'https://github.com/En3Tho/PoshRedisViewer/blob/main/LICENSE'
102 |
103 | # A URL to the main website for this project.
104 | ProjectUri = 'https://github.com/En3Tho/PoshRedisViewer'
105 |
106 | # A URL to an icon representing this module.
107 | # IconUri = ''
108 |
109 | # ReleaseNotes of this module
110 | # ReleaseNotes = ''
111 |
112 | # Prerelease string of this module
113 | # Prerelease = ''
114 |
115 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save
116 | # RequireLicenseAcceptance = $false
117 |
118 | # External dependent modules of this module
119 | # ExternalModuleDependencies = @()
120 |
121 | } # End of PSData hashtable
122 |
123 | } # End of PrivateData hashtable
124 |
125 | # HelpInfo URI of this module
126 | # HelpInfoURI = ''
127 |
128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
129 | # DefaultCommandPrefix = ''
130 |
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/Releases/0.0.6/StackExchange.Redis.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/StackExchange.Redis.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/System.IO.Pipelines.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/System.IO.Pipelines.dll
--------------------------------------------------------------------------------
/Releases/0.0.6/Terminal.Gui.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.6/Terminal.Gui.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/En3Tho.FSharp.ComputationExpressions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/En3Tho.FSharp.ComputationExpressions.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/En3Tho.FSharp.Extensions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/En3Tho.FSharp.Extensions.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/FSharp.Core.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/FSharp.Core.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/NStack.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/NStack.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/Pipelines.Sockets.Unofficial.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/Pipelines.Sockets.Unofficial.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/PoshRedisViewer.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/PoshRedisViewer.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/PoshRedisViewerModule.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/PoshRedisViewerModule.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/PoshRedisViewerModule.psd1:
--------------------------------------------------------------------------------
1 | #
2 | # Module manifest for module 'PoshRedisViewerModule'
3 | #
4 | # Generated by: Rzrl
5 | #
6 | # Generated on: 25.09.2021
7 | #
8 |
9 | @{
10 |
11 | # Script module or binary module file associated with this manifest.
12 | RootModule = 'PoshRedisViewerModule.dll'
13 |
14 | # Version number of this module.
15 | ModuleVersion = '0.0.7'
16 |
17 | # Supported PSEditions
18 | # CompatiblePSEditions = @()
19 |
20 | # ID used to uniquely identify this module
21 | GUID = '0c79ae41-ea88-4f75-94f4-17a31572e263'
22 |
23 | # Author of this module
24 | Author = 'Igor Bagdmamyan'
25 |
26 | # Company or vendor of this module
27 | CompanyName = 'Igor Bagdmamyan'
28 |
29 | # Copyright statement for this module
30 | Copyright = '(c) Igor Bagdmamyan. All rights reserved.'
31 |
32 | # Description of the functionality provided by this module
33 | Description = 'A simple Redis viewer capable of readonly operations'
34 |
35 | # Minimum version of the PowerShell engine required by this module
36 | PowerShellVersion = '7.1.3'
37 |
38 | # Name of the PowerShell host required by this module
39 | # PowerShellHostName = ''
40 |
41 | # Minimum version of the PowerShell host required by this module
42 | # PowerShellHostVersion = ''
43 |
44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45 | # DotNetFrameworkVersion = ''
46 |
47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48 | # ClrVersion = ''
49 |
50 | # Processor architecture (None, X86, Amd64) required by this module
51 | # ProcessorArchitecture = ''
52 |
53 | # Modules that must be imported into the global environment prior to importing this module
54 | # RequiredModules = @()
55 |
56 | # Assemblies that must be loaded prior to importing this module
57 | # RequiredAssemblies = @()
58 |
59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module.
60 | # ScriptsToProcess = @()
61 |
62 | # Type files (.ps1xml) to be loaded when importing this module
63 | # TypesToProcess = @()
64 |
65 | # Format files (.ps1xml) to be loaded when importing this module
66 | # FormatsToProcess = @()
67 |
68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69 | # NestedModules = @()
70 |
71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72 | FunctionsToExport = @()
73 |
74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75 | CmdletsToExport = @('Get-RedisViewer')
76 |
77 | # Variables to export from this module
78 | VariablesToExport = '*'
79 |
80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81 | AliasesToExport = @()
82 |
83 | # DSC resources to export from this module
84 | # DscResourcesToExport = @()
85 |
86 | # List of all modules packaged with this module
87 | # ModuleList = @()
88 |
89 | # List of all files packaged with this module
90 | # FileList = @()
91 |
92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
93 | PrivateData = @{
94 |
95 | PSData = @{
96 |
97 | # Tags applied to this module. These help with module discovery in online galleries.
98 | # Tags = @()
99 |
100 | # A URL to the license for this module.
101 | LicenseUri = 'https://github.com/En3Tho/PoshRedisViewer/blob/main/LICENSE'
102 |
103 | # A URL to the main website for this project.
104 | ProjectUri = 'https://github.com/En3Tho/PoshRedisViewer'
105 |
106 | # A URL to an icon representing this module.
107 | # IconUri = ''
108 |
109 | # ReleaseNotes of this module
110 | # ReleaseNotes = ''
111 |
112 | # Prerelease string of this module
113 | # Prerelease = ''
114 |
115 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save
116 | # RequireLicenseAcceptance = $false
117 |
118 | # External dependent modules of this module
119 | # ExternalModuleDependencies = @()
120 |
121 | } # End of PSData hashtable
122 |
123 | } # End of PrivateData hashtable
124 |
125 | # HelpInfo URI of this module
126 | # HelpInfoURI = ''
127 |
128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
129 | # DefaultCommandPrefix = ''
130 |
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/Releases/0.0.7/StackExchange.Redis.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/StackExchange.Redis.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/System.IO.Pipelines.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/System.IO.Pipelines.dll
--------------------------------------------------------------------------------
/Releases/0.0.7/Terminal.Gui.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.7/Terminal.Gui.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/En3Tho.FSharp.ComputationExpressions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/En3Tho.FSharp.ComputationExpressions.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/En3Tho.FSharp.Extensions.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/En3Tho.FSharp.Extensions.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/FSharp.Core.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/FSharp.Core.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/NStack.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/NStack.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/Pipelines.Sockets.Unofficial.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/Pipelines.Sockets.Unofficial.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/PoshRedisViewer.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/PoshRedisViewer.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/PoshRedisViewerModule.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/PoshRedisViewerModule.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/PoshRedisViewerModule.psd1:
--------------------------------------------------------------------------------
1 | #
2 | # Module manifest for module 'PoshRedisViewerModule'
3 | #
4 | # Generated by: Rzrl
5 | #
6 | # Generated on: 25.09.2021
7 | #
8 |
9 | @{
10 |
11 | # Script module or binary module file associated with this manifest.
12 | RootModule = 'PoshRedisViewerModule.dll'
13 |
14 | # Version number of this module.
15 | ModuleVersion = '0.0.7'
16 |
17 | # Supported PSEditions
18 | # CompatiblePSEditions = @()
19 |
20 | # ID used to uniquely identify this module
21 | GUID = '0c79ae41-ea88-4f75-94f4-17a31572e263'
22 |
23 | # Author of this module
24 | Author = 'Igor Bagdmamyan'
25 |
26 | # Company or vendor of this module
27 | CompanyName = 'Igor Bagdmamyan'
28 |
29 | # Copyright statement for this module
30 | Copyright = '(c) Igor Bagdmamyan. All rights reserved.'
31 |
32 | # Description of the functionality provided by this module
33 | Description = 'A simple Redis viewer capable of readonly operations'
34 |
35 | # Minimum version of the PowerShell engine required by this module
36 | PowerShellVersion = '7.1.3'
37 |
38 | # Name of the PowerShell host required by this module
39 | # PowerShellHostName = ''
40 |
41 | # Minimum version of the PowerShell host required by this module
42 | # PowerShellHostVersion = ''
43 |
44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45 | # DotNetFrameworkVersion = ''
46 |
47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48 | # ClrVersion = ''
49 |
50 | # Processor architecture (None, X86, Amd64) required by this module
51 | # ProcessorArchitecture = ''
52 |
53 | # Modules that must be imported into the global environment prior to importing this module
54 | # RequiredModules = @()
55 |
56 | # Assemblies that must be loaded prior to importing this module
57 | # RequiredAssemblies = @()
58 |
59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module.
60 | # ScriptsToProcess = @()
61 |
62 | # Type files (.ps1xml) to be loaded when importing this module
63 | # TypesToProcess = @()
64 |
65 | # Format files (.ps1xml) to be loaded when importing this module
66 | # FormatsToProcess = @()
67 |
68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69 | # NestedModules = @()
70 |
71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72 | FunctionsToExport = @()
73 |
74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75 | CmdletsToExport = @('Get-RedisViewer')
76 |
77 | # Variables to export from this module
78 | VariablesToExport = '*'
79 |
80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81 | AliasesToExport = @()
82 |
83 | # DSC resources to export from this module
84 | # DscResourcesToExport = @()
85 |
86 | # List of all modules packaged with this module
87 | # ModuleList = @()
88 |
89 | # List of all files packaged with this module
90 | # FileList = @()
91 |
92 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
93 | PrivateData = @{
94 |
95 | PSData = @{
96 |
97 | # Tags applied to this module. These help with module discovery in online galleries.
98 | # Tags = @()
99 |
100 | # A URL to the license for this module.
101 | LicenseUri = 'https://github.com/En3Tho/PoshRedisViewer/blob/main/LICENSE'
102 |
103 | # A URL to the main website for this project.
104 | ProjectUri = 'https://github.com/En3Tho/PoshRedisViewer'
105 |
106 | # A URL to an icon representing this module.
107 | # IconUri = ''
108 |
109 | # ReleaseNotes of this module
110 | # ReleaseNotes = ''
111 |
112 | # Prerelease string of this module
113 | # Prerelease = ''
114 |
115 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save
116 | # RequireLicenseAcceptance = $false
117 |
118 | # External dependent modules of this module
119 | # ExternalModuleDependencies = @()
120 |
121 | } # End of PSData hashtable
122 |
123 | } # End of PrivateData hashtable
124 |
125 | # HelpInfo URI of this module
126 | # HelpInfoURI = ''
127 |
128 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
129 | # DefaultCommandPrefix = ''
130 |
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/Releases/0.0.8/StackExchange.Redis.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/StackExchange.Redis.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/System.IO.Pipelines.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/System.IO.Pipelines.dll
--------------------------------------------------------------------------------
/Releases/0.0.8/Terminal.Gui.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/Releases/0.0.8/Terminal.Gui.dll
--------------------------------------------------------------------------------
/fish-haddock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/fish-haddock.png
--------------------------------------------------------------------------------
/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/En3Tho/PoshRedisViewer/10f1ff7e873787501f4d3040bfa8d3de1a897c26/img.png
--------------------------------------------------------------------------------