feat: Initialize Zastava Webhook service with TLS and Authority authentication
- Added Program.cs to set up the web application with Serilog for logging, health check endpoints, and a placeholder admission endpoint. - Configured Kestrel server to use TLS 1.3 and handle client certificates appropriately. - Created StellaOps.Zastava.Webhook.csproj with necessary dependencies including Serilog and Polly. - Documented tasks in TASKS.md for the Zastava Webhook project, outlining current work and exit criteria for each task.
This commit is contained in:
44
Mongo2Go-4.1.0/src/Mongo2Go/Helper/FileSystem.cs
Normal file
44
Mongo2Go-4.1.0/src/Mongo2Go/Helper/FileSystem.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public class FileSystem : IFileSystem
|
||||
{
|
||||
public void CreateFolder(string path)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteFolder(string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
Directory.Delete(path, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteFile(string fullFileName)
|
||||
{
|
||||
if (File.Exists(fullFileName))
|
||||
{
|
||||
File.Delete(fullFileName);
|
||||
}
|
||||
}
|
||||
|
||||
public void MakeFileExecutable (string path)
|
||||
{
|
||||
//when on linux or osx we must set the executeble flag on mongo binarys
|
||||
var p = Process.Start("chmod", $"+x {path}");
|
||||
p.WaitForExit();
|
||||
|
||||
if (p.ExitCode != 0)
|
||||
{
|
||||
throw new IOException($"Could not set executable bit for {path}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
112
Mongo2Go-4.1.0/src/Mongo2Go/Helper/FolderSearch.cs
Normal file
112
Mongo2Go-4.1.0/src/Mongo2Go/Helper/FolderSearch.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public static class FolderSearch
|
||||
{
|
||||
private static readonly char[] _separators = { Path.DirectorySeparatorChar };
|
||||
|
||||
public static string CurrentExecutingDirectory()
|
||||
{
|
||||
string filePath = new Uri(typeof(FolderSearch).GetTypeInfo().Assembly.CodeBase).LocalPath;
|
||||
return Path.GetDirectoryName(filePath);
|
||||
}
|
||||
|
||||
public static string FindFolder(this string startPath, string searchPattern)
|
||||
{
|
||||
if (startPath == null || searchPattern == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string currentPath = startPath;
|
||||
|
||||
foreach (var part in searchPattern.Split(_separators, StringSplitOptions.None))
|
||||
{
|
||||
if (!Directory.Exists(currentPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] matchesDirectory = Directory.GetDirectories(currentPath, part);
|
||||
if (!matchesDirectory.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (matchesDirectory.Length > 1)
|
||||
{
|
||||
currentPath = MatchVersionToAssemblyVersion(matchesDirectory)
|
||||
?? matchesDirectory.OrderBy(x => x).Last();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPath = matchesDirectory.First();
|
||||
}
|
||||
}
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
public static string FindFolderUpwards(this string startPath, string searchPattern)
|
||||
{
|
||||
if (string.IsNullOrEmpty(startPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string matchingFolder = startPath.FindFolder(searchPattern);
|
||||
return matchingFolder ?? startPath.RemoveLastPart().FindFolderUpwards(searchPattern);
|
||||
}
|
||||
|
||||
internal static string RemoveLastPart(this string path)
|
||||
{
|
||||
if (!path.Contains(Path.DirectorySeparatorChar))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<string> parts = path.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.None).ToList();
|
||||
parts.RemoveAt(parts.Count() - 1);
|
||||
return string.Join(Path.DirectorySeparatorChar.ToString(), parts.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Absolute path stays unchanged, relative path will be relative to current executing directory (usually the /bin folder)
|
||||
/// </summary>
|
||||
public static string FinalizePath(string fileName)
|
||||
{
|
||||
string finalPath;
|
||||
|
||||
if (Path.IsPathRooted(fileName))
|
||||
{
|
||||
finalPath = fileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
finalPath = Path.Combine(CurrentExecutingDirectory(), fileName);
|
||||
finalPath = Path.GetFullPath(finalPath);
|
||||
}
|
||||
|
||||
return finalPath;
|
||||
}
|
||||
|
||||
private static string MatchVersionToAssemblyVersion(string[] folders)
|
||||
{
|
||||
var version = typeof(FolderSearch).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
|
||||
foreach (var folder in folders)
|
||||
{
|
||||
var lastFolder = new DirectoryInfo(folder).Name;
|
||||
if (lastFolder == version)
|
||||
return folder;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IFileSystem.cs
Normal file
10
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IFileSystem.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public interface IFileSystem
|
||||
{
|
||||
void CreateFolder(string path);
|
||||
void DeleteFolder(string path);
|
||||
void DeleteFile(string fullFileName);
|
||||
void MakeFileExecutable (string path );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public interface IMongoBinaryLocator
|
||||
{
|
||||
string Directory { get; }
|
||||
}
|
||||
}
|
||||
11
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IMongoDbProcess.cs
Normal file
11
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IMongoDbProcess.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public interface IMongoDbProcess : IDisposable
|
||||
{
|
||||
IEnumerable<string> StandardOutput { get; }
|
||||
IEnumerable<string> ErrorOutput { get; }
|
||||
}
|
||||
}
|
||||
11
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IMongoDbProcessStarter.cs
Normal file
11
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IMongoDbProcessStarter.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public interface IMongoDbProcessStarter
|
||||
{
|
||||
IMongoDbProcess Start(string binariesDirectory, string dataDirectory, int port, bool singleNodeReplSet, string additionalMongodArguments, ushort singleNodeReplSetWaitTimeout = MongoDbDefaults.SingleNodeReplicaSetWaitTimeout, ILogger logger = null);
|
||||
|
||||
IMongoDbProcess Start(string binariesDirectory, string dataDirectory, int port, bool doNotKill, bool singleNodeReplSet, string additionalMongodArguments, ushort singleNodeReplSetWaitTimeout = MongoDbDefaults.SingleNodeReplicaSetWaitTimeout, ILogger logger = null);
|
||||
}
|
||||
}
|
||||
10
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IPortPool.cs
Normal file
10
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IPortPool.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public interface IPortPool
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns and reserves a new port
|
||||
/// </summary>
|
||||
int GetNextOpenPort();
|
||||
}
|
||||
}
|
||||
8
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IPortWatcher.cs
Normal file
8
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IPortWatcher.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public interface IPortWatcher
|
||||
{
|
||||
int FindOpenPort();
|
||||
bool IsPortAvailable(int portNumber);
|
||||
}
|
||||
}
|
||||
7
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IProcessWatcher.cs
Normal file
7
Mongo2Go-4.1.0/src/Mongo2Go/Helper/IProcessWatcher.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public interface IProcessWatcher
|
||||
{
|
||||
bool IsProcessRunning(string processName);
|
||||
}
|
||||
}
|
||||
101
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoBinaryLocator.cs
Normal file
101
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoBinaryLocator.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
|
||||
public class MongoBinaryLocator : IMongoBinaryLocator
|
||||
{
|
||||
private readonly string _nugetPrefix = Path.Combine("packages", "Mongo2Go*");
|
||||
private readonly string _nugetCachePrefix = Path.Combine("packages", "mongo2go", "*");
|
||||
private readonly string _nugetCacheBasePrefix = Path.Combine("mongo2go", "*");
|
||||
public const string DefaultWindowsSearchPattern = @"tools\mongodb-windows*\bin";
|
||||
public const string DefaultLinuxSearchPattern = "tools/mongodb-linux*/bin";
|
||||
public const string DefaultOsxSearchPattern = "tools/mongodb-macos*/bin";
|
||||
public const string WindowsNugetCacheLocation = @"%USERPROFILE%\.nuget\packages";
|
||||
public static readonly string OsxAndLinuxNugetCacheLocation = Environment.GetEnvironmentVariable("HOME") + "/.nuget/packages";
|
||||
private string _binFolder = string.Empty;
|
||||
private readonly string _searchPattern;
|
||||
private readonly string _nugetCacheDirectory;
|
||||
private readonly string _additionalSearchDirectory;
|
||||
|
||||
public MongoBinaryLocator(string searchPatternOverride, string additionalSearchDirectory)
|
||||
{
|
||||
_additionalSearchDirectory = additionalSearchDirectory;
|
||||
_nugetCacheDirectory = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
_searchPattern = DefaultOsxSearchPattern;
|
||||
_nugetCacheDirectory = _nugetCacheDirectory ?? OsxAndLinuxNugetCacheLocation;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
_searchPattern = DefaultLinuxSearchPattern;
|
||||
_nugetCacheDirectory = _nugetCacheDirectory ?? OsxAndLinuxNugetCacheLocation;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
_searchPattern = DefaultWindowsSearchPattern;
|
||||
_nugetCacheDirectory = _nugetCacheDirectory ?? Environment.ExpandEnvironmentVariables(WindowsNugetCacheLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MonogDbBinariesNotFoundException($"Unknown OS: {RuntimeInformation.OSDescription}");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(searchPatternOverride))
|
||||
{
|
||||
_searchPattern = searchPatternOverride;
|
||||
}
|
||||
}
|
||||
|
||||
public string Directory {
|
||||
get {
|
||||
if (string.IsNullOrEmpty(_binFolder)){
|
||||
return _binFolder = ResolveBinariesDirectory ();
|
||||
} else {
|
||||
return _binFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ResolveBinariesDirectory()
|
||||
{
|
||||
var searchDirectories = new[]
|
||||
{
|
||||
// First search from the additional search directory, if provided
|
||||
_additionalSearchDirectory,
|
||||
// Then search from the project directory
|
||||
FolderSearch.CurrentExecutingDirectory(),
|
||||
// Finally search from the nuget cache directory
|
||||
_nugetCacheDirectory
|
||||
};
|
||||
return FindBinariesDirectory(searchDirectories.Where(x => !string.IsNullOrWhiteSpace(x)).ToList());
|
||||
}
|
||||
|
||||
private string FindBinariesDirectory(IList<string> searchDirectories)
|
||||
{
|
||||
foreach (var directory in searchDirectories)
|
||||
{
|
||||
var binaryFolder =
|
||||
// First try just the search pattern
|
||||
directory.FindFolderUpwards(_searchPattern) ??
|
||||
// Next try the search pattern with nuget installation prefix
|
||||
directory.FindFolderUpwards(Path.Combine(_nugetPrefix, _searchPattern)) ??
|
||||
// Finally try the search pattern with the nuget cache prefix
|
||||
directory.FindFolderUpwards(Path.Combine(_nugetCachePrefix, _searchPattern)) ??
|
||||
// Finally try the search pattern with the basic nuget cache prefix
|
||||
directory.FindFolderUpwards(Path.Combine(_nugetCacheBasePrefix, _searchPattern));
|
||||
if (binaryFolder != null) return binaryFolder;
|
||||
}
|
||||
throw new MonogDbBinariesNotFoundException(
|
||||
$"Could not find Mongo binaries using the search patterns \"{_searchPattern}\", \"{Path.Combine(_nugetPrefix, _searchPattern)}\", \"{Path.Combine(_nugetCachePrefix, _searchPattern)}\", and \"{Path.Combine(_nugetCacheBasePrefix, _searchPattern)}\". " +
|
||||
$"You can override the search pattern and directory when calling MongoDbRunner.Start. We have detected the OS as {RuntimeInformation.OSDescription}.\n" +
|
||||
$"We walked up to root directory from the following locations.\n {string.Join("\n", searchDirectories)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
// IDisposable and friends
|
||||
public partial class MongoDbProcess
|
||||
{
|
||||
~MongoDbProcess()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
// we have no "managed resources" - but we leave this switch to avoid an FxCop CA1801 warnig
|
||||
}
|
||||
|
||||
if (_process == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_process.DoNotKill)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_process.HasExited)
|
||||
{
|
||||
_process.Kill();
|
||||
_process.WaitForExit();
|
||||
}
|
||||
|
||||
_process.Dispose();
|
||||
_process = null;
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoDbProcess.cs
Normal file
19
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoDbProcess.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public partial class MongoDbProcess : IMongoDbProcess
|
||||
{
|
||||
|
||||
private WrappedProcess _process;
|
||||
|
||||
public IEnumerable<string> ErrorOutput { get; set; }
|
||||
public IEnumerable<string> StandardOutput { get; set; }
|
||||
|
||||
internal MongoDbProcess(WrappedProcess process)
|
||||
{
|
||||
_process = process;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
92
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoDbProcessStarter.cs
Normal file
92
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoDbProcessStarter.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
using MongoDB.Driver.Core.Servers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public class MongoDbProcessStarter : IMongoDbProcessStarter
|
||||
{
|
||||
private const string ProcessReadyIdentifier = "waiting for connections";
|
||||
private const string Space = " ";
|
||||
private const string ReplicaSetName = "singleNodeReplSet";
|
||||
private const string ReplicaSetReadyIdentifier = "transition to primary complete; database writes are now permitted";
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new process. Process can be killed
|
||||
/// </summary>
|
||||
public IMongoDbProcess Start(string binariesDirectory, string dataDirectory, int port, bool singleNodeReplSet, string additionalMongodArguments, ushort singleNodeReplSetWaitTimeout = MongoDbDefaults.SingleNodeReplicaSetWaitTimeout, ILogger logger = null)
|
||||
{
|
||||
return Start(binariesDirectory, dataDirectory, port, false, singleNodeReplSet, additionalMongodArguments, singleNodeReplSetWaitTimeout, logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new process.
|
||||
/// </summary>
|
||||
public IMongoDbProcess Start(string binariesDirectory, string dataDirectory, int port, bool doNotKill, bool singleNodeReplSet, string additionalMongodArguments, ushort singleNodeReplSetWaitTimeout = MongoDbDefaults.SingleNodeReplicaSetWaitTimeout, ILogger logger = null)
|
||||
{
|
||||
string fileName = @"{0}{1}{2}".Formatted(binariesDirectory, System.IO.Path.DirectorySeparatorChar.ToString(), MongoDbDefaults.MongodExecutable);
|
||||
|
||||
string arguments = (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) ?
|
||||
@"--dbpath ""{0}"" --port {1} --bind_ip 127.0.0.1".Formatted(dataDirectory, port) :
|
||||
@"--tlsMode disabled --dbpath ""{0}"" --port {1} --bind_ip 127.0.0.1".Formatted(dataDirectory, port);
|
||||
|
||||
arguments = singleNodeReplSet ? arguments + Space + "--replSet" + Space + ReplicaSetName : arguments;
|
||||
arguments += MongodArguments.GetValidAdditionalArguments(arguments, additionalMongodArguments);
|
||||
|
||||
WrappedProcess wrappedProcess = ProcessControl.ProcessFactory(fileName, arguments);
|
||||
wrappedProcess.DoNotKill = doNotKill;
|
||||
|
||||
ProcessOutput output = ProcessControl.StartAndWaitForReady(wrappedProcess, 5, ProcessReadyIdentifier, logger);
|
||||
if (singleNodeReplSet)
|
||||
{
|
||||
var replicaSetReady = false;
|
||||
|
||||
// subscribe to output from mongod process and check for replica set ready message
|
||||
wrappedProcess.OutputDataReceived += (_, args) => replicaSetReady |= !string.IsNullOrWhiteSpace(args.Data) && args.Data.IndexOf(ReplicaSetReadyIdentifier, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
|
||||
MongoClient client = new MongoClient("mongodb://127.0.0.1:{0}/?directConnection=true&replicaSet={1}".Formatted(port, ReplicaSetName));
|
||||
var admin = client.GetDatabase("admin");
|
||||
var replConfig = new BsonDocument(new List<BsonElement>()
|
||||
{
|
||||
new BsonElement("_id", ReplicaSetName),
|
||||
new BsonElement("members",
|
||||
new BsonArray {new BsonDocument {{"_id", 0}, {"host", "127.0.0.1:{0}".Formatted(port)}}})
|
||||
});
|
||||
var command = new BsonDocument("replSetInitiate", replConfig);
|
||||
admin.RunCommand<BsonDocument>(command);
|
||||
|
||||
// wait until replica set is ready or until the timeout is reached
|
||||
SpinWait.SpinUntil(() => replicaSetReady, TimeSpan.FromSeconds(singleNodeReplSetWaitTimeout));
|
||||
|
||||
if (!replicaSetReady)
|
||||
{
|
||||
throw new TimeoutException($"Replica set initialization took longer than the specified timeout of {singleNodeReplSetWaitTimeout} seconds. Please consider increasing the value of {nameof(singleNodeReplSetWaitTimeout)}.");
|
||||
}
|
||||
|
||||
// wait until transaction is ready or until the timeout is reached
|
||||
SpinWait.SpinUntil(() =>
|
||||
client.Cluster.Description.Servers.Any(s => s.State == ServerState.Connected && s.IsDataBearing),
|
||||
TimeSpan.FromSeconds(singleNodeReplSetWaitTimeout));
|
||||
|
||||
if (!client.Cluster.Description.Servers.Any(s => s.State == ServerState.Connected && s.IsDataBearing))
|
||||
{
|
||||
throw new TimeoutException($"Cluster readiness for transactions took longer than the specified timeout of {singleNodeReplSetWaitTimeout} seconds. Please consider increasing the value of {nameof(singleNodeReplSetWaitTimeout)}.");
|
||||
}
|
||||
}
|
||||
|
||||
MongoDbProcess mongoDbProcess = new MongoDbProcess(wrappedProcess)
|
||||
{
|
||||
ErrorOutput = output.ErrorOutput,
|
||||
StandardOutput = output.StandardOutput
|
||||
};
|
||||
|
||||
return mongoDbProcess;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoImportExport.cs
Normal file
46
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoImportExport.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public static class MongoImportExport
|
||||
{
|
||||
/// <summary>
|
||||
/// Input File: Absolute path stays unchanged, relative path will be relative to current executing directory (usually the /bin folder)
|
||||
/// </summary>
|
||||
public static ProcessOutput Import(string binariesDirectory, int port, string database, string collection, string inputFile, bool drop, string additionalMongodArguments = null)
|
||||
{
|
||||
string finalPath = FolderSearch.FinalizePath(inputFile);
|
||||
|
||||
if (!File.Exists(finalPath))
|
||||
{
|
||||
throw new FileNotFoundException("File not found", finalPath);
|
||||
}
|
||||
|
||||
string fileName = Path.Combine("{0}", "{1}").Formatted(binariesDirectory, MongoDbDefaults.MongoImportExecutable);
|
||||
string arguments = @"--host localhost --port {0} --db {1} --collection {2} --file ""{3}""".Formatted(port, database, collection, finalPath);
|
||||
if (drop) { arguments += " --drop"; }
|
||||
arguments += MongodArguments.GetValidAdditionalArguments(arguments, additionalMongodArguments);
|
||||
|
||||
Process process = ProcessControl.ProcessFactory(fileName, arguments);
|
||||
|
||||
return ProcessControl.StartAndWaitForExit(process);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output File: Absolute path stays unchanged, relative path will be relative to current executing directory (usually the /bin folder)
|
||||
/// </summary>
|
||||
public static ProcessOutput Export(string binariesDirectory, int port, string database, string collection, string outputFile, string additionalMongodArguments = null)
|
||||
{
|
||||
string finalPath = FolderSearch.FinalizePath(outputFile);
|
||||
|
||||
string fileName = Path.Combine("{0}", "{1}").Formatted(binariesDirectory, MongoDbDefaults.MongoExportExecutable);
|
||||
string arguments = @"--host localhost --port {0} --db {1} --collection {2} --out ""{3}""".Formatted(port, database, collection, finalPath);
|
||||
arguments += MongodArguments.GetValidAdditionalArguments(arguments, additionalMongodArguments);
|
||||
|
||||
Process process = ProcessControl.ProcessFactory(fileName, arguments);
|
||||
|
||||
return ProcessControl.StartAndWaitForExit(process);
|
||||
}
|
||||
}
|
||||
}
|
||||
77
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoLogStatement.cs
Normal file
77
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongoLogStatement.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure of a log generated by mongod. Used to deserialize the logs
|
||||
/// and pass them to an ILogger.
|
||||
/// See: https://docs.mongodb.com/manual/reference/log-messages/#json-log-output-format
|
||||
/// Note: "truncated" and "size" are not parsed as we're unsure how to
|
||||
/// properly parse and use them.
|
||||
/// </summary>
|
||||
class MongoLogStatement
|
||||
{
|
||||
[JsonPropertyName("t")]
|
||||
public MongoDate MongoDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Severity of the logs as defined by MongoDB. Mapped to LogLevel
|
||||
/// as defined by Microsoft.
|
||||
/// D1-D2 mapped to Debug level. D3-D5 mapped Trace level.
|
||||
/// </summary>
|
||||
[JsonPropertyName("s")]
|
||||
public string Severity { get; set; }
|
||||
|
||||
public LogLevel Level
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(Severity))
|
||||
return LogLevel.None;
|
||||
switch (Severity)
|
||||
{
|
||||
case "F": return LogLevel.Critical;
|
||||
case "E": return LogLevel.Error;
|
||||
case "W": return LogLevel.Warning;
|
||||
case "I": return LogLevel.Information;
|
||||
case "D":
|
||||
case "D1":
|
||||
case "D2":
|
||||
return LogLevel.Debug;
|
||||
case "D3":
|
||||
case "D4":
|
||||
case "D5":
|
||||
default:
|
||||
return LogLevel.Trace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonPropertyName("c")]
|
||||
public string Component { get; set; }
|
||||
|
||||
[JsonPropertyName("ctx")]
|
||||
public string Context { get; set; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[JsonPropertyName("msg")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[JsonPropertyName("tags")]
|
||||
public IEnumerable<string> Tags { get; set; }
|
||||
|
||||
[JsonPropertyName("attr")]
|
||||
public IDictionary<string, JsonElement> Attributes { get; set; }
|
||||
}
|
||||
class MongoDate
|
||||
{
|
||||
[JsonPropertyName("$date")]
|
||||
public DateTime DateTime { get; set; }
|
||||
}
|
||||
}
|
||||
74
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongodArguments.cs
Normal file
74
Mongo2Go-4.1.0/src/Mongo2Go/Helper/MongodArguments.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public static class MongodArguments
|
||||
{
|
||||
private const string ArgumentSeparator = "--";
|
||||
private const string Space = " ";
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <paramref name="additionalMongodArguments" /> if it is verified that it does not contain any mongod argument already defined by Mongo2Go.
|
||||
/// </summary>
|
||||
/// <param name="existingMongodArguments">mongod arguments defined by Mongo2Go</param>
|
||||
/// <param name="additionalMongodArguments">Additional mongod arguments</param>
|
||||
/// <exception cref="T:System.ArgumentException"><paramref name="additionalMongodArguments" /> contains at least one mongod argument already defined by Mongo2Go</exception>
|
||||
/// <returns>A string with the additional mongod arguments</returns>
|
||||
public static string GetValidAdditionalArguments(string existingMongodArguments, string additionalMongodArguments)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(additionalMongodArguments))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var existingMongodArgumentArray = existingMongodArguments.Trim().Split(new[] { ArgumentSeparator }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var existingMongodArgumentOptions = new List<string>();
|
||||
for (var i = 0; i < existingMongodArgumentArray.Length; i++)
|
||||
{
|
||||
var argumentOptionSplit = existingMongodArgumentArray[i].Split(' ');
|
||||
|
||||
if (argumentOptionSplit.Length == 0
|
||||
|| string.IsNullOrWhiteSpace(argumentOptionSplit[0].Trim()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
existingMongodArgumentOptions.Add(argumentOptionSplit[0].Trim());
|
||||
}
|
||||
|
||||
var additionalMongodArgumentArray = additionalMongodArguments.Trim().Split(new[] { ArgumentSeparator }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var validAdditionalMongodArguments = new List<string>();
|
||||
var duplicateMongodArguments = new List<string>();
|
||||
for (var i = 0; i < additionalMongodArgumentArray.Length; i++)
|
||||
{
|
||||
var additionalArgument = additionalMongodArgumentArray[i].Trim();
|
||||
var argumentOptionSplit = additionalArgument.Split(' ');
|
||||
|
||||
if (argumentOptionSplit.Length == 0
|
||||
|| string.IsNullOrWhiteSpace(argumentOptionSplit[0].Trim()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (existingMongodArgumentOptions.Contains(argumentOptionSplit[0].Trim()))
|
||||
{
|
||||
duplicateMongodArguments.Add(argumentOptionSplit[0].Trim());
|
||||
}
|
||||
|
||||
validAdditionalMongodArguments.Add(ArgumentSeparator + additionalArgument);
|
||||
}
|
||||
|
||||
if (duplicateMongodArguments.Count != 0)
|
||||
{
|
||||
throw new ArgumentException($"mongod arguments defined by Mongo2Go ({string.Join(", ", existingMongodArgumentOptions)}) cannot be overriden. Please remove the following additional argument(s): {string.Join(", ", duplicateMongodArguments)}.");
|
||||
}
|
||||
|
||||
return validAdditionalMongodArguments.Count == 0
|
||||
? string.Empty
|
||||
: Space + string.Join(" ", validAdditionalMongodArguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#if NETSTANDARD2_0
|
||||
using System;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public static class NetStandard21Compatibility
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether a specified string occurs within this <paramref name="string"/>, using the specified comparison rules.
|
||||
/// </summary>
|
||||
/// <param name="string">The string to operate on.</param>
|
||||
/// <param name="value">The string to seek.</param>
|
||||
/// <param name="comparisonType">One of the enumeration values that specifies the rules to use in the comparison.</param>
|
||||
/// <returns><see langword="true"/> if the <paramref name="value"/> parameter occurs within this string, or if <paramref name="value"/> is the empty string (""); otherwise, <see langword="false"/>.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is <see langword="null"/></exception>
|
||||
public static bool Contains(this string @string, string value, StringComparison comparisonType)
|
||||
{
|
||||
if (@string == null) throw new ArgumentNullException(nameof(@string));
|
||||
|
||||
return @string.IndexOf(value, comparisonType) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public class NoFreePortFoundException : Exception
|
||||
{
|
||||
public NoFreePortFoundException() { }
|
||||
public NoFreePortFoundException(string message) : base(message) { }
|
||||
public NoFreePortFoundException(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
}
|
||||
37
Mongo2Go-4.1.0/src/Mongo2Go/Helper/PortPool.cs
Normal file
37
Mongo2Go-4.1.0/src/Mongo2Go/Helper/PortPool.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Intention: port numbers won't be assigned twice to avoid connection problems with integration tests
|
||||
/// </summary>
|
||||
public sealed class PortPool : IPortPool
|
||||
{
|
||||
private static readonly PortPool Instance = new PortPool();
|
||||
|
||||
// Explicit static constructor to tell C# compiler
|
||||
// not to mark type as beforefieldinit
|
||||
static PortPool()
|
||||
{
|
||||
}
|
||||
|
||||
// Singleton
|
||||
private PortPool()
|
||||
{
|
||||
}
|
||||
|
||||
public static PortPool GetInstance
|
||||
{
|
||||
get { return Instance; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns and reserves a new port
|
||||
/// </summary>
|
||||
public int GetNextOpenPort()
|
||||
{
|
||||
IPortWatcher portWatcher = PortWatcherFactory.CreatePortWatcher();
|
||||
return portWatcher.FindOpenPort();
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Mongo2Go-4.1.0/src/Mongo2Go/Helper/PortWatcher.cs
Normal file
38
Mongo2Go-4.1.0/src/Mongo2Go/Helper/PortWatcher.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public class PortWatcher : IPortWatcher
|
||||
{
|
||||
public int FindOpenPort()
|
||||
{
|
||||
// Locate a free port on the local machine by binding a socket to
|
||||
// an IPEndPoint using IPAddress.Any and port 0. The socket will
|
||||
// select a free port.
|
||||
int listeningPort = 0;
|
||||
Socket portSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
try
|
||||
{
|
||||
IPEndPoint socketEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
portSocket.Bind(socketEndPoint);
|
||||
socketEndPoint = (IPEndPoint)portSocket.LocalEndPoint;
|
||||
listeningPort = socketEndPoint.Port;
|
||||
}
|
||||
finally
|
||||
{
|
||||
portSocket.Close();
|
||||
}
|
||||
|
||||
return listeningPort;
|
||||
}
|
||||
|
||||
public bool IsPortAvailable(int portNumber)
|
||||
{
|
||||
IPEndPoint[] tcpConnInfoArray = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
|
||||
return tcpConnInfoArray.All(endpoint => endpoint.Port != portNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
Mongo2Go-4.1.0/src/Mongo2Go/Helper/PortWatcherFactory.cs
Normal file
14
Mongo2Go-4.1.0/src/Mongo2Go/Helper/PortWatcherFactory.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public class PortWatcherFactory
|
||||
{
|
||||
public static IPortWatcher CreatePortWatcher()
|
||||
{
|
||||
return RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|
||||
? (IPortWatcher) new UnixPortWatcher()
|
||||
: new PortWatcher();
|
||||
}
|
||||
}
|
||||
}
|
||||
163
Mongo2Go-4.1.0/src/Mongo2Go/Helper/ProcessControl.cs
Normal file
163
Mongo2Go-4.1.0/src/Mongo2Go/Helper/ProcessControl.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public static class ProcessControl
|
||||
{
|
||||
public static WrappedProcess ProcessFactory(string fileName, string arguments)
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = arguments,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
};
|
||||
|
||||
WrappedProcess process = new WrappedProcess { StartInfo = startInfo };
|
||||
return process;
|
||||
}
|
||||
|
||||
public static ProcessOutput StartAndWaitForExit(Process process)
|
||||
{
|
||||
List<string> errorOutput = new List<string>();
|
||||
List<string> standardOutput = new List<string>();
|
||||
|
||||
process.ErrorDataReceived += (sender, args) => errorOutput.Add(args.Data);
|
||||
process.OutputDataReceived += (sender, args) => standardOutput.Add(args.Data);
|
||||
|
||||
process.Start();
|
||||
|
||||
process.BeginErrorReadLine();
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
process.CancelErrorRead();
|
||||
process.CancelOutputRead();
|
||||
|
||||
return new ProcessOutput(errorOutput, standardOutput);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads from Output stream to determine if process is ready
|
||||
/// </summary>
|
||||
public static ProcessOutput StartAndWaitForReady(Process process, int timeoutInSeconds, string processReadyIdentifier, ILogger logger = null)
|
||||
{
|
||||
if (timeoutInSeconds < 1 ||
|
||||
timeoutInSeconds > 10)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("timeoutInSeconds", "The amount in seconds should have a value between 1 and 10.");
|
||||
}
|
||||
|
||||
// Determine when the process is ready, and store the error and standard outputs
|
||||
// to eventually return them.
|
||||
List<string> errorOutput = new List<string>();
|
||||
List<string> standardOutput = new List<string>();
|
||||
bool processReady = false;
|
||||
|
||||
void OnProcessOnErrorDataReceived(object sender, DataReceivedEventArgs args) => errorOutput.Add(args.Data);
|
||||
void OnProcessOnOutputDataReceived(object sender, DataReceivedEventArgs args)
|
||||
{
|
||||
standardOutput.Add(args.Data);
|
||||
|
||||
if (!string.IsNullOrEmpty(args.Data) && args.Data.IndexOf(processReadyIdentifier, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
processReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
process.ErrorDataReceived += OnProcessOnErrorDataReceived;
|
||||
process.OutputDataReceived += OnProcessOnOutputDataReceived;
|
||||
|
||||
if (logger == null)
|
||||
WireLogsToConsoleAndDebugOutput(process);
|
||||
else
|
||||
WireLogsToLogger(process, logger);
|
||||
|
||||
process.Start();
|
||||
|
||||
process.BeginErrorReadLine();
|
||||
process.BeginOutputReadLine();
|
||||
|
||||
int lastResortCounter = 0;
|
||||
int timeOut = timeoutInSeconds * 10;
|
||||
while (!processReady)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
if (++lastResortCounter > timeOut)
|
||||
{
|
||||
// we waited X seconds.
|
||||
// for any reason the detection did not worked, eg. the identifier changed
|
||||
// lets assume everything is still ok
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//unsubscribing writing to list - to prevent memory overflow.
|
||||
process.ErrorDataReceived -= OnProcessOnErrorDataReceived;
|
||||
process.OutputDataReceived -= OnProcessOnOutputDataReceived;
|
||||
|
||||
return new ProcessOutput(errorOutput, standardOutput);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send the mongod process logs to .NET's console and debug outputs.
|
||||
/// </summary>
|
||||
/// <param name="process"></param>
|
||||
private static void WireLogsToConsoleAndDebugOutput(Process process)
|
||||
{
|
||||
void DebugOutputHandler(object sender, DataReceivedEventArgs args) => Debug.WriteLine(args.Data);
|
||||
void ConsoleOutputHandler(object sender, DataReceivedEventArgs args) => Console.WriteLine(args.Data);
|
||||
|
||||
//Writing to debug trace & console to enable test runners to capture the output
|
||||
process.ErrorDataReceived += DebugOutputHandler;
|
||||
process.ErrorDataReceived += ConsoleOutputHandler;
|
||||
process.OutputDataReceived += DebugOutputHandler;
|
||||
process.OutputDataReceived += ConsoleOutputHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses and redirects mongod logs to ILogger.
|
||||
/// </summary>
|
||||
/// <param name="process"></param>
|
||||
/// <param name="logger"></param>
|
||||
private static void WireLogsToLogger(Process process, ILogger logger)
|
||||
{
|
||||
// Parse the structured log and wire it to logger
|
||||
void OnReceivingLogFromMongod(object sender, DataReceivedEventArgs args)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(args.Data))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var log = JsonSerializer.Deserialize<MongoLogStatement>(args.Data);
|
||||
logger.Log(log.Level,
|
||||
"{message} - {attributes} - {date} - {component} - {context} - {id} - {tags}",
|
||||
log.Message, log.Attributes, log.MongoDate.DateTime, log.Component, log.Context, log.Id, log.Tags);
|
||||
}
|
||||
catch (Exception ex) when (ex is JsonException || ex is NotSupportedException)
|
||||
{
|
||||
logger.LogWarning(ex,
|
||||
"Failed parsing the mongod logs {log}. It could be that the format has changed. " +
|
||||
"See: https://docs.mongodb.com/manual/reference/log-messages/#std-label-log-message-json-output-format",
|
||||
args.Data);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Nothing else to do. Swallow the exception and do not wire the logs.
|
||||
}
|
||||
};
|
||||
process.ErrorDataReceived += OnReceivingLogFromMongod;
|
||||
process.OutputDataReceived += OnReceivingLogFromMongod;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
16
Mongo2Go-4.1.0/src/Mongo2Go/Helper/ProcessOutput.cs
Normal file
16
Mongo2Go-4.1.0/src/Mongo2Go/Helper/ProcessOutput.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public class ProcessOutput
|
||||
{
|
||||
public ProcessOutput(IEnumerable<string> errorOutput, IEnumerable<string> standardOutput)
|
||||
{
|
||||
StandardOutput = standardOutput;
|
||||
ErrorOutput = errorOutput;
|
||||
}
|
||||
|
||||
public IEnumerable<string> StandardOutput { get; private set; }
|
||||
public IEnumerable<string> ErrorOutput { get; private set; }
|
||||
}
|
||||
}
|
||||
13
Mongo2Go-4.1.0/src/Mongo2Go/Helper/ProcessWatcher.cs
Normal file
13
Mongo2Go-4.1.0/src/Mongo2Go/Helper/ProcessWatcher.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public class ProcessWatcher : IProcessWatcher
|
||||
{
|
||||
public bool IsProcessRunning(string processName)
|
||||
{
|
||||
return Process.GetProcessesByName(processName).Any();
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Mongo2Go-4.1.0/src/Mongo2Go/Helper/StringFormatExtension.cs
Normal file
27
Mongo2Go-4.1.0/src/Mongo2Go/Helper/StringFormatExtension.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// saves about 40 keystrokes
|
||||
/// </summary>
|
||||
public static class StringFormatExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Populates the template using the provided arguments and the invariant culture
|
||||
/// </summary>
|
||||
public static string Formatted(this string template, params object[] args)
|
||||
{
|
||||
return template.Formatted(CultureInfo.InvariantCulture, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the template using the provided arguments using the provided formatter
|
||||
/// </summary>
|
||||
public static string Formatted(this string template, IFormatProvider formatter, params object[] args)
|
||||
{
|
||||
return string.IsNullOrEmpty(template) ? string.Empty : string.Format(formatter, template, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Mongo2Go-4.1.0/src/Mongo2Go/Helper/UnixPortWatcher.cs
Normal file
46
Mongo2Go-4.1.0/src/Mongo2Go/Helper/UnixPortWatcher.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
|
||||
public class UnixPortWatcher : IPortWatcher
|
||||
{
|
||||
public int FindOpenPort ()
|
||||
{
|
||||
// Locate a free port on the local machine by binding a socket to
|
||||
// an IPEndPoint using IPAddress.Any and port 0. The socket will
|
||||
// select a free port.
|
||||
int listeningPort = 0;
|
||||
Socket portSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
try
|
||||
{
|
||||
IPEndPoint socketEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
portSocket.Bind(socketEndPoint);
|
||||
socketEndPoint = (IPEndPoint)portSocket.LocalEndPoint;
|
||||
listeningPort = socketEndPoint.Port;
|
||||
}
|
||||
finally
|
||||
{
|
||||
portSocket.Close();
|
||||
}
|
||||
|
||||
return listeningPort;
|
||||
}
|
||||
|
||||
public bool IsPortAvailable (int portNumber)
|
||||
{
|
||||
TcpListener tcpListener = new TcpListener (IPAddress.Loopback, portNumber);
|
||||
try {
|
||||
tcpListener.Start ();
|
||||
return true;
|
||||
}
|
||||
catch (SocketException) {
|
||||
return false;
|
||||
} finally
|
||||
{
|
||||
tcpListener.Stop ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Mongo2Go-4.1.0/src/Mongo2Go/Helper/WrappedProcess.cs
Normal file
9
Mongo2Go-4.1.0/src/Mongo2Go/Helper/WrappedProcess.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Mongo2Go.Helper
|
||||
{
|
||||
public class WrappedProcess : Process
|
||||
{
|
||||
public bool DoNotKill { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user