Skip to content

Commit 3021539

Browse files
authored
Merge pull request #21 from open-olive/SIDE-1007/csharp-ldk-complete
[SIDE-1007] C# LDK Completion
2 parents 26d7d42 + 7f3670f commit 3021539

File tree

128 files changed

+3134
-500
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+3134
-500
lines changed

.github/workflows/csharp.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
on: [ push, pull_request ]
2+
name: C# Build
3+
defaults:
4+
run:
5+
working-directory: ldk/csharp
6+
jobs:
7+
build:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v2
11+
- uses: actions/setup-dotnet@v1
12+
with:
13+
dotnet-version: '3.1.x'
14+
- run: dotnet build OliveHelpsLDK

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Loop Development Kit
2+
3+
This is the central repository for all the Olive Help LDKs. You'll probably want to look at the individual LDK readmes in the `ldk\{language}` folder.
4+
5+
## Developing
6+
7+
### LDK Contract
8+
9+
Each LDK must adhere to this contract:
10+
11+
- They should start a GRPC server serving the following services:
12+
- `proto.Loop`
13+
- `plugin.Broker`
14+
- `plugin.Stdio`
15+
- When started up they write to STDOUT a connection string in the following format: `1|1|tcp|{HOST}:{PORT}|grpc`.
16+
- They do not write anything else to STDOUT until the Go LDK LoopClient calls the `proto.Loop.LoopStart` rpc.
17+
- The `LoopStart` rpc should complete once the Loop is started, it should not wait until the Loop is complete.
18+
- Their logger should write to STDERR single line JSON objects with the following properties:
19+
- `@timestamp` - The current timestamp in the format `yyyy-MM-ddTHH:mm:ss.ffffffzzz`. Seconds to the 6th decimal point is required, otherwise the logger will fail to parse the message and will log the JSON to the logs.
20+
- `@level` - The logging level (one of `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`)
21+
- `@module` - The name of the module, usually the loop name.
22+
- `@pid` - The Loop's process ID.
23+
- `@message` - The message to log.
24+
- and other properties as appropriate.
25+

ldk/csharp/OliveHelpsLDK/Console/Program.cs

Lines changed: 0 additions & 71 deletions
This file was deleted.

ldk/csharp/OliveHelpsLDK/Console/Console.csproj renamed to ldk/csharp/OliveHelpsLDK/Example/Example.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<PropertyGroup>
44
<TargetFramework>netcoreapp3.1</TargetFramework>
55
<OutputType>Exe</OutputType>
6+
<AssemblyName>Example</AssemblyName>
7+
<RootNamespace>Example</RootNamespace>
68
</PropertyGroup>
79

810
<ItemGroup>
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using OliveHelpsLDK;
6+
using OliveHelpsLDK.Logging;
7+
using OliveHelpsLDK.Whispers;
8+
using OliveHelpsLDK.Whispers.Forms;
9+
using OliveHelpsLDK.Whispers.Forms.Outputs;
10+
using Checkbox = OliveHelpsLDK.Whispers.Forms.Inputs.Checkbox;
11+
using Email = OliveHelpsLDK.Whispers.Forms.Inputs.Email;
12+
using IBase = OliveHelpsLDK.Whispers.Forms.Inputs.IBase;
13+
using ICheckbox = OliveHelpsLDK.Whispers.Forms.Outputs.ICheckbox;
14+
using IEmail = OliveHelpsLDK.Whispers.Forms.Outputs.IEmail;
15+
using IMarkdown = OliveHelpsLDK.Whispers.Forms.Outputs.IMarkdown;
16+
using Markdown = OliveHelpsLDK.Whispers.Forms.Inputs.Markdown;
17+
using Number = OliveHelpsLDK.Whispers.Forms.Inputs.Number;
18+
using Password = OliveHelpsLDK.Whispers.Forms.Inputs.Password;
19+
using Radio = OliveHelpsLDK.Whispers.Forms.Inputs.Radio;
20+
using Select = OliveHelpsLDK.Whispers.Forms.Inputs.Select;
21+
using Telephone = OliveHelpsLDK.Whispers.Forms.Inputs.Telephone;
22+
using Text = OliveHelpsLDK.Whispers.Forms.Inputs.Text;
23+
using Time = OliveHelpsLDK.Whispers.Forms.Inputs.Time;
24+
25+
namespace Example
26+
{
27+
class Program
28+
{
29+
public static void Main(string[] args)
30+
{
31+
ILogger logger = new Logger("csharp-clipboard-example");
32+
LoopServer.Start(new Loop
33+
{
34+
Logger = logger
35+
}, logger);
36+
}
37+
}
38+
39+
class Loop : ILoop
40+
{
41+
private ILoopServices _services;
42+
43+
private IStreamingCall<string> _clipboardStream;
44+
45+
private IStreamingCall<string> _textStream;
46+
47+
public ILogger Logger;
48+
49+
public Task Start(ILoopServices services)
50+
{
51+
_services = services;
52+
ClipboardStream();
53+
return Task.CompletedTask;
54+
}
55+
56+
public Task Stop()
57+
{
58+
_services = null;
59+
_clipboardStream?.Dispose();
60+
return Task.CompletedTask;
61+
}
62+
63+
private void ClipboardStream()
64+
{
65+
_clipboardStream = _services.Clipboard.Stream();
66+
Task.Run(async () =>
67+
{
68+
while (await _clipboardStream.MoveNext())
69+
{
70+
try
71+
{
72+
var clipboardContent = _clipboardStream.Current();
73+
Logger.Info($"Received Clipboard Update \"{clipboardContent}\"");
74+
switch (clipboardContent)
75+
{
76+
case "formnew":
77+
FormStream();
78+
Logger.Info("Starting Form Stream");
79+
break;
80+
case "keystart":
81+
KeyboardStream();
82+
break;
83+
case "keystop":
84+
KeyboardStream(false);
85+
break;
86+
default:
87+
EmitWhisper(clipboardContent);
88+
break;
89+
}
90+
}
91+
catch (Exception e)
92+
{
93+
Logger.Error(e.ToString());
94+
}
95+
}
96+
});
97+
}
98+
99+
private void KeyboardStream(bool start = true)
100+
{
101+
if (start && _textStream == null)
102+
{
103+
_textStream = _services.Keyboard.StreamText();
104+
Task.Run(async () =>
105+
{
106+
while (await _textStream.MoveNext())
107+
{
108+
Logger.Info("Keyboard Stream Received",
109+
new Dictionary<string, object>() {["text"] = _textStream.Current()});
110+
}
111+
});
112+
}
113+
else if (start == false && _textStream != null)
114+
{
115+
_textStream?.Dispose();
116+
_textStream = null;
117+
}
118+
}
119+
120+
private void EmitWhisper(string content)
121+
{
122+
var ccs = new CancellationTokenSource();
123+
ccs.CancelAfter(5000);
124+
_services.Whisper.MarkdownAsync(new WhisperMarkdown
125+
{
126+
Markdown = $"Clipboard Content {content}",
127+
Config = new WhisperConfig
128+
{
129+
Icon = "bathtub",
130+
Label = "C# Whisper"
131+
}
132+
}, ccs.Token);
133+
Logger.Info($"Sent Clipboard Update {content}");
134+
}
135+
136+
private void FormStream()
137+
{
138+
var whisperForm = new WhisperForm
139+
{
140+
CancelLabel = "Cancel",
141+
SubmitLabel = "Submit",
142+
Config = new WhisperConfig
143+
{
144+
Icon = "bathtub",
145+
Label = "C# Whisper Form"
146+
},
147+
Inputs = new Dictionary<string, IBase>
148+
{
149+
["Checkbox"] = new Checkbox {Label = "checkbox", Tooltip = "checkbox tooltip", Value = true},
150+
["Email"] = new Email {Label = "email", Tooltip = "email tooltip", Value = "[email protected]"},
151+
["Markdown"] = new Markdown
152+
{Label = "markdown", Tooltip = "markdown tooltip", Value = "# Hello\n\n How are you"},
153+
["Number"] = new Number
154+
{Label = "number", Tooltip = "number tooltip", Value = 5, Max = 10, Min = 0},
155+
["Password"] = new Password {Label = "password", Tooltip = "password tooltip"},
156+
["Radio"] = new Radio
157+
{Label = "radio", Tooltip = "radio tooltip", Options = new[] {"Radio1", "Radio2"}},
158+
["Select"] = new Select
159+
{
160+
Label = "select", Tooltip = "select tooltip", Options = new[] {"Select1", "Select2"}
161+
},
162+
["Telephone"] = new Telephone
163+
{
164+
Label = "telephone", Tooltip = "telephone tooltip", Value = "888-777-6666",
165+
Pattern = "XXX-XXX-XXXX"
166+
},
167+
["Text"] = new Text {Label = "text", Tooltip = "text tooltip", Value = "Text"},
168+
["Time"] = new Time {Label = "time", Tooltip = "time tooltip", Value = DateTimeOffset.Now},
169+
}
170+
};
171+
var stream = _services.Whisper.FormAsync(whisperForm);
172+
Task.Run(async () =>
173+
{
174+
while (await stream.MoveNext())
175+
{
176+
switch (stream.Current())
177+
{
178+
case WhisperUpdate u:
179+
LogFormUpdate(u);
180+
break;
181+
case WhisperResult r:
182+
Logger.Info("Received Form Response");
183+
Logger.Info(r.IsSubmitted ? "Form Submitted" : "Form Rejected",
184+
r.Outputs as IDictionary<string, object>);
185+
186+
break;
187+
}
188+
}
189+
190+
Logger.Info("Form Ended");
191+
});
192+
}
193+
194+
private void LogFormUpdate(WhisperUpdate update)
195+
{
196+
switch (update.Output)
197+
{
198+
case null:
199+
Logger.Info("Form Update Null");
200+
break;
201+
case ICheckbox checkbox:
202+
Logger.Info("Form Update Checkbox",
203+
new Dictionary<string, object> {{"checkbox", checkbox.Value ? "true" : "false"}});
204+
break;
205+
case IEmail email:
206+
Logger.Info("Form Update Email", new Dictionary<string, object> {{"email", email.Value}});
207+
break;
208+
case IMarkdown markdown:
209+
Logger.Info("Form Update Markdown",
210+
new Dictionary<string, object> {{"markdown", markdown.Value}});
211+
break;
212+
case INone none:
213+
Logger.Info("Form Update None");
214+
break;
215+
case INumber number:
216+
Logger.Info("Form Update Number",
217+
new Dictionary<string, object> {{"number", number.Value.ToString()}});
218+
break;
219+
case IPassword password:
220+
Logger.Info("Form Update Password",
221+
new Dictionary<string, object> {{"password", password.Value}});
222+
break;
223+
case IRadio radio:
224+
Logger.Info("Form Update Radio",
225+
new Dictionary<string, object> {{"radio", radio.Value}});
226+
break;
227+
case ISelect select:
228+
Logger.Info("Form Update Select",
229+
new Dictionary<string, object> {{"select", select.Value}});
230+
break;
231+
case ITelephone telephone:
232+
Logger.Info("Form Update Telephone",
233+
new Dictionary<string, object> {{"telephone", telephone.Value}});
234+
break;
235+
case IText text:
236+
Logger.Info("Form Update Text",
237+
new Dictionary<string, object> {{"text", text.Value}});
238+
break;
239+
case ITime time:
240+
Logger.Info("Form Update Time",
241+
new Dictionary<string, object> {{"Time", time.Value.ToString()}});
242+
break;
243+
default:
244+
Logger.Warn("Form Update - Unexpected Type");
245+
break;
246+
}
247+
}
248+
}
249+
}

0 commit comments

Comments
 (0)