master
cs 117 lines 3.75 KB
Raw
1 // WSLC-CustomContainer
2 //
3 // A barebones Windows console application that turns text (e.g. a URL) into a
4 // scannable QR code, rendered by a tiny Python tool running inside a *custom*
5 // Linux container.
6 //
7 // What makes this sample different from the others: it ships its own
8 // Containerfile that is built automatically as part of the normal build (F5)
9 // via the <WslcImage> item in WSLCCustomContainer.csproj. The built image is
10 // saved to customcontainer.tar next to the executable, and this app loads that
11 // local tar (no registry pull) before running the tool.
12 //
13 // dotnet run -- "https://aka.ms/wslc"
14
15 using Microsoft.WSL.Containers;
16
17 const string imageName = "customcontainer:latest";
18
19 // The text to encode comes from the command line; fall back to a sample URL.
20 string text = args.Length > 0 ? string.Join(' ', args) : "https://aka.ms/wslc";
21
22 // Everything lives beside the executable — no hard-coded absolute paths. The
23 // container image tar is produced next to the exe by the build.
24 string baseDir = AppContext.BaseDirectory;
25 string sessionPath = Path.Combine(baseDir, "WslcQrStorage");
26 string imageTarPath = Path.Combine(baseDir, "customcontainer.tar");
27
28 if (!File.Exists(imageTarPath))
29 {
30 Console.Error.WriteLine($"[wslc] Image tar not found: {imageTarPath}");
31 Console.Error.WriteLine("[wslc] Build the project first so the custom image is auto-built.");
32 return 1;
33 }
34
35 int exitCode = 1;
36 using var stopEvent = new ManualResetEventSlim(false);
37 var consoleLock = new object();
38 using Stream stdout = Console.OpenStandardOutput();
39 using Stream stderr = Console.OpenStandardError();
40
41 void Write(Stream target, byte[] data)
42 {
43 lock (consoleLock)
44 {
45 target.Write(data, 0, data.Length);
46 target.Flush();
47 }
48 }
49
50 try
51 {
52 // ---- Session ----
53 Console.Error.WriteLine("[wslc] Creating session...");
54 var sessionSettings = new SessionSettings("WSLCCustomContainer", sessionPath)
55 {
56 CpuCount = 2,
57 MemorySizeInMB = 2048,
58 VhdRequirements = new VhdOptions(string.Empty, 4UL * 1024 * 1024 * 1024, VhdType.Dynamic),
59 };
60
61 using var session = new Session(sessionSettings);
62 session.Start();
63
64 // ---- Load the locally built image from the tar (no registry pull) ----
65 Console.Error.WriteLine($"[wslc] Loading image from {Path.GetFileName(imageTarPath)}...");
66 session.LoadImage(imageTarPath);
67
68 // ---- Create & start container ----
69 Console.Error.WriteLine("[wslc] Starting container...");
70
71 // The init process keeps the container alive while we exec our tool.
72 var initProcess = new ProcessSettings
73 {
74 CommandLine = new List<string> { "/bin/sleep", "infinity" },
75 };
76
77 var containerSettings = new ContainerSettings(imageName)
78 {
79 InitProcess = initProcess,
80 EnableAutoRemove = true,
81 };
82
83 using var container = session.CreateContainer(containerSettings);
84 container.Start();
85
86 // ---- Exec the QR tool, passing the text to encode ----
87 Console.Error.WriteLine($"[wslc] Generating QR code for: {text}");
88 Console.Error.WriteLine();
89
90 var processSettings = new ProcessSettings
91 {
92 CommandLine = new List<string> { "python", "/app/qr.py", text },
93 OutputMode = ProcessOutputMode.Event,
94 };
95
96 using var process = container.CreateProcess(processSettings);
97 process.OutputReceived += data => Write(stdout, data);
98 process.ErrorReceived += data => Write(stderr, data);
99 process.Exited += code =>
100 {
101 exitCode = code;
102 stopEvent.Set();
103 };
104
105 process.Start();
106 stopEvent.Wait();
107
108 Console.Error.WriteLine("[wslc] Shutting down...");
109 container.Stop(Signal.SIGTERM, TimeSpan.FromSeconds(10));
110 session.Terminate();
111 }
112 catch (Exception ex)
113 {
114 Console.Error.WriteLine($"[wslc] Error: {ex.Message}");
115 }
116
117 return exitCode;