Skip to content

Commit edb3931

Browse files
committed
auth and upload
1 parent dfde1b6 commit edb3931

25 files changed

+368
-99
lines changed

PowerSession.Cli/PowerSession.Cli.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14-
<ProjectReference Include="..\PowerSession.Commands\PowerSession.Commands.csproj" />
1514
<ProjectReference Include="..\PowerSession.ConPTY\PowerSession.ConPTY.csproj" />
15+
<ProjectReference Include="..\PowerSession.Main\PowerSession.Main.csproj" />
1616
</ItemGroup>
1717

1818
<ItemGroup>

PowerSession.Cli/Program.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.CommandLine.Invocation;
55
using System.IO;
66
using Commands;
7+
using Main.Commands;
78

89
internal static class Program
910
{
@@ -33,13 +34,34 @@ private static void Main(string[] args)
3334
playCommand.Execute();
3435
});
3536

37+
var auth = new Command("auth")
38+
{
39+
Handler = CommandHandler.Create(() =>
40+
{
41+
var authCommand = new AuthCommand();
42+
authCommand.Execute();
43+
})
44+
};
45+
46+
var upload = new Command("upload")
47+
{
48+
new Argument<FileInfo>("file")
49+
};
50+
upload.Handler = CommandHandler.Create((FileInfo file) =>
51+
{
52+
var uploadCommand = new UploadCommand(file.FullName);
53+
uploadCommand.Execute();
54+
});
55+
3656
var rooCommand = new RootCommand
3757
{
3858
record,
39-
play
59+
play,
60+
auth,
61+
upload
4062
};
4163

42-
rooCommand.Description = "PowerSession";
64+
rooCommand.Description = "PowerSession.Main";
4365

4466
rooCommand.InvokeAsync(args).Wait();
4567
}

PowerSession.Commands/Command.cs

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

PowerSession.ConPTY/Native/ConsoleApi.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace PowerSession.ConPTY.Native
1+
namespace PowerSession.Main.ConPTY.Native
22
{
33
using System;
44
using System.Runtime.InteropServices;

PowerSession.ConPTY/Native/ProcessApi.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace PowerSession.ConPTY.Native
1+
namespace PowerSession.Main.ConPTY.Native
22
{
33
using System;
44
using System.Runtime.InteropServices;

PowerSession.ConPTY/Native/PseudoConsoleApi.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace PowerSession.ConPTY.Native
1+
namespace PowerSession.Main.ConPTY.Native
22
{
33
using System;
44
using System.Runtime.InteropServices;

PowerSession.ConPTY/Processes/Process.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
using static PowerSession.ConPTY.Native.ProcessApi;
1+
using static PowerSession.Main.ConPTY.Native.ProcessApi;
22

3-
namespace PowerSession.ConPTY.Processes
3+
namespace PowerSession.Main.ConPTY.Processes
44
{
55
using System;
66
using System.Runtime.InteropServices;
7+
using Native;
78

89
internal sealed class Process : IDisposable
910
{
10-
public Process(STARTUPINFOEX startupInfo, PROCESS_INFORMATION processInfo)
11+
public Process(ProcessApi.STARTUPINFOEX startupInfo, ProcessApi.PROCESS_INFORMATION processInfo)
1112
{
1213
StartupInfo = startupInfo;
1314
ProcessInfo = processInfo;
1415
}
1516

16-
public STARTUPINFOEX StartupInfo { get; }
17-
public PROCESS_INFORMATION ProcessInfo { get; }
17+
public ProcessApi.STARTUPINFOEX StartupInfo { get; }
18+
public ProcessApi.PROCESS_INFORMATION ProcessInfo { get; }
1819

1920
#region IDisposable Support
2021

PowerSession.ConPTY/Processes/ProcessFactory.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
using static PowerSession.ConPTY.Native.ProcessApi;
1+
using static PowerSession.Main.ConPTY.Native.ProcessApi;
22

3-
namespace PowerSession.ConPTY.Processes
3+
namespace PowerSession.Main.ConPTY.Processes
44
{
55
using System;
66
using System.ComponentModel;
77
using System.Runtime.InteropServices;
8+
using Native;
89

910
internal static class ProcessFactory
1011
{
@@ -18,7 +19,7 @@ internal static Process Start(string command, IntPtr attributes, IntPtr hPC)
1819
return new Process(startupInfo, processInfo);
1920
}
2021

21-
private static STARTUPINFOEX ConfigureProcessThread(IntPtr hPC, IntPtr attributes)
22+
private static ProcessApi.STARTUPINFOEX ConfigureProcessThread(IntPtr hPC, IntPtr attributes)
2223
{
2324
// this method implements the behavior described in https://docs.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session#preparing-for-creation-of-the-child-process
2425

@@ -34,8 +35,8 @@ ref lpSize
3435
throw new Win32Exception(Marshal.GetLastWin32Error(),
3536
"Could not calculate the number of bytes for the attribute list.");
3637

37-
var startupInfo = new STARTUPINFOEX();
38-
startupInfo.StartupInfo.cb = Marshal.SizeOf<STARTUPINFOEX>();
38+
var startupInfo = new ProcessApi.STARTUPINFOEX();
39+
startupInfo.StartupInfo.cb = Marshal.SizeOf<ProcessApi.STARTUPINFOEX>();
3940
startupInfo.lpAttributeList = Marshal.AllocHGlobal(lpSize);
4041

4142
success = InitializeProcThreadAttributeList(
@@ -61,11 +62,11 @@ ref lpSize
6162
return startupInfo;
6263
}
6364

64-
private static PROCESS_INFORMATION RunProcess(ref STARTUPINFOEX sInfoEx, string commandLine)
65+
private static ProcessApi.PROCESS_INFORMATION RunProcess(ref ProcessApi.STARTUPINFOEX sInfoEx, string commandLine)
6566
{
66-
var securityAttributeSize = Marshal.SizeOf<SECURITY_ATTRIBUTES>();
67-
var pSec = new SECURITY_ATTRIBUTES {nLength = securityAttributeSize};
68-
var tSec = new SECURITY_ATTRIBUTES {nLength = securityAttributeSize};
67+
var securityAttributeSize = Marshal.SizeOf<ProcessApi.SECURITY_ATTRIBUTES>();
68+
var pSec = new ProcessApi.SECURITY_ATTRIBUTES {nLength = securityAttributeSize};
69+
var tSec = new ProcessApi.SECURITY_ATTRIBUTES {nLength = securityAttributeSize};
6970
var success = CreateProcess(
7071
null,
7172
commandLine,

PowerSession.ConPTY/PseudoConsole.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
using static PowerSession.ConPTY.Native.PseudoConsoleApi;
1+
using static PowerSession.Main.ConPTY.Native.PseudoConsoleApi;
22

3-
namespace PowerSession.ConPTY
3+
namespace PowerSession.Main.ConPTY
44
{
55
using System;
66
using System.ComponentModel;
77
using Microsoft.Win32.SafeHandles;
8+
using Native;
89

910
internal sealed class PseudoConsole : IDisposable
1011
{
@@ -26,7 +27,7 @@ internal static PseudoConsole Create(SafeFileHandle inputReadSide, SafeFileHandl
2627
int height)
2728
{
2829
var createResult = CreatePseudoConsole(
29-
new COORD {X = (short) width, Y = (short) height},
30+
new PseudoConsoleApi.COORD {X = (short) width, Y = (short) height},
3031
inputReadSide, outputWriteSide,
3132
0, out var hPC);
3233
if (createResult != 0) throw new Win32Exception(createResult, "Failed to create pseudo console.");

PowerSession.ConPTY/PseudoConsolePipe.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using static PowerSession.ConPTY.Native.PseudoConsoleApi;
1+
using static PowerSession.Main.ConPTY.Native.PseudoConsoleApi;
22

3-
namespace PowerSession.ConPTY
3+
namespace PowerSession.Main.ConPTY
44
{
55
using System;
66
using System.ComponentModel;

PowerSession.ConPTY/Terminal.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
using static PowerSession.ConPTY.Native.ConsoleApi;
1+
using static PowerSession.Main.ConPTY.Native.ConsoleApi;
22

3-
namespace PowerSession.ConPTY
3+
namespace PowerSession.Main.ConPTY
44
{
55
using System;
66
using System.Collections;
77
using System.IO;
88
using System.Threading;
99
using System.Threading.Tasks;
1010
using Microsoft.Win32.SafeHandles;
11+
using Native;
1112
using Processes;
1213

1314
public sealed class Terminal
@@ -16,14 +17,16 @@ public sealed class Terminal
1617

1718
private readonly Stream _inputReader;
1819
private readonly Stream _outputWriter;
19-
public readonly int Height;
20-
21-
public readonly int Width;
20+
private readonly int _height;
21+
private readonly int _width;
2222

2323
private SafeFileHandle _consoleInputPipeWriteHandle;
2424
private StreamWriter _consoleInputWriter;
2525
private FileStream _consoleOutStream;
2626

27+
private readonly CancellationTokenSource _tokenSource;
28+
private readonly CancellationToken _token;
29+
2730
public Terminal(Stream inputReader = null, Stream outputWriter = null, bool enableAnsiEscape = true,
2831
int width = default, int height = default)
2932
{
@@ -43,15 +46,18 @@ public Terminal(Stream inputReader = null, Stream outputWriter = null, bool enab
4346
}
4447
}
4548

46-
Width = width == 0 ? Console.WindowWidth : width;
47-
Height = height == 0 ? Console.WindowHeight : height;
49+
_width = width == 0 ? Console.WindowWidth : width;
50+
_height = height == 0 ? Console.WindowHeight : height;
51+
52+
_tokenSource = new CancellationTokenSource();
53+
_token = _tokenSource.Token;
4854
}
4955

5056
public void Record(string command, IDictionary environment = null)
5157
{
5258
using var inputPipe = new PseudoConsolePipe();
5359
using var outputPipe = new PseudoConsolePipe();
54-
using var pseudoConsole = PseudoConsole.Create(inputPipe.ReadSide, outputPipe.WriteSide, Width, Height);
60+
using var pseudoConsole = PseudoConsole.Create(inputPipe.ReadSide, outputPipe.WriteSide, _width, _height);
5561
using var process = ProcessFactory.Start(command, PseudoConsole.PseudoConsoleThreadAttribute,
5662
pseudoConsole.Handle);
5763
_consoleOutStream = new FileStream(outputPipe.ReadSide, FileAccess.Read);
@@ -67,6 +73,7 @@ public void Record(string command, IDictionary environment = null)
6773
_consoleOutStream));
6874
WaitForExit(process).WaitOne(Timeout.Infinite);
6975

76+
_tokenSource.Cancel();
7077
_consoleOutStream.Close();
7178
_consoleInputWriter.Close();
7279
_outputWriter.Close();
@@ -82,8 +89,11 @@ private void AttachStdin()
8289

8390
Task.Factory.StartNew(() =>
8491
{
85-
ConsoleKeyInfo key;
86-
while ((key = Console.ReadKey(true)).Key != ConsoleKey.Escape) _consoleInputWriter.Write(key.KeyChar);
92+
while (!_token.IsCancellationRequested)
93+
{
94+
var key = Console.ReadKey(true);
95+
_consoleInputWriter.Write(key.KeyChar);
96+
}
8797
}, TaskCreationOptions.LongRunning);
8898
}
8999

@@ -107,7 +117,7 @@ private static void OnClose(Action handler)
107117
{
108118
SetConsoleCtrlHandler(eventType =>
109119
{
110-
if (eventType == CtrlTypes.CTRL_CLOSE_EVENT) handler();
120+
if (eventType == ConsoleApi.CtrlTypes.CTRL_CLOSE_EVENT) handler();
111121
return false;
112122
}, true);
113123
}

PowerSession.Main/Api/AsciinemaApi.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
namespace PowerSession.Main.Api
2+
{
3+
using System;
4+
using System.IO;
5+
using System.Net.Http;
6+
using System.Net.Http.Headers;
7+
using System.Runtime.InteropServices;
8+
using System.Text;
9+
using PowerSession.Api;
10+
11+
public class AsciinemaApi : IApiService
12+
{
13+
private readonly HttpClient _httpClient;
14+
private string ApiHost = "https://asciinema.org";
15+
private string AuthUrl => $"{ApiHost}/connect/{AppConfig.InstallId}";
16+
private string UploadUrl => $"{ApiHost}/api/asciicasts";
17+
18+
private static readonly string RuntimeFramework = $"NetCoreApp/{Environment.Version.Major}.{Environment.Version.Minor}";
19+
private static readonly string OperatingSystem = $"Windows {Environment.OSVersion.Version.Major}-{Environment.OSVersion.VersionString}";
20+
21+
public string Upload(string filePath)
22+
{
23+
var req = new MultipartFormDataContent();
24+
var cast = new ByteArrayContent(File.ReadAllBytes(filePath));
25+
cast.Headers.ContentType = MediaTypeHeaderValue.Parse(System.Net.Mime.MediaTypeNames.Text.Plain);
26+
req.Add(cast, "asciicast", "ascii.cast");
27+
28+
var res = _httpClient.PostAsync(UploadUrl, req).Result;
29+
if (!res.IsSuccessStatusCode)
30+
{
31+
Console.WriteLine("Upload Failed:");
32+
Console.WriteLine(res.Content.ReadAsStringAsync().Result);
33+
return null;
34+
}
35+
return res.Headers.Location.ToString();
36+
}
37+
38+
public AsciinemaApi()
39+
{
40+
_httpClient = new HttpClient();
41+
_httpClient.DefaultRequestHeaders.Accept.Clear();
42+
_httpClient.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(System.Net.Mime.MediaTypeNames.Application.Json));
43+
44+
_httpClient.DefaultRequestHeaders.Add("User-Agent",$"asciinema/2.0.0 {RuntimeFramework} {OperatingSystem}");
45+
46+
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"user:{AppConfig.InstallId}")));
47+
}
48+
49+
public void Auth()
50+
{
51+
Console.WriteLine("Open the following URL in a web browser to link your" +
52+
$"install ID with your {ApiHost} user account:\n\n" +
53+
$"{AuthUrl}\n\n" +
54+
"This will associate all recordings uploaded from this machine " +
55+
"(past and future ones) to your account, " +
56+
$"and allow you to manage them (change title/theme, delete) at {ApiHost}.");
57+
}
58+
}
59+
}

PowerSession.Main/Api/IApiService.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace PowerSession.Api
2+
{
3+
public interface IApiService
4+
{
5+
void Auth();
6+
string Upload(string filePath);
7+
}
8+
}

0 commit comments

Comments
 (0)