Innovenergy_trunk/csharp/App/RemoteSupportConsole/VrmConnection.cs

128 lines
4.9 KiB
C#

using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Text;
using CliWrap.EventStream;
using InnovEnergy.Lib.Utils;
using InnovEnergy.Lib.Victron.VictronVRM;
using static System.ConsoleColor;
using static System.StringSplitOptions;
namespace InnovEnergy.App.RemoteSupportConsole;
public static class VrmConnection
{
public static async Task<Int32> Open(Installation installation, IReadOnlyList<Detail> details)
{
var rsHost = details.RemoteSupportIp();
var rsPort = details.RemoteSupportPort();
"starting remote support connection with ".Write();
installation.Name.WriteLine(Green);
using var proxy = await OpenProxy(rsHost!, rsPort!);
"initiating SSH connection\n".WriteLine();
return await Ssh.Interactive(proxy.Host, installation.Name, proxy.User, proxy.Port);
}
private static async Task<VrmProxy> OpenProxy(String rsHost, String rsPort)
{
"contacting Victron remote support host at ".Write();
rsHost.Write(Cyan);
" ... ".Write();
var stdIn = new Subject<String>();
var stdInPipe = stdIn
.Select(l => l + "\n")
.Select(Encoding.UTF8.GetBytes)
.AsPipeSource();
var stdOut = Ssh
.Command(rsHost, "ccgxsupport", "22")
.WithStandardInputPipe(stdInPipe)
.Observe()
.OfType<StandardOutputCommandEvent>()
.Select(e => e.Text)
.Replay();
var connection = stdOut.Connect();
await stdOut.FirstAsync(l => l.StartsWith("Full readline support"));
"ok".WriteLine();
"requesting tunnel through port ".Write();
rsPort.Write(Cyan);
" ... ".Write();
stdIn.OnNext($"proxyport {rsPort}");
var connectMsg = await stdOut.FirstAsync(l => l.StartsWith("You can now connect"));
"ok".WriteLine();
var portUserHost = connectMsg.Split(" ", RemoveEmptyEntries);
var userHost = portUserHost[^1].Split("@");
var user = userHost[0];
var host = userHost[1];
var port = portUserHost[^2];
return new VrmProxy(connection, user, host, port);
}
public static IObservable<CommandEvent> Log(this IObservable<CommandEvent> es)
{
return es.Do(e => Console.WriteLine(Log(e)));
}
private static String Log(CommandEvent e) => e switch
{
StandardOutputCommandEvent so => "=> " + so.Text,
StandardErrorCommandEvent se => "!! " + se.Text,
StartedCommandEvent => "START",
ExitedCommandEvent => "EXIT",
_ => "UNKNOWN MESSAGE: " + e.GetType().Name
};
}
// ReSharper disable CommentTypo
// $ ssh ccgxsupport@3.72.120.57
// Welcome to the Victron remote support tunnel creator.
//
// You will given a one-time tunnel. SSH authentication to
// the Color Control is done with your SSH public key.
//
// *****************************************************************************
// * IMPORTANT NOTE: *
// * *
// * There are now multiple SSH support hosts. Logging in directly *
// * is not officially supported behavior, because you may end up on the wrong *
// * server. A script called 'rs' to use the new format '1.2.3.4;45630' is *
// * available. Ask your Victron contact to supply you with it. *
// *****************************************************************************
//
// The proxy opened up to the CCGX will be restricted to your IP: 145.40.192.17
//
// Commands are:
// proxyport [port] - take color control [port] and temporarily make it available to the outside.
// iptoport [ip] - show the ports being listened on by that IP. Note, you do need to know
// which server the device is connected to. Currently, possibilites are:
// - 84.22.108.49 (EU)
// - 84.22.107.120 (EU)
// - 3.69.217.175 (EU)
// - 3.72.120.57 (EU)
// - 3.25.10.245 (AUS Sydney)
// - 35.165.124.40 (USA West)
// - 13.244.154.199 (South Africa)
// - 13.246.113.18 (South Africa)
// A good start would be the last known, as seen on the diagnostics page.
// exit - exits the shell and all tunnels you set up
//
// Full readline support (command history and editing) is available.
//
// proxyport 24337
// You can now connect to the CCGX with: ssh -o 'UserKnownHostsFile=/dev/null' -o 'StrictHostKeyChecking=no' -o 'ServerAliveInterval=60' -p 4001 root@3.72.120.57