2021-04-23 08:11:32 -07:00
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Espresso.Shell.Core ;
2021-04-20 08:31:18 -07:00
using Espresso.Shell.Models ;
using Newtonsoft.Json ;
2021-04-08 15:12:09 -07:00
using System ;
using System.CommandLine ;
using System.CommandLine.Invocation ;
2021-04-20 07:54:03 -07:00
using System.IO ;
2021-04-08 15:12:09 -07:00
using System.Threading ;
namespace Espresso.Shell
{
class Program
{
private static Mutex mutex = null ;
private const string appName = "Espresso" ;
2021-04-23 08:47:18 -07:00
private static FileSystemWatcher watcher = null ;
2021-04-23 08:11:32 -07:00
public static Mutex Mutex { get = > mutex ; set = > mutex = value ; }
2021-04-22 08:14:07 -07:00
2021-04-08 15:12:09 -07:00
static int Main ( string [ ] args )
{
bool instantiated ;
2021-04-23 08:11:32 -07:00
Mutex = new Mutex ( true , appName , out instantiated ) ;
2021-04-08 15:12:09 -07:00
if ( ! instantiated )
{
2021-04-20 08:31:18 -07:00
ForceExit ( appName + " is already running! Exiting the application." , 1 ) ;
2021-04-08 15:12:09 -07:00
}
Console . WriteLine ( "Espresso - Computer Caffeination Engine" ) ;
2021-04-20 07:54:03 -07:00
var configOption = new Option < string > (
aliases : new [ ] { "--config" , "-c" } ,
getDefaultValue : ( ) = > string . Empty ,
description : "Pointer to a PowerToys configuration file that the tool will be watching for changes. All other options are disregarded if config is used." )
{
Argument = new Argument < string > ( ( ) = > string . Empty )
{
Arity = ArgumentArity . ZeroOrOne ,
} ,
} ;
configOption . Required = false ;
2021-04-08 16:09:59 -07:00
var displayOption = new Option < bool > (
aliases : new [ ] { "--display-on" , "-d" } ,
getDefaultValue : ( ) = > true ,
description : "Determines whether the display should be kept awake." )
2021-04-08 15:12:09 -07:00
{
2021-04-08 16:09:59 -07:00
Argument = new Argument < bool > ( ( ) = > false )
{
Arity = ArgumentArity . ZeroOrOne ,
} ,
} ;
displayOption . Required = false ;
var timeOption = new Option < long > (
aliases : new [ ] { "--time-limit" , "-t" } ,
2021-04-08 15:12:09 -07:00
getDefaultValue : ( ) = > 0 ,
description : "Determines the interval, in seconds, during which the computer is kept awake." )
2021-04-08 16:09:59 -07:00
{
Argument = new Argument < long > ( ( ) = > 0 )
{
Arity = ArgumentArity . ExactlyOne ,
} ,
} ;
timeOption . Required = false ;
var rootCommand = new RootCommand
{
2021-04-20 07:54:03 -07:00
configOption ,
2021-04-08 16:09:59 -07:00
displayOption ,
timeOption
2021-04-08 15:12:09 -07:00
} ;
rootCommand . Description = appName ;
2021-04-20 07:54:03 -07:00
rootCommand . Handler = CommandHandler . Create < string , bool , long > ( HandleCommandLineArguments ) ;
2021-04-08 15:12:09 -07:00
return rootCommand . InvokeAsync ( args ) . Result ;
}
2021-04-20 08:31:18 -07:00
private static void ForceExit ( string message , int exitCode )
{
Console . WriteLine ( message ) ;
Console . ReadKey ( ) ;
Environment . Exit ( exitCode ) ;
}
2021-04-20 07:54:03 -07:00
private static void HandleCommandLineArguments ( string config , bool displayOn , long timeLimit )
2021-04-08 15:12:09 -07:00
{
2021-04-08 16:09:59 -07:00
Console . WriteLine ( $"The value for --display-on is: {displayOn}" ) ;
Console . WriteLine ( $"The value for --time-limit is: {timeLimit}" ) ;
2021-04-20 07:54:03 -07:00
if ( ! string . IsNullOrWhiteSpace ( config ) )
2021-04-08 15:12:09 -07:00
{
2021-04-20 07:54:03 -07:00
// Configuration file is used, therefore we disregard any other command-line parameter
// and instead watch for changes in the file.
2021-04-20 08:31:18 -07:00
try
{
2021-04-23 08:47:18 -07:00
watcher = new FileSystemWatcher
2021-04-20 08:31:18 -07:00
{
Path = Path . GetDirectoryName ( config ) ,
EnableRaisingEvents = true ,
2021-04-23 08:47:18 -07:00
NotifyFilter = NotifyFilters . LastWrite | NotifyFilters . Size ,
2021-04-20 08:31:18 -07:00
Filter = Path . GetFileName ( config )
} ;
watcher . Changed + = new FileSystemEventHandler ( HandleEspressoConfigChange ) ;
2021-04-22 08:14:07 -07:00
// Initially the file might not be updated, so we need to start processing
// settings right away.
ProcessSettings ( config ) ;
2021-04-20 08:31:18 -07:00
}
catch ( Exception ex )
2021-04-08 15:12:09 -07:00
{
2021-04-23 08:47:18 -07:00
Console . WriteLine ( $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}" ) ;
//ForceExit($"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}", 1);
2021-04-20 08:31:18 -07:00
}
2021-04-08 15:12:09 -07:00
}
2021-04-08 16:30:56 -07:00
else
{
2021-04-20 07:54:03 -07:00
if ( timeLimit < = 0 )
2021-04-08 16:30:56 -07:00
{
2021-04-20 07:54:03 -07:00
// Indefinite keep awake.
bool success = APIHelper . SetIndefiniteKeepAwake ( displayOn ) ;
if ( success )
{
Console . WriteLine ( $"Currently in indefinite keep awake. Display always on: {displayOn}" ) ;
}
else
{
Console . WriteLine ( "Could not set up the state to be indefinite keep awake." ) ;
}
2021-04-08 16:30:56 -07:00
}
else
{
2021-04-20 07:54:03 -07:00
// Timed keep-awake.
bool success = APIHelper . SetTimedKeepAwake ( timeLimit , displayOn ) ;
if ( success )
{
Console . WriteLine ( $"Finished execution of timed keep-awake." ) ;
// Because the timed keep-awake execution completed, there is no reason for
// Espresso to stay alive - I will just shut down the application until it's
// launched again by the user.
Environment . Exit ( 0 ) ;
}
else
{
Console . WriteLine ( "Could not set up the state to be timed keep awake." ) ;
}
2021-04-08 16:30:56 -07:00
}
}
2021-04-08 15:12:09 -07:00
new ManualResetEvent ( false ) . WaitOne ( ) ;
}
2021-04-20 07:54:03 -07:00
private static void HandleEspressoConfigChange ( object sender , FileSystemEventArgs e )
2021-04-22 08:14:07 -07:00
{
2021-04-23 08:47:18 -07:00
Console . WriteLine ( "Detected a file change. Reacting..." ) ;
2021-04-22 08:14:07 -07:00
ProcessSettings ( e . FullPath ) ;
}
private static void ProcessSettings ( string fullPath )
2021-04-20 07:54:03 -07:00
{
2021-04-20 08:31:18 -07:00
try
{
2021-04-22 08:14:07 -07:00
EspressoSettingsModel settings = null ;
2021-04-20 08:31:18 -07:00
2021-04-23 08:47:18 -07:00
var fileStream = SettingsHelper . GetSettingsFile ( fullPath , 3 ) ;
2021-04-22 08:14:07 -07:00
if ( fileStream ! = null )
2021-04-20 08:31:18 -07:00
{
2021-04-22 08:14:07 -07:00
using ( fileStream )
{
using StreamReader reader = new StreamReader ( fileStream ) ;
settings = JsonConvert . DeserializeObject < EspressoSettingsModel > ( reader . ReadToEnd ( ) ) ;
}
if ( settings ! = null )
{
// If the settings were successfully processed, we need to set the right mode of operation.
// INDEFINITE = 0
// TIMED = 1
switch ( settings . Properties . Mode )
2021-04-20 08:31:18 -07:00
{
2021-04-22 08:14:07 -07:00
case 0 :
{
// Indefinite keep awake.
bool success = APIHelper . SetIndefiniteKeepAwake ( settings . Properties . KeepDisplayOn . Value ) ;
if ( success )
{
Console . WriteLine ( $"Currently in indefinite keep awake. Display always on: {settings.Properties.KeepDisplayOn.Value}" ) ;
}
else
{
Console . WriteLine ( "Could not set up the state to be indefinite keep awake." ) ;
}
break ;
}
case 1 :
{
// Timed keep-awake.
long computedTime = ( settings . Properties . Hours . Value * 60 * 60 ) + ( settings . Properties . Minutes . Value * 60 ) ;
Console . WriteLine ( $"In timed keep-awake mode. Expecting to be awake for {computedTime} seconds." ) ;
bool success = APIHelper . SetTimedKeepAwake ( computedTime , settings . Properties . KeepDisplayOn . Value ) ;
if ( success )
{
Console . WriteLine ( $"Finished execution of timed keep-awake." ) ;
ResetNormalPowerState ( ) ;
}
else
{
Console . WriteLine ( "Could not set up the state to be timed keep awake." ) ;
}
break ;
}
default :
{
ForceExit ( "Could not select the right mode of operation. Existing..." , 1 ) ;
break ;
}
2021-04-20 08:31:18 -07:00
}
2021-04-22 08:14:07 -07:00
}
else
{
Console . WriteLine ( "Settings are null." ) ;
}
}
else
{
Console . WriteLine ( "Could not get handle on file." ) ;
2021-04-20 08:31:18 -07:00
}
}
catch ( Exception ex )
{
2021-04-23 08:00:22 -07:00
Console . WriteLine ( $"There was a problem reading the configuration file.\n{ex.Message}" ) ;
2021-04-20 08:31:18 -07:00
}
}
private static void ResetNormalPowerState ( )
{
bool success = APIHelper . SetNormalKeepAwake ( ) ;
if ( success )
{
Console . WriteLine ( "Returned to normal keep-awake state." ) ;
}
else
{
Console . WriteLine ( "Could not return to normal keep-awake state." ) ;
}
2021-04-20 07:54:03 -07:00
}
2021-04-08 15:12:09 -07:00
}
}