Select Git revision
-
Lukáš Ondráček authoredLukáš Ondráček authored
Parsers.cs 11.37 KiB
// i3csstatus - Alternative generator of i3 status bar written in c#
// (c) 2022 Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#nullable enable
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Linq;
using System.Threading;
using Color = System.Drawing.Color;
using Process = System.Diagnostics.Process;
using Config;
namespace i3csstatus;
static class TimeShow
{
static public string Show(long t_s)
{
if(t_s<180) return $"{t_s}s";
if(t_s<180*60) return $"{t_s/60}min";
return $"{t_s/60/60}h";
}
static public string WithSign(long t_s)
{
if(t_s >= 0)
return "+" + Show(t_s);
else
return "-" + Show(-t_s);
}
}
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = true)]
class ParserName : System.Attribute
{
public string Name {get; init;}
public ParserName(string _name)
{
Name = _name;
}
}
class ParserGetter: GlobalModuleResource
{
Dictionary<string, Type> parserTypes;
public ParserGetter()
{
parserTypes = new Dictionary<string, Type>(
from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where type.IsDefined(typeof(ParserName), false)
where typeof(Parser).IsAssignableFrom(type)
from name in type.GetCustomAttributes(typeof(ParserName), false)
select new KeyValuePair<string, Type>(((ParserName)name).Name, type)
);
}
public Parser? ByName(string name)
{
var constructorSignature = new Type[]{};
if(!parserTypes.ContainsKey(name))
return null;
var constructor = parserTypes[name].GetConstructor(constructorSignature);
if(constructor == null)
throw new Exception($"Missing constructor of {name} parser");
return (Parser) constructor.Invoke(new object[]{});
}
public Parser ByNameFromConfig(ConfigValue val)
{
if(val == null) return new ParserText();
var p = ByName(val.AsString());
if(p == null)
throw new ConfigMistake(val, $"Parser with name \"{val.AsString()}\" not exists.");
return p;
}
}
interface Parser
{
IEnumerable<Block> Parse(string s);
void Init(ModuleParent _bar, Module _module, ConfigSection section);
}
#nullable disable
[ParserName("text")]
class ParserText: Parser
{
public void Init(ModuleParent _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Block> Parse(string data)
{
if(data.Length > 0 && data[^1] == '\n') data = data[..^1];
return data.Split("\n").Select(x => new Block(x)).ToArray();
}
}
[ParserName("osdd_last")]
class ParserOsddLast: Parser
{
public void Init(ModuleParent _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Block> Parse(string data)
{
var lines = data.Split("\n");
if(lines.Length >= 1)
{
List<Block> output = new();
long timeEleapsed_s = DateTimeOffset.Now.ToUnixTimeSeconds()-long.Parse(lines[0]);
bool first = true;
foreach(var l in lines[1..])
{
if(l.Length > 7)
output.Add(new Block((first?$"[{TimeShow.Show(timeEleapsed_s)}] ":"") + l[7..], Color: System.Drawing.ColorTranslator.FromHtml("#"+l[..6])));
first = false;
}
return output;
}
else
{
return new Block[]{new Block("OSDD parse ERROR", Color: Color.Red)};
}
}
}
[ParserName("checkmail_status")]
class ParserCheckmailLog: Parser
{
ModuleParent bar;
public void Init(ModuleParent _bar, Module _module, ConfigSection section)
{
bar = _bar;
}
public IEnumerable<Block> Parse(string data)
{
try
{
long msgTime = int.Parse(data.Split()[0]);
long countNewMails = int.Parse(data.Split()[1]);
long delay = DateTimeOffset.Now.ToUnixTimeSeconds() - msgTime;
long t = Environment.TickCount64;
bool t_parity = t/1000%2==0;
if(countNewMails > 0)
{
bar.Schedule((int)(1000-t%1000 + 10));
}
if(delay < -5 || delay > 90)
{
if(countNewMails > 0)
return new Block[]{new Block($"NO CONNECTION {TimeShow.Show(delay)} [{countNewMails}]", Color: t_parity?Color.FromArgb(255, 0, 0):Color.FromArgb(0x33, 0x33, 255))};
else
return new Block[]{new Block($"NO CONNECTION {TimeShow.Show(delay)}", Color: Color.Red)};
}
else
{
if(countNewMails > 0)
return new Block[]{new Block($"[{countNewMails} NEW]", Color: t_parity?Color.FromArgb(255, 0x70, 0):Color.FromArgb(0x33, 0x33, 255))};
else
return new Block[]{new Block($"OK", Color: Color.FromArgb(0,255,0))};
}
}
catch(Exception e)
{
Console.Error.WriteLine(e);
return new Block[]{new Block("CM PE", Color: Color.Red)};
}
}
}
[ParserName("offlineimap_status")]
class ParserOfflineimapLog: Parser
{
public void Init(ModuleParent _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Block> Parse(string data)
{
data = data.Trim();
if(data.StartsWith("DOING"))
return new Block[]{new Block("IMAP", Color: Color.Green)};
if(data.StartsWith("WAITING"))
return new Block[]{new Block("IMAP", Color: Color.Orange)};
if(int.TryParse(data, out int n))
{
if(n == 0)
return new Block[]{};
else
return new Block[]{new Block($"IMAP {n}", Color: Color.Red)};
}
else
return new Block[]{new Block("IMAP PE", Color: Color.Red)};
}
}
[ParserName("i3")]
class ParserI3: Parser
{
public void Init(ModuleParent _bar, Module _module, ConfigSection section){}
static Block parseElement(JsonNode _json)
{
var json = _json.AsObject();
var align = Align.Left;
if(json["align"]?.GetValue<string>() == "right") align=Align.Right;
if(json["align"]?.GetValue<string>() == "center") align=Align.Center;
var markup = Markup.None;
if(json["markup"]?.GetValue<string>() == "pango") markup=Markup.Pango;
string minWidth_string = null;
int? minWidth_int = null;
try
{
minWidth_string = json["min_width"]?.AsValue()?.GetValue<string>();
}
catch(Exception) {}
try
{
minWidth_int = json["min_width"]?.AsValue()?.GetValue<int>();
}
catch(Exception) {}
return new Block(
Text: json["full_text"].AsValue().GetValue<string>(),
ShortText: json["short_text"]?.AsValue()?.GetValue<string>(),
Color: json["color"]?.AsValue()?.GetValue<string>()?.ToColor(),
BackgroundColor: json["background"]?.AsValue()?.GetValue<string>()?.ToColor(),
BorderColor: json["border"]?.AsValue()?.GetValue<string>()?.ToColor(),
BorderTop: json["border_top"]?.AsValue()?.GetValue<int>(),
BorderRight: json["border_right"]?.AsValue()?.GetValue<int>(),
BorderBottom: json["border_bottom"]?.AsValue()?.GetValue<int>(),
BorderLeft: json["border_left"]?.AsValue()?.GetValue<int>(),
MinWidth_string: minWidth_string,
MinWidth_int: minWidth_int,
Align: align,
Urgent: json["urgent"]?.AsValue().GetValue<bool>() ?? false,
Separator: json["separator"]?.AsValue().GetValue<bool>() ?? true,
SeparatorBlockWidth: json["separator_block_width"]?.AsValue()?.GetValue<int>(),
Markup: markup
);
}
public IEnumerable<Block> Parse(string data)
{
JsonArray json = JsonObject.Parse(data).AsArray();
return json.Select(parseElement).ToArray();
}
}
[ParserName("ICE_speed")]
class ParserICESpeed: Parser
{
#pragma warning disable 8602
public void Init(ModuleParent _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Block> Parse(string data)
{
try
{
JsonObject json = JsonObject.Parse(data).AsObject();
return new Block[]{new Block($"{json["speed"].GetValue<double>()} km/h", Color: Color.White)};
}
catch(Exception e)
{
Console.Error.WriteLine(e);
return new Block[]{new Block("Speed PE", Color: Color.Red)};
}
}
#pragma warning restore 8602
}
[ParserName("ICE_next_stop")]
class ParserICENextStop: Parser
{
#pragma warning disable 8602
public void Init(ModuleParent _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Block> Parse(string data)
{
try
{
JsonObject json = JsonObject.Parse(data).AsObject();
JsonObject nextStop = null;
string nextStopID = json["trip"].AsObject()["stopInfo"].AsObject()["actualNext"].GetValue<string>();
foreach(var s in json["trip"].AsObject()["stops"].AsArray())
{
string id = s.AsObject()["station"].AsObject()["evaNr"].GetValue<string>();
if(id == nextStopID) nextStop = s.AsObject();
}
string nextStopName = nextStop["station"].AsObject()["name"].GetValue<string>();
long nextStopArrival = nextStop["timetable"].AsObject()["actualArrivalTime"].GetValue<long>()/1000;
long nextStopArrivalScheudled = nextStop["timetable"].AsObject()["scheduledArrivalTime"].GetValue<long>()/1000;
long arrivalIn = nextStopArrival - DateTimeOffset.Now.ToUnixTimeSeconds();
string delayStr = nextStopArrivalScheudled==nextStopArrival?"":$" ({TimeShow.WithSign(nextStopArrival - nextStopArrivalScheudled)})";
return new Block[]{new Block($"{nextStopName} in {TimeShow.Show(arrivalIn)}"+delayStr, Color: Color.White)};
}
catch(Exception e)
{
Console.Error.WriteLine(e);
return new Block[]{new Block("ICE PE", Color: Color.Red)};
}
}
#pragma warning restore 8602
}
[ParserName("CD_speed")]
class ParserCDSpeed: Parser
{
#pragma warning disable 8602
public void Init(ModuleParent _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Block> Parse(string data)
{
try
{
JsonObject json = JsonObject.Parse(data).AsObject();
return new Block[]{new Block($"{json["speed"].GetValue<double>()} km/h", Color: Color.White)};
}
catch(Exception e)
{
Console.Error.WriteLine(e);
return new Block[]{new Block("Speed PE", Color: Color.Red)};
}
}
#pragma warning restore 8602
}
[ParserName("CD_next_stop")]
class ParserCDNextStop: Parser
{
#pragma warning disable 8602
public void Init(ModuleParent _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Block> Parse(string data)
{
try
{
string[] lines = data.Split("\n");
JsonObject delayJson = JsonObject.Parse(lines[1]).AsObject();
int delay_min = delayJson.AsObject()["delay"]?.GetValue<int>() ?? 0;
JsonObject json = JsonObject.Parse(lines[0]).AsObject();
JsonObject nextStop = null;
foreach(var s in json["connexionTimes"].AsArray())
{
string arrivalTime = s.AsObject()["timeArrival"]?.GetValue<string>();
if(arrivalTime != null)
{
var arrival = DateTime.Parse(arrivalTime);
if(arrival.AddMinutes(delay_min) >= DateTime.Now)
{
nextStop = s.AsObject();
break;
}
}
}
string nextStopName = nextStop["station"].AsObject()["name"].GetValue<string>();
DateTime nextStopArrival = DateTime.Parse(nextStop.AsObject()["timeArrival"]?.GetValue<string>()).AddMinutes(delay_min);
long arrivalIn = (long)(nextStopArrival - DateTime.Now).TotalSeconds;
string delayStr = delay_min==0?"":$" ({TimeShow.WithSign(delay_min * 60)})";
return new Block[]{new Block($"{nextStopName} in {TimeShow.Show(arrivalIn)}"+delayStr, Color: Color.White)};
}
catch(Exception e)
{
Console.Error.WriteLine(e);
return new Block[]{new Block("CD PE", Color: Color.Red)};
}
}
#pragma warning restore 8602
}