/*
* Copyright (c) 2025 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN 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
* (at your option) any later version.
*
* ProtonVPN 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 ProtonVPN. If not, see .
*/
using ProtonVPN.Common.Core.Extensions;
using ProtonVPN.Common.Core.Networking;
namespace ProtonVPN.Vpn.Management;
///
/// Message received over OpenVPN management interface.
///
public class ReceivedManagementMessage
{
private readonly string _messageText;
public ReceivedManagementMessage(string messageText)
{
_messageText = messageText ?? "";
}
public override string ToString() => _messageText;
public bool IsChannelDisconnected => _messageText.IsNullOrEmpty();
public bool IsWaitingHoldRelease => _messageText.StartsWithIgnoringCase(">HOLD");
public bool IsEchoSet => _messageText.StartsWithIgnoringCase("SUCCESS: real-time echo notification set");
public bool IsStateSet => _messageText.StartsWithIgnoringCase("SUCCESS: real-time state notification set");
public bool IsByteCountSet => _messageText.StartsWithIgnoringCase("SUCCESS: bytecount");
public bool IsUsernameNeeded => _messageText.StartsWithIgnoringCase(">PASSWORD:Need");
public bool IsPasswordNeeded => _messageText.StartsWithIgnoringCase("SUCCESS: 'Auth' username entered");
public bool IsLogSet => _messageText.StartsWithIgnoringCase("SUCCESS: real-time log notification set");
public bool IsByteCount => _messageText.StartsWithIgnoringCase(">BYTECOUNT");
public bool IsState => _messageText.StartsWithIgnoringCase(">STATE");
public bool IsError => ManagementError.ContainsError(_messageText);
public bool IsDisconnectReceived => _messageText.StartsWithIgnoringCase("SUCCESS: signal SIGTERM thrown");
public bool IsControlMessage => _messageText.ContainsIgnoringCase("PUSH: Received control message");
public NetworkTraffic Bandwidth()
{
string[] byteCountArr = _messageText.Split(':')[1].Split(',');
if (byteCountArr.Length <= 1)
{
return NetworkTraffic.Zero;
}
if (!ulong.TryParse(byteCountArr[0], out ulong bytesIn))
{
return NetworkTraffic.Zero;
}
if (!ulong.TryParse(byteCountArr[1], out ulong bytesOut))
{
return NetworkTraffic.Zero;
}
return new NetworkTraffic(bytesIn, bytesOut);
}
public ManagementState State()
{
string[] messageParts = _messageText.Split(',');
if (messageParts.Length <= 1)
{
return ManagementState.Null;
}
string stateText = messageParts[1];
string statusText = messageParts.Length > 2 ? messageParts[2] : "";
string localIpAddress = messageParts.Length > 3 ? messageParts[3] : "";
string remoteIpAddress = messageParts.Length > 4 ? messageParts[4] : "";
return new ManagementState(stateText, statusText, localIpAddress, remoteIpAddress);
}
public ManagementError Error()
{
return new ManagementError(_messageText);
}
}