using System.Diagnostics; using System.Net.Sockets; using CliWrap; using CliWrap.Buffered; using InnovEnergy.Lib.Protocols.DBus; using InnovEnergy.Lib.Protocols.DBus.Daemon; using InnovEnergy.Lib.Protocols.DBus.Transport; using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Victron.VeDBus; namespace InnovEnergy.TestBatteryDbus; //Setting up properties internal static class Props { public static VeProperties Properties = new VeProperties(); } public static class Program { public static Int32 Help() { Console.WriteLine("Usage: TestDbus name [args]"); Console.WriteLine(""); Console.WriteLine("Allowed args:"); Console.WriteLine(" -f forces the name. only used for com.victronenergy.settings"); Console.WriteLine(" -h displays this text"); Console.WriteLine(""); Console.WriteLine("This program allows you to \"fake\" a process with dbus-connection."); Console.WriteLine("It overtakes and duplicates an existing service specified by the first argument name"); Console.WriteLine(""); Console.WriteLine("Allowed Commands:"); Console.WriteLine(" /exit exits the program"); Console.WriteLine(" /get name gets the value at name"); Console.WriteLine(" /set name value sets the value at name to value"); return 0; } public static async Task Main(String[] args) { if (args.Contains("-h")) { return Help(); } var dev = "Release"; //for Debuging change to Debug //Setup DBUS connection Console.WriteLine("Setting up Dbus-connection"); var dbus = new DBusConnection(Bus.System); //Todo Remove me if (dev == "Debug") { var ep = new UnixDomainSocketEndPoint("/home/kim/graber_dbus.sock"); var auth = AuthenticationMethod.ExternalAsRoot(); var dbusAddress = new Bus(ep, auth); dbus = new DBusConnection(dbusAddress); } //Taking name from args or giving a list of named services to choose from var name = args.FirstOrDefault(predicate: (arg) => !arg.StartsWith("-"), await ChooseFromNames(dbus)); //catch settings if (name == "com.victronenergy.settings" && !args.Contains("-f")) { Console.WriteLine("com.victronenergy.settings cannot be simulated as the watchdog would force reboot the system."); Console.WriteLine("Use -f to overwrite"); } // var properties = new VeProperties(); //Grab up-to-date dbus items and build mirrored VeProperties Console.WriteLine("Success...Grabbing newest settings from:"); Console.WriteLine(name); // fill properties with preexisting values of the replaced task var values = await dbus .GetAllValues(name); var texts = await dbus .GetAllTexts(name); var keys = values.Keys.Intersect(texts.Keys); foreach (var key in keys) { //writable true is so our new process will correctly handle set requests Props.Properties.Set(key, values[key], text: texts[key], writable: true); } //Catch com.victronenergy.settings name Console.WriteLine("Success...Catching name and publishing under: "); Console.WriteLine(name); //Grabbing process name :1.xx and getting the task process id from that var processIdNameOwner = await dbus.GetNameOwner(name); var processIdTask = dbus.GetConnectionUnixProcessId(processIdNameOwner); Int32 processId = (Int32)await processIdTask; Console.WriteLine("pid: " + processId); //Setup command accepting loop //Queue our task for the name and then kill the old task carrying that name. This should allow us to grab said name and publish to it. await dbus.RequestName(name, RequestNameOptions.None); var usurpedProcess = new Process(); if (dev == "Debug") { var result = await Cli.Wrap("ssh").WithArguments($"root@beaglebone kill -9 {processId}").ExecuteBufferedAsync(); // usurpedProcess = Process.GetProcessById(processId); } else { usurpedProcess = Process.GetProcessById(processId); usurpedProcess.Kill(); } // var commandHandler = new Task(() => { // Console.WriteLine("Enter Commands or exit with /exit: "); // while (true) // { // Console.WriteLine(""); // // var cmd = Console.ReadLine()?.ToUpper().Trim(); // // //Get out if the command is invalid or none // if (StringUtils.IsNullOrEmpty(cmd)) continue; // if (!cmd!.StartsWith("/")) {Help(); continue;} // // //Handle command and if requested end the program, restart the original service we overtook // var exit = ProcessLocalCommand(cmd); // if (!exit) continue; // if (dev == "Debug") // { // var result2 = Cli.Wrap("ssh") // .WithArguments($"root@beaglebone cd /service && svc -u dbus-fronius") //{usurpedProcess.ProcessName} // .ExecuteBufferedAsync(); // return; // } // usurpedProcess.Start(); // return; // }}); var publishTask = await Props.Properties.PublishOnDBus(dbus); //run publish and command-handler and end the program if exit is called or an exception occurs // await Task.WhenAny(commandHandler, publishTask); //TODO use second connection for second task return 0; } private static async Task ChooseFromNames(DBusConnection dbus) { var names = (await dbus.ListNames()).Where(name => !name.StartsWith(":") && name != "org.freedesktop.DBus").ToList(); var choice = "Choose name to test as:".ChooseFrom(chooseFrom: names); if (choice == null) Environment.Exit(0); return choice; } // // private static Boolean ProcessLocalCommand(String cmd) // { // switch (cmd.Split(" ")) // { // case { } a when a[0] == "/exit": // //end program by ending the loop // return true; // // case { } b when b[0] == ("/set"): // //set property at first argument to value of second argument // Props.Properties.Set(b[1], b[2]); // break; // // case { } c when c[0] == ("/get"): // //Get Value of property at first argument // Console.WriteLine(Props.Properties.Get(c[1])); // break; // } // // //continue the loop // return false; // } }