Skip to content
Snippets Groups Projects
Select Git revision
  • 4d95463ecd3613171b4e4aadc5686686551d917e
  • master default
2 results

Program.cs

Blame
  • 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
    }