FastGithub/FastGithub/ServiceExtensions.cs
2021-11-14 03:40:08 +08:00

174 lines
6.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using FastGithub.DomainResolve;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using PInvoke;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
namespace FastGithub
{
/// <summary>
/// IHostBuilder扩展
/// </summary>
static class ServiceExtensions
{
/// <summary>
/// 控制命令
/// </summary>
private enum Command
{
Start,
Stop,
}
[SupportedOSPlatform("linux")]
[DllImport("libc", SetLastError = true)]
private static extern uint geteuid();
/// <summary>
/// 使用windows服务
/// </summary>
/// <param name="hostBuilder"></param>
/// <returns></returns>
public static IHostBuilder UseWindowsService(this IHostBuilder hostBuilder)
{
var contentRoot = Path.GetDirectoryName(Environment.GetCommandLineArgs().First());
if (contentRoot != null)
{
Environment.CurrentDirectory = contentRoot;
hostBuilder.UseContentRoot(contentRoot);
}
return WindowsServiceLifetimeHostBuilderExtensions.UseWindowsService(hostBuilder);
}
/// <summary>
/// 运行主机
/// </summary>
/// <param name="host"></param>
/// <param name="singleton"></param>
public static void Run(this IHost host, bool singleton = true)
{
if (TryGetCommand(out var cmd) && (OperatingSystem.IsWindows() || OperatingSystem.IsLinux()))
{
try
{
if (OperatingSystem.IsWindows())
{
UseCommandAtWindows(cmd);
}
else if (OperatingSystem.IsLinux())
{
UseCommandAtLinux(cmd);
}
}
catch (Exception ex)
{
var loggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
loggerFactory.CreateLogger(nameof(FastGithub)).LogError(ex.Message);
}
}
else
{
using var mutex = new Mutex(true, "Global\\FastGithub", out var firstInstance);
if (singleton == false || firstInstance)
{
HostingAbstractionsHostExtensions.Run(host);
}
}
}
/// <summary>
/// 获取控制指令
/// </summary>
/// <param name="cmd"></param>
/// <returns></returns>
private static bool TryGetCommand(out Command cmd)
{
var args = Environment.GetCommandLineArgs();
return Enum.TryParse(args.Skip(1).FirstOrDefault(), true, out cmd);
}
/// <summary>
/// 应用控制指令
/// </summary>
/// <param name="cmd"></param>
[SupportedOSPlatform("windows")]
private static void UseCommandAtWindows(Command cmd)
{
var binaryPath = Environment.GetCommandLineArgs().First();
var serviceName = Path.GetFileNameWithoutExtension(binaryPath);
var state = true;
if (cmd == Command.Start)
{
state = ServiceInstallUtil.InstallAndStartService(serviceName, binaryPath);
}
else if (cmd == Command.Stop)
{
state = ServiceInstallUtil.StopAndDeleteService(serviceName);
}
if (state == false)
{
throw new Win32Exception();
}
}
/// <summary>
/// 应用控制指令
/// </summary>
/// <param name="cmd"></param>
[SupportedOSPlatform("linux")]
private static void UseCommandAtLinux(Command cmd)
{
if (geteuid() != 0)
{
throw new UnauthorizedAccessException("无法操作服务没有root权限");
}
var binaryPath = Path.GetFullPath(Environment.GetCommandLineArgs().First());
var serviceName = Path.GetFileNameWithoutExtension(binaryPath);
var serviceFilePath = $"/etc/systemd/system/{serviceName}.service";
if (cmd == Command.Start)
{
var serviceBuilder = new StringBuilder()
.AppendLine("[Unit]")
.AppendLine($"Description={serviceName}")
.AppendLine()
.AppendLine("[Service]")
.AppendLine("Type=notify")
.AppendLine($"User={Environment.UserName}")
.AppendLine($"ExecStart={binaryPath}")
.AppendLine($"WorkingDirectory={Path.GetDirectoryName(binaryPath)}")
.AppendLine()
.AppendLine("[Install]")
.AppendLine("WantedBy=multi-user.target");
File.WriteAllText(serviceFilePath, serviceBuilder.ToString());
Process.Start("chcon", $"--type=bin_t {binaryPath}").WaitForExit(); // SELinux
Process.Start("systemctl", "daemon-reload").WaitForExit();
Process.Start("systemctl", $"start {serviceName}.service").WaitForExit();
Process.Start("systemctl", $"enable {serviceName}.service").WaitForExit();
}
else if (cmd == Command.Stop)
{
Process.Start("systemctl", $"stop {serviceName}.service").WaitForExit();
Process.Start("systemctl", $"disable {serviceName}.service").WaitForExit();
if (File.Exists(serviceFilePath))
{
File.Delete(serviceFilePath);
}
Process.Start("systemctl", "daemon-reload").WaitForExit();
}
}
}
}