Private/SampleJson.ps1
|
#Requires -Version 5.1 function Initialize-SMBeatSampleJsonNative { if ($script:SMBeatSampleJsonReady) { return $true } if ($script:SMBeatSampleJsonFailed) { return $false } if ('SMBeat.Native.SampleJson' -as [type]) { $script:SMBeatSampleJsonReady = $true return $true } $code = @' using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; namespace SMBeat.Native { public sealed class SampleRecord { public string ts { get; set; } public DateTime TsUtc { get; set; } public string server { get; set; } public string kind { get; set; } public string name { get; set; } public string client { get; set; } public string user { get; set; } public long readBytesDelta { get; set; } public long writeBytesDelta { get; set; } public long sentBytesDelta { get; set; } public long receivedBytesDelta { get; set; } public int sampleIntervalSec { get; set; } } public sealed class SampleWindowPair { public List<SampleRecord> Previous = new List<SampleRecord>(); public List<SampleRecord> Current = new List<SampleRecord>(); } public static class SampleJson { public static SampleRecord ParseLine(string line) { if (string.IsNullOrWhiteSpace(line)) { return null; } int i = 0; SkipWs(line, ref i); if (i >= line.Length || line[i] != '{') { return null; } i++; SampleRecord rec = new SampleRecord(); StringBuilder sb = new StringBuilder(64); bool any = false; while (i < line.Length) { SkipWs(line, ref i); if (i >= line.Length) { return null; } if (line[i] == '}') { break; } if (line[i] == ',') { i++; continue; } if (line[i] != '"') { return null; } string key; if (!TryReadString(line, ref i, sb, out key)) { return null; } SkipWs(line, ref i); if (i >= line.Length || line[i] != ':') { return null; } i++; SkipWs(line, ref i); if (i >= line.Length) { return null; } if (line[i] == '"') { string text; if (!TryReadString(line, ref i, sb, out text)) { return null; } AssignString(rec, key, text); any = true; } else if (line[i] == 'n' || line[i] == 'N') { if (!TrySkipLiteral(line, ref i, "null")) { return null; } AssignString(rec, key, null); any = true; } else if (line[i] == 't' || line[i] == 'T' || line[i] == 'f' || line[i] == 'F') { if (!TrySkipBool(line, ref i)) { return null; } } else { long n; if (!TryReadInt64(line, ref i, out n)) { return null; } AssignNumber(rec, key, n); any = true; } } if (!any || string.IsNullOrEmpty(rec.ts)) { return null; } DateTime ts; if (!TryParseTs(rec.ts, out ts)) { return null; } rec.TsUtc = ts; return rec; } public static List<SampleRecord> ReadFile(string path, DateTime startUtc, DateTime endUtc) { List<SampleRecord> list = new List<SampleRecord>(); if (string.IsNullOrEmpty(path) || !File.Exists(path)) { return list; } foreach (string line in File.ReadLines(path, Encoding.UTF8)) { SampleRecord rec = ParseLine(line); if (rec == null) { continue; } if (rec.TsUtc >= startUtc && rec.TsUtc < endUtc) { list.Add(rec); } } return list; } public static SampleWindowPair ReadDirectory( string dir, DateTime prevStart, DateTime prevEnd, DateTime windowStart, DateTime windowEnd) { SampleWindowPair pair = new SampleWindowPair(); if (string.IsNullOrEmpty(dir) || !Directory.Exists(dir)) { return pair; } DateTime spanStart = prevStart < windowStart ? prevStart : windowStart; DateTime spanEnd = prevEnd > windowEnd ? prevEnd : windowEnd; DateTime startDay = spanStart.Date.AddDays(-1); DateTime endDay = spanEnd.Date.AddDays(1); string[] files = Directory.GetFiles(dir, "*.jsonl"); Array.Sort(files, StringComparer.OrdinalIgnoreCase); foreach (string path in files) { string dayPart = Path.GetFileNameWithoutExtension(path); DateTime fileDay; if (!DateTime.TryParseExact(dayPart, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out fileDay)) { continue; } if (fileDay < startDay || fileDay > endDay) { continue; } foreach (string line in File.ReadLines(path, Encoding.UTF8)) { SampleRecord rec = ParseLine(line); if (rec == null) { continue; } if (rec.TsUtc >= prevStart && rec.TsUtc < prevEnd) { pair.Previous.Add(rec); } if (rec.TsUtc >= windowStart && rec.TsUtc < windowEnd) { pair.Current.Add(rec); } } } return pair; } private static void AssignString(SampleRecord rec, string key, string value) { if (key == "ts") { rec.ts = value; } else if (key == "server") { rec.server = value; } else if (key == "kind") { rec.kind = value; } else if (key == "name") { rec.name = value; } else if (key == "client") { rec.client = value; } else if (key == "user") { rec.user = value; } } private static void AssignNumber(SampleRecord rec, string key, long value) { if (key == "readBytesDelta") { rec.readBytesDelta = value; } else if (key == "writeBytesDelta") { rec.writeBytesDelta = value; } else if (key == "sentBytesDelta") { rec.sentBytesDelta = value; } else if (key == "receivedBytesDelta") { rec.receivedBytesDelta = value; } else if (key == "sampleIntervalSec") { rec.sampleIntervalSec = (int)value; } } private static bool TryParseTs(string value, out DateTime ts) { if (DateTime.TryParseExact(value, "yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out ts)) { return true; } return DateTime.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out ts); } private static void SkipWs(string s, ref int i) { while (i < s.Length && char.IsWhiteSpace(s[i])) { i++; } } private static bool TrySkipLiteral(string s, ref int i, string lit) { if (i + lit.Length > s.Length) { return false; } for (int k = 0; k < lit.Length; k++) { if (char.ToLowerInvariant(s[i + k]) != lit[k]) { return false; } } i += lit.Length; return true; } private static bool TrySkipBool(string s, ref int i) { if (s[i] == 't' || s[i] == 'T') { return TrySkipLiteral(s, ref i, "true"); } return TrySkipLiteral(s, ref i, "false"); } private static bool TryReadInt64(string s, ref int i, out long value) { value = 0; int start = i; if (i < s.Length && (s[i] == '-' || s[i] == '+')) { i++; } bool digit = false; while (i < s.Length && s[i] >= '0' && s[i] <= '9') { digit = true; i++; } if (i < s.Length && s[i] == '.') { i++; while (i < s.Length && s[i] >= '0' && s[i] <= '9') { i++; } } if (!digit) { return false; } string raw = s.Substring(start, i - start); double d; if (!double.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out d)) { return false; } if (d >= long.MaxValue) { value = long.MaxValue; } else if (d <= long.MinValue) { value = long.MinValue; } else { value = (long)d; } return true; } private static bool TryReadString(string s, ref int i, StringBuilder sb, out string value) { value = null; if (i >= s.Length || s[i] != '"') { return false; } i++; sb.Length = 0; while (i < s.Length) { char c = s[i]; if (c == '"') { i++; value = sb.ToString(); return true; } if (c == '\\') { i++; if (i >= s.Length) { return false; } char e = s[i]; if (e == '"' || e == '\\' || e == '/') { sb.Append(e); } else if (e == 'b') { sb.Append('\b'); } else if (e == 'f') { sb.Append('\f'); } else if (e == 'n') { sb.Append('\n'); } else if (e == 'r') { sb.Append('\r'); } else if (e == 't') { sb.Append('\t'); } else if (e == 'u' && i + 4 < s.Length) { int hex; if (!int.TryParse(s.Substring(i + 1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out hex)) { return false; } sb.Append((char)hex); i += 4; } else { sb.Append(e); } i++; continue; } sb.Append(c); i++; } return false; } } } '@ try { Add-Type -TypeDefinition $code -Language CSharp -ErrorAction Stop $script:SMBeatSampleJsonReady = $true return $true } catch { $script:SMBeatSampleJsonFailed = $true return $false } } |