using System.Net; using System.Text; using System.Diagnostics; using System.Collections.Generic; using System.Linq; using System.IO; using System.Threading.Tasks; var port = 8230; var queue = new List(); var progress = 0; var total = 0; var delay = 850; var lastrun = DateTime.Now; HttpListener server = null; try { EnsureInventory(); var items = Inventory .Where(x => x.IsRecyclable) .GroupBy(x => x.GetDescriptor()) .Where(g => g.Count() >= 8) .Select(g => new { name = g.Key.GetName(), id = g.Key.GetInfo().Identifier, rev = g.Key.GetInfo().Revision, count = g.Count(), list = g.Select(i => (int)i.Id).ToList() }) .OrderByDescending(x => x.count) .ToList(); Log($"Found {items.Count} recyclable types (8+ items)"); items.ForEach(x => Log($" {x.name}: {x.count}x")); var json = "[" + string.Join(",", items.Select((item, i) => $"{{\"i\":{i},\"n\":\"{item.name.Replace("\"", "\\\"")}\",\"id\":\"{item.id}\",\"r\":{item.rev},\"c\":{item.count}}}" )) + "]"; var html = @" Recycler

Recycler

Ready
Select items to recycle
"; server = new HttpListener(); server.Prefixes.Add($"http://localhost:{port}/"); server.Start(); Process.Start(new ProcessStartInfo { FileName = $"http://localhost:{port}/", UseShellExecute = true }); Log($"Server on port {port}"); Task.Run(async () => { while (Run && server.IsListening) { try { var ctx = await server.GetContextAsync(); Task.Run(() => handle(ctx)); } catch { break; } } }); while (Run) { if (queue.Count >= 8 && (DateTime.Now - lastrun).TotalMilliseconds >= delay) { var batch = queue.Take(8).ToList(); queue.RemoveRange(0, 8); Send(Out["RecycleItems"], 8, batch[0], batch[1], batch[2], batch[3], batch[4], batch[5], batch[6], batch[7]); progress += 8; lastrun = DateTime.Now; if (queue.Count < 8) { Log($"Done - recycled {progress} items"); queue.Clear(); progress = 0; total = 0; } } Delay(10); } void handle(HttpListenerContext ctx) { try { var req = ctx.Request; var res = ctx.Response; var path = req.RawUrl; if (path == "/") { var b = Encoding.UTF8.GetBytes(html); res.ContentType = "text/html"; res.ContentLength64 = b.Length; res.OutputStream.Write(b, 0, b.Length); } else if (path == "/recycle" && req.HttpMethod == "POST") { using (var r = new StreamReader(req.InputStream)) { var data = System.Text.Json.JsonSerializer.Deserialize>(r.ReadToEnd()); queue.Clear(); progress = 0; if (data.ContainsKey("delay")) delay = System.Text.Json.JsonSerializer.Deserialize(data["delay"].ToString()); if (data.ContainsKey("items")) { var selected = System.Text.Json.JsonSerializer.Deserialize>>(data["items"].ToString()); foreach (var s in selected) { if (s["i"] < items.Count) { var item = items[s["i"]]; var amt = Math.Min(s["a"], item.count); for (int i = 0; i < amt && i < item.list.Count; i++) queue.Add(item.list[i]); } } } total = queue.Count; Log($"Queued {total} items @ {delay}ms"); } res.StatusCode = 200; } else if (path == "/stop") { queue.Clear(); progress = total = 0; Log("Stopped"); res.StatusCode = 200; } else if (path == "/status") { var json = $"{{\"done\":{progress},\"total\":{total}}}"; var b = Encoding.UTF8.GetBytes(json); res.ContentType = "application/json"; res.ContentLength64 = b.Length; res.OutputStream.Write(b, 0, b.Length); } else { res.StatusCode = 404; } res.Close(); } catch { } } } finally { server?.Stop(); server?.Close(); Log("Shutdown"); }