//******************************************************************************************************
// Common.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 04/03/2006 - J. Ritchie Carroll
// Generated original version of source code.
// 12/13/2007 - Darrell Zuercher
// Edited code comments.
// 09/08/2008 - J. Ritchie Carroll
// Converted to C#.
// 02/13/2009 - Josh L. Patterson
// Edited Code Comments.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 09/17/2009 - Pinal C. Patel
// Modified GetApplicationType() to remove dependency on HttpContext.Current.
// 09/28/2010 - Pinal C. Patel
// Cached the current ApplicationType returned by GetApplicationType() for better performance.
// 12/05/2010 - Pinal C. Patel
// Added an overload for TypeConvertToString() that takes CultureInfo as a parameter.
// 12/07/2010 - Pinal C. Patel
// Updated TypeConvertToString() to return an empty string if the passed in value is null.
// 03/09/2011 - Pinal C. Patel
// Moved UpdateType enumeration from GSF.Services.ServiceProcess namespace for broader usage.
// 04/07/2011 - J. Ritchie Carroll
// Added ToNonNullNorEmptyString() and ToNonNullNorWhiteSpace() extensions.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web.Hosting;
using GSF.Collections;
using GSF.Console;
using GSF.Interop;
using GSF.IO;
using GSF.Reflection;
using GSF.Units;
using Microsoft.Win32;
namespace GSF
{
#region [ Enumerations ]
///
/// Specifies the type of the application.
///
public enum ApplicationType
{
///
/// Application is of unknown type.
///
Unknown = 0,
///
/// Application doesn't require a subsystem.
///
Native = 1,
///
/// Application runs in the Windows GUI subsystem.
///
WindowsGui = 2,
///
/// Application runs in the Windows character subsystem.
///
WindowsCui = 3,
///
/// Application runs in the OS/2 character subsystem.
///
OS2Cui = 5,
///
/// Application runs in the POSIX character subsystem.
///
PosixCui = 7,
///
/// Application is a native Win9x driver.
///
NativeWindows = 8,
///
/// Application runs in the Windows CE subsystem.
///
WindowsCEGui = 9,
///
/// The application is a web site or web application.
///
Web = 100
}
///
/// Indicates the type of update.
///
public enum UpdateType
{
///
/// Update is informational.
///
Information,
///
/// Update is a warning.
///
Warning,
///
/// Update is an alarm.
///
Alarm
}
#endregion
// This is the location for handy miscellaneous functions that are difficult to categorize elsewhere. For the most
// part these functions may have the most value in a Visual Basic application which supports importing functions
// down to a class level, e.g.: Imports GSF.Common
///
/// Defines common global functions.
///
public static partial class Common
{
private static ApplicationType? s_applicationType;
private static string s_osPlatformName;
private static PlatformID s_osPlatformID = PlatformID.Win32S;
///
/// Gets the type of the currently executing application.
///
/// One of the values.
public static ApplicationType GetApplicationType()
{
if (s_applicationType.HasValue)
return s_applicationType.Value;
if (HostingEnvironment.IsHosted)
{
s_applicationType = ApplicationType.Web;
}
else
{
try
{
// References:
// - http://support.microsoft.com/kb/65122
// - http://support.microsoft.com/kb/90493/en-us
// - http://www.codeguru.com/cpp/w-p/system/misc/article.php/c2897/
// We will always have an entry assembly for windows application.
FileStream exe = new FileStream(AssemblyInfo.EntryAssembly.Location, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
byte[] dosHeader = new byte[64];
byte[] exeHeader = new byte[248];
byte[] subSystem = new byte[2];
exe.Read(dosHeader, 0, dosHeader.Length);
exe.Seek(BitConverter.ToInt16(dosHeader, 60), SeekOrigin.Begin);
exe.Read(exeHeader, 0, exeHeader.Length);
exe.Close();
Buffer.BlockCopy(exeHeader, 92, subSystem, 0, 2);
s_applicationType = ((ApplicationType)(LittleEndian.ToInt16(subSystem, 0)));
}
catch
{
// We are unable to determine the application type.
s_applicationType = ApplicationType.Unknown;
}
}
return s_applicationType.Value;
}
///
/// Gets the operating system
///
/// The operating system .
///
/// This function will properly detect the platform ID, even if running on Mac.
///
public static PlatformID GetOSPlatformID()
{
if (s_osPlatformID != PlatformID.Win32S)
return s_osPlatformID;
s_osPlatformID = Environment.OSVersion.Platform;
if (s_osPlatformID == PlatformID.Unix)
{
// Environment.OSVersion.Platform can report Unix when running on Mac OS X
try
{
s_osPlatformID = Command.Execute("uname").StandardOutput.StartsWith("Darwin", StringComparison.OrdinalIgnoreCase) ? PlatformID.MacOSX : PlatformID.Unix;
}
catch
{
// Fall back on looking for Mac specific root folders:
if (Directory.Exists("/Applications") && Directory.Exists("/System") && Directory.Exists("/Users") && Directory.Exists("/Volumes"))
s_osPlatformID = PlatformID.MacOSX;
}
}
return s_osPlatformID;
}
///
/// Gets the operating system product name.
///
/// Operating system product name.
public static string GetOSProductName()
{
if ((object)s_osPlatformName != null)
return s_osPlatformName;
switch (GetOSPlatformID())
{
case PlatformID.Unix:
case PlatformID.MacOSX:
// Call sw_vers on Mac to get product name and version information, Linux could have this
try
{
string output = Command.Execute("sw_vers").StandardOutput;
Dictionary kvps = output.ParseKeyValuePairs('\n', ':');
if (kvps.Count > 0)
s_osPlatformName = kvps.Values.Select(val => val.Trim()).ToDelimitedString(" ");
}
catch
{
s_osPlatformName = null;
}
if (string.IsNullOrEmpty(s_osPlatformName))
{
// Try some common ways to get product name on Linux, some might work on Mac
try
{
foreach (string fileName in FilePath.GetFileList("/etc/*release*"))
{
using (StreamReader reader = new StreamReader(fileName))
{
string line = reader.ReadLine();
while ((object)line != null)
{
if (line.StartsWith("PRETTY_NAME", StringComparison.OrdinalIgnoreCase) && !line.Contains('#'))
{
string[] parts = line.Split('=');
if (parts.Length == 2)
{
s_osPlatformName = parts[1].Replace("\"", "");
break;
}
}
line = reader.ReadLine();
}
}
if (!string.IsNullOrEmpty(s_osPlatformName))
break;
}
}
catch
{
try
{
string output = Command.Execute("lsb_release", "-a").StandardOutput;
Dictionary kvps = output.ParseKeyValuePairs('\n', ':');
if (kvps.TryGetValue("Description", out s_osPlatformName) && !string.IsNullOrEmpty(s_osPlatformName))
s_osPlatformName = s_osPlatformName.Trim();
}
catch
{
s_osPlatformName = null;
}
}
}
break;
default:
// Get Windows product name
try
{
s_osPlatformName = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", null).ToString();
}
catch
{
s_osPlatformName = null;
}
break;
}
if (string.IsNullOrWhiteSpace(s_osPlatformName))
s_osPlatformName = GetOSPlatformID().ToString();
if (IsMono)
s_osPlatformName += " using Mono";
return s_osPlatformName;
}
///
/// Gets the memory usage by the current process.
///
/// Memory usage by the current process.
public static long GetProcessMemory()
{
long processMemory = Environment.WorkingSet;
if (processMemory == 0 && IsPosixEnvironment)
{
try
{
double percentOfTotal;
ulong totalMemory = GetTotalPhysicalMemory();
//using (PerformanceCounter counter = new PerformanceCounter("Mono Memory", "Total Physical Memory"))
// totalMemory = counter.RawValue;
// Get percent of total memory used by current process
string output = Command.Execute("ps", $"-p {Process.GetCurrentProcess().Id} -o %mem").StandardOutput;
string[] lines = output.Split('\n');
if (lines.Length > 1 && double.TryParse(lines[1].Trim(), out percentOfTotal))
processMemory = (long)Math.Round(percentOfTotal / 100.0D * totalMemory);
}
catch
{
processMemory = -1;
}
}
return processMemory;
}
///
/// Gets the total physical system memory.
///
/// Total physical system memory.
public static ulong GetTotalPhysicalMemory()
{
if (IsPosixEnvironment)
{
string output = Command.Execute("awk", "'/MemTotal/ {print $2}' /proc/meminfo").StandardOutput;
return ulong.Parse(output) * SI2.Kilo;
}
WindowsApi.MEMORYSTATUSEX memStatus = new WindowsApi.MEMORYSTATUSEX();
return WindowsApi.GlobalMemoryStatusEx(memStatus) ? memStatus.ullTotalPhys : 0;
}
///
/// Gets the available physical system memory.
///
/// Total available system memory.
public static ulong GetAvailablePhysicalMemory()
{
if (IsPosixEnvironment)
{
string output = Command.Execute("awk", "'/MemAvailable/ {print $2}' /proc/meminfo").StandardOutput;
return ulong.Parse(output) * SI2.Kilo;
}
WindowsApi.MEMORYSTATUSEX memStatus = new WindowsApi.MEMORYSTATUSEX();
return WindowsApi.GlobalMemoryStatusEx(memStatus) ? memStatus.ullAvailPhys : 0;
}
#region [ Old Code ]
///// Returns the smallest item from a list of parameters.
///// A variable number of parameters of type
///// Result is the minimum value of type in the .
//public static object Min(params object[] itemList)
//{
// return itemList.Min