Skip to content
Snippets Groups Projects
Commit 11fcd08b authored by Jiří Kalvoda's avatar Jiří Kalvoda
Browse files

Init Parser and add some module used it

parent 5e89ced8
Branches
No related tags found
No related merge requests found
#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<Element> Parse(string s);
void Init(StatusBar _bar, Module _module, ConfigSection section);
}
[ParserName("text")]
class ParserText: Parser
{
Color color;
public void Init(StatusBar _bar, Module _module, ConfigSection section)
{
color = section.Optional("color")?.AsColor() ?? System.Drawing.ColorTranslator.FromHtml("white");
}
public IEnumerable<Element> Parse(string data)
{
if(data.Length > 0 && data[^1] == '\n') data = data[..^1];
return data.Split("\n").Select(x => new Element(x, color: color)).ToArray();
}
}
[ParserName("osdd_last")]
class ParserOsddLast: Parser
{
public void Init(StatusBar _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Element> Parse(string data)
{
var lines = data.Split("\n");
if(lines.Length >= 1)
{
List<Element> 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 Element((first?$"[{TimeShow.Show(timeEleapsed_s)}] ":"") + l[7..], color: System.Drawing.ColorTranslator.FromHtml("#"+l[..6])));
first = false;
}
return output;
}
else
{
return new Element[]{new Element("OSDD parse ERROR", color: Color.Red)};
}
}
}
[ParserName("ICE_speed")]
class ParserICESpeed: Parser
{
#pragma warning disable 8602
public void Init(StatusBar _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Element> Parse(string data)
{
try
{
JsonObject json = JsonObject.Parse(data).AsObject();
return new Element[]{new Element($"{json["speed"].GetValue<double>()} km/h", color: Color.White)};
}
catch(Exception e)
{
Console.Error.WriteLine(e);
return new Element[]{new Element("Speed PE", color: Color.Red)};
}
}
#pragma warning restore 8602
}
[ParserName("ICE_next_stop")]
class ParserICENextStop: Parser
{
#pragma warning disable 8602
public void Init(StatusBar _bar, Module _module, ConfigSection section)
{
}
public IEnumerable<Element> 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 Element[]{new Element($"{nextStopName} in {TimeShow.Show(arrivalIn)}"+delayStr, color: Color.White)};
}
catch(Exception e)
{
Console.Error.WriteLine(e);
return new Element[]{new Element("ICE PE", color: Color.Red)};
}
}
#pragma warning restore 8602
}
...@@ -16,6 +16,7 @@ using System.Runtime.InteropServices; ...@@ -16,6 +16,7 @@ using System.Runtime.InteropServices;
using Color = System.Drawing.Color; using Color = System.Drawing.Color;
using Process = System.Diagnostics.Process; using Process = System.Diagnostics.Process;
using System.Net.Http;
using Config; using Config;
...@@ -109,14 +110,13 @@ namespace i3csstatus { ...@@ -109,14 +110,13 @@ namespace i3csstatus {
class ModuleFile: Module class ModuleFile: Module
{ {
string path; string path;
protected Color color;
InnerStatusBar ifNotFound; InnerStatusBar ifNotFound;
InnerStatusBar ifReadError; InnerStatusBar ifReadError;
Parser parser;
public void Init(StatusBar _bar, ConfigParser config, ConfigSection section) public void Init(StatusBar _bar, ConfigParser config, ConfigSection section)
{ {
path = section.Mandatory("path").AsPath(); path = section.Mandatory("path").AsPath();
color = section.Optional("color")?.AsColor() ?? System.Drawing.ColorTranslator.FromHtml("white"); ifNotFound = new InnerStatusBar(_bar, section.Optional("not_found_handler")?.AsConfig() ??
ifNotFound = new InnerStatusBar(_bar, section.Optional("not_found")?.AsConfig() ??
section.Optional("read_error")?.AsConfig() ?? section.Optional("read_error")?.AsConfig() ??
new ConfigParser( new ConfigParser(
@" @"
...@@ -124,18 +124,15 @@ namespace i3csstatus { ...@@ -124,18 +124,15 @@ namespace i3csstatus {
color = red color = red
text = NFound text = NFound
")); "));
ifReadError = new InnerStatusBar(_bar, section.Optional("read_error")?.AsConfig() ?? ifReadError = new InnerStatusBar(_bar, section.Optional("error_handler")?.AsConfig() ??
new ConfigParser( new ConfigParser(
@" @"
[constant] [constant]
color = red color = red
text = ERR text = ERR
")); "));
} parser = _bar.GetGlobal<ParserGetter>().ByNameFromConfig(section.Optional("parser"));
protected virtual IEnumerable<Element> Parse(string text) parser.Init(_bar, this, section);
{
if(text.Length > 0 && text[^1] == '\n') text = text[..^1];
return text.Split("\n").Select(x => new Element(x, color: color)).ToArray();
} }
public IEnumerable<Element> Get() public IEnumerable<Element> Get()
{ {
...@@ -144,15 +141,16 @@ text = ERR ...@@ -144,15 +141,16 @@ text = ERR
{ {
text = File.ReadAllText(path); text = File.ReadAllText(path);
} }
catch (Exception ex) when (ex is FileNotFoundException || ex is DirectoryNotFoundException) catch (Exception e) when (e is FileNotFoundException || e is DirectoryNotFoundException)
{ {
return ifNotFound.Get(); return ifNotFound.Get();
} }
catch (Exception) catch (Exception e)
{ {
Console.Error.WriteLine(e);
return ifReadError.Get(); return ifReadError.Get();
} }
return Parse(text); return parser.Parse(text);
} }
} }
[ModuleName("pipe")] [ModuleName("pipe")]
...@@ -161,18 +159,17 @@ text = ERR ...@@ -161,18 +159,17 @@ text = ERR
StatusBar bar; StatusBar bar;
string path; string path;
string text; string text;
protected Color color;
InnerStatusBar ifNoData; InnerStatusBar ifNoData;
InnerStatusBar ifReadError; InnerStatusBar ifReadError;
Thread inputThread; Thread inputThread;
int msgSeparator; int msgSeparator;
int scheudleIn_ms; int scheudleIn_ms;
bool pipeError = false; bool pipeError = false;
Parser parser;
public void Init(StatusBar _bar, ConfigParser config, ConfigSection section) public void Init(StatusBar _bar, ConfigParser config, ConfigSection section)
{ {
bar = _bar; bar = _bar;
path = section.Mandatory("path").AsPath(); path = section.Mandatory("path").AsPath();
color = section.Optional("color")?.AsColor() ?? System.Drawing.ColorTranslator.FromHtml("white");
ifNoData = new InnerStatusBar(_bar, section.Optional("no_data")?.AsConfig() ?? ifNoData = new InnerStatusBar(_bar, section.Optional("no_data")?.AsConfig() ??
new ConfigParser( new ConfigParser(
@" @"
...@@ -186,6 +183,9 @@ text = ERR ...@@ -186,6 +183,9 @@ text = ERR
")); "));
msgSeparator = section.Optional("separator")?.AsInt() ?? 0; msgSeparator = section.Optional("separator")?.AsInt() ?? 0;
scheudleIn_ms = section.Optional("delay")?.AsMs() ?? 10; scheudleIn_ms = section.Optional("delay")?.AsMs() ?? 10;
parser = _bar.GetGlobal<ParserGetter>().ByNameFromConfig(section.Optional("parser"));
parser.Init(_bar, this, section);
inputThread = new Thread(this.inputThreadFunc); inputThread = new Thread(this.inputThreadFunc);
inputThread.IsBackground = true; inputThread.IsBackground = true;
inputThread.Start(); inputThread.Start();
...@@ -228,11 +228,6 @@ text = ERR ...@@ -228,11 +228,6 @@ text = ERR
} }
} }
} }
protected virtual IEnumerable<Element> Parse(string text)
{
if(text.Length > 0 && text[^1] == '\n') text = text[..^1];
return text.Split("\n").Select(x => new Element(x, color: color)).ToArray();
}
public IEnumerable<Element> Get() public IEnumerable<Element> Get()
{ {
string _text; string _text;
...@@ -244,42 +239,114 @@ text = ERR ...@@ -244,42 +239,114 @@ text = ERR
return ifReadError.Get(); return ifReadError.Get();
if(_text == null) if(_text == null)
return ifNoData.Get(); return ifNoData.Get();
return Parse(_text); return parser.Parse(_text);
} }
} }
[ModuleName("osdd_last")] [ModuleName("http")]
class ModuleOsddLast: ModulePipe class ModuleHttp: Module
{ {
public new void Init(StatusBar _bar, ConfigParser config, ConfigSection section) StatusBar bar;
string url;
string text;
HttpRequestException error;
long dataTick;
InnerStatusBar ifNoData;
InnerStatusBar ifReadError;
Thread inputThread;
int period_ms;
Parser parser;
int maxOld_ms;
int showOld_ms;
int timeout_ms;
public void Init(StatusBar _bar, ConfigParser config, ConfigSection section)
{ {
base.Init(_bar, config, section); bar = _bar;
url = section.Mandatory("url").AsString();
ifNoData = new InnerStatusBar(_bar, section.Optional("no_data_handler")?.AsConfig() ??
new ConfigParser(
@"
"));
ifReadError = new InnerStatusBar(_bar, section.Optional("error_handler")?.AsConfig() ??
new ConfigParser(
@"
[constant]
color = red
text = ERR
"));
period_ms = section.Optional("period")?.AsMs() ?? 10000;
timeout_ms = section.Optional("period")?.AsMs() ?? 10000;
showOld_ms = section.Optional("show_old")?.AsMs() ?? 30000;
maxOld_ms = section.Optional("max_old")?.AsMs() ?? 300000;
parser = _bar.GetGlobal<ParserGetter>().ByNameFromConfig(section.Optional("parser"));
parser.Init(_bar, this, section);
inputThread = new Thread(this.inputThreadFunc);
inputThread.IsBackground = true;
inputThread.Start();
} }
static string timeShow(long t_s) async void inputThreadFunc()
{ {
if(t_s<180) return $"{t_s}s"; while(true)
if(t_s<180*60) return $"{t_s/60}min";
return $"{t_s/60/60}h";
}
protected override IEnumerable<Element> Parse(string text)
{ {
try try
{ {
var lines = text.Split("\n"); long t = Environment.TickCount64;
List<Element> output = new(); using var client = new HttpClient();
long timeEleapsed_s = DateTimeOffset.Now.ToUnixTimeSeconds()-long.Parse(lines[0]); client.Timeout = TimeSpan.FromMilliseconds(10000);
bool first = true; client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36");
foreach(var l in lines[1..])
string _text = await client.GetStringAsync(url);
lock(this)
{ {
if(l.Length > 7) dataTick = t;
output.Add(new Element((first?$"[{timeShow(timeEleapsed_s)}] ":"") + l[7..], color: System.Drawing.ColorTranslator.FromHtml("#"+l[..6]))); text = _text;
first = false; error = null;
}
}
catch(HttpRequestException e)
{
if(e.StatusCode != null)
lock(this)
{
error = e;
}
}
catch(System.Threading.Tasks.TaskCanceledException)
{
}
Thread.Sleep(period_ms);
} }
return output;
} }
catch(Exception) public IEnumerable<Element> Get()
{
string _text;
long _dataTick;
HttpRequestException _error;
lock(this)
{
_text = text;
_dataTick = dataTick;
_error = error;
}
long t = Environment.TickCount64;
if(_error != null)
return ifReadError.Get();
if(_text == null )
return ifNoData.Get();
if(maxOld_ms != 0 && _dataTick + maxOld_ms <= t)
return ifNoData.Get();
var v = parser.Parse(_text);
if(_dataTick + showOld_ms <= t)
{ {
return new Element[]{new Element("OSDD parse ERROR", color: Color.Red)}; bool first = true;
v.Select(x => {
var v = x;
if(first) v = v with { text = $"[{TimeShow.Show((t-_dataTick)/1000)}] {v.text}" };
first = false;
return v;
}).ToArray();
} }
return v;
} }
} }
[ModuleName("i3status")] [ModuleName("i3status")]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment