// --------------------------------------------------------------------------------------------------------------------
//
// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
//
//
// Manage the HandBrake Worker Process Service.
//
// --------------------------------------------------------------------------------------------------------------------
namespace HandBrake.Worker
{
using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.CompilerServices;
using System.Threading;
using HandBrake.Interop.Interop;
using HandBrake.Worker.Logging;
using HandBrake.Worker.Routing;
using HandBrake.Worker.Services;
using HandBrake.Worker.Services.Interfaces;
using HandBrake.Worker.Utilities;
public class Program
{
private static readonly ITokenService TokenService = new TokenService();
private static ApiRouter router;
private static ManualResetEvent manualResetEvent = new ManualResetEvent(false);
private static int parentProcessId = -1;
public static void Main(string[] args)
{
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
Portable.Initialise();
if (!Portable.IsProcessIsolationEnabled())
{
Console.WriteLine("Worker is disabled in portable.ini");
Console.WriteLine("Press 'Enter' to exit");
Console.Read();
return;
}
int port = 8037; // Default Port;
string envVar = Environment.GetEnvironmentVariable("HB_PORT");
if (!string.IsNullOrWhiteSpace(envVar))
{
if (int.TryParse(envVar, out var parsedPort))
{
port = parsedPort;
}
}
string token = Environment.GetEnvironmentVariable("HB_TOKEN");
if (!string.IsNullOrWhiteSpace(token))
{
TokenService.RegisterToken(token);
}
envVar = Environment.GetEnvironmentVariable("HB_PID");
if (!string.IsNullOrWhiteSpace(envVar))
{
if (int.TryParse(envVar, out var parsedPid))
{
parentProcessId = parsedPid;
}
}
// Clear the environment variables for this process. We no longer need them.
Environment.SetEnvironmentVariable("HB_PORT", string.Empty);
Environment.SetEnvironmentVariable("HB_TOKEN", string.Empty);
Environment.SetEnvironmentVariable("HB_PID", string.Empty);
GC.Collect();
GC.WaitForPendingFinalizers();
if (!TokenService.IsTokenSet())
{
ConsoleOutput.WriteLine("# HandBrake Worker", ConsoleColor.DarkYellow);
ConsoleOutput.WriteLine("*** Please note, this application should not be run standalone. To run the GUI, please use 'HandBrake.exe' *** ", ConsoleColor.Red);
Console.WriteLine();
}
ConsoleOutput.WriteLine("Worker: Starting HandBrake Engine ...", ConsoleColor.White, true);
if (parentProcessId != -1)
{
ConsoleOutput.WriteLine(string.Format("Worker: Parent Process Id {0}", parentProcessId), ConsoleColor.White, true);
// TODO Support Process Termination if the Parent process dies.
}
router = new ApiRouter();
router.TerminationEvent += Router_TerminationEvent;
ConsoleOutput.WriteLine(string.Format("Worker: Starting Web Server on port {0} ...", port), ConsoleColor.White, true);
Dictionary> apiHandlers = RegisterApiHandlers();
HttpServer webServer = new HttpServer(apiHandlers, port, TokenService);
int runCode = webServer.Run();
if (runCode == 0)
{
ConsoleOutput.WriteLine("Worker: Server Started", ConsoleColor.White, true);
manualResetEvent.WaitOne();
webServer.Stop();
ConsoleOutput.WriteLine("Worker: Server Stopped", ConsoleColor.White, true);
}
else
{
ConsoleOutput.WriteLine(string.Format("Worker is exiting ... ({0})", runCode));
Environment.Exit(runCode);
}
}
private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
HandBrakeUtils.DisposeGlobal();
}
private static Dictionary> RegisterApiHandlers()
{
Dictionary> apiHandlers =
new Dictionary>();
// Process Handling
apiHandlers.Add("Shutdown", ShutdownServer);
apiHandlers.Add("IsTokenSet", IsTokenSet);
apiHandlers.Add("RegisterToken", RegisterToken);
apiHandlers.Add("Version", router.GetVersionInfo);
// Logging
apiHandlers.Add("GetAllLogMessages", router.GetAllLogMessages);
apiHandlers.Add("GetLogMessagesFromIndex", router.GetLogMessagesFromIndex);
apiHandlers.Add("ResetLogging", router.ResetLogging);
// Encode APIs
apiHandlers.Add("StartEncode", router.StartEncode);
apiHandlers.Add("PauseEncode", router.PauseEncode);
apiHandlers.Add("ResumeEncode", router.ResumeEncode);
apiHandlers.Add("StopEncode", router.StopEncode);
apiHandlers.Add("PollEncodeProgress", router.PollEncodeProgress);
// Scan APIs
apiHandlers.Add("StartScan", router.StartScan);
apiHandlers.Add("StopScan", router.StopScan);
apiHandlers.Add("PollScanProgress", router.PollScanProgress);
apiHandlers.Add("GetTitles", router.GetScanTitles);
apiHandlers.Add("GetMainTitle", router.GetMainScanTitle);
apiHandlers.Add("GetPreview", router.GetPreview);
return apiHandlers;
}
private static string RegisterToken(HttpListenerRequest request)
{
string requestPostData = HttpUtilities.GetRequestPostData(request);
if (!string.IsNullOrEmpty(requestPostData) && !TokenService.IsTokenSet())
{
return TokenService.RegisterToken(requestPostData).ToString();
}
return false.ToString();
}
private static string IsTokenSet(HttpListenerRequest arg)
{
return TokenService.IsTokenSet().ToString();
}
private static void Router_TerminationEvent(object sender, EventArgs e)
{
Console.WriteLine("Worker: Termination event received. ");
manualResetEvent.Set();
Environment.Exit(0);
}
private static string ShutdownServer(HttpListenerRequest request)
{
manualResetEvent.Set();
return "Server Terminated";
}
}
}