public static async Task Main(string[] args) { Logo(); try { // TODO PrepareLogger(); // If this returns true, args were sent to an already-running instance, we can exit. if (await CommandLineSwitchPipe.TrySendArgs(args)) { return; } // Read appsettings.json and do some basic checks like path validity ValidateConfiguration(); // Set up a pipe to receive switches once we're running ctsSwitchPipe = new CancellationTokenSource(); _ = Task.Run(() => CommandLineSwitchPipe.StartServer(ProcessSwitches, ctsSwitchPipe.Token)); // The localpath should be clear of files at startup FileProcessing.MoveSnapshotsToStorage(); FileProcessing.MoveAbandonedVideoToStorage(); // TODO remove zero-length circular buffer h264, don't move it FileProcessing.ClearLocalStorage(); // The default state, although some command-line switches may change this RequestedState = new MotionDetectionState(); // If command-line args were passed to this instance, process them now if (args.Length > 0) { ProcessSwitches(args, false); if (RequestedState == null) { Console.WriteLine("No new execution state requested, exiting."); return; } } // If a command-line switch arrives in the SwitchPipe thread, it can // cancel the state-change token to end the current processing state // and request a different processing state. We loop until no new state // is requested, at which point the app exits. while (RequestedState != null) { RunningState = RequestedState; RequestedState = null; ctsRunningState = new CancellationTokenSource(); await RunningState.RunAsync(ctsRunningState.Token).ConfigureAwait(false); RunningState.Dispose(); RunningState = null; } } catch (Exception ex) { Console.WriteLine($"\nException of type {ex.GetType().Name}\n{ex.Message}"); if (ex.InnerException != null) { Console.Write(ex.InnerException.Message); } Console.WriteLine($"\n{ex.StackTrace}"); } finally { // Stephen Cleary says CTS disposal is unnecessary as long as you cancel ctsSwitchPipe?.Cancel(); ctsRunningState?.Cancel(); RequestedState?.Dispose(); RunningState?.Dispose(); } Console.WriteLine("Exiting spicam."); }
private static void ProcessSwitches(string[] args, bool argsReceivedFromPipe) { if (args.Length == 0) { return; } bool showHelp = true; var command = args[0].Trim().ToLower(); switch (command) { case "-quit": case "-exit": case "-stop": { showHelp = false; if (!argsReceivedFromPipe) { throw new Exception("Nothing to stop, no running instance of spicam found."); } // Cancel the current processing state. Setting RequestedState // to null will cause the application to exit. RequestedState = null; ctsRunningState.Cancel(); } break; case "-quiet": { showHelp = false; if (args.Length != 2 || !int.TryParse(args[1], out var minutes)) { Console.WriteLine("The -quiet switch requires a 'minutes' parameter."); return; } // Ensure the target of this switch is doing motion detection (or will be) var target = (argsReceivedFromPipe) ? RunningState as MotionDetectionState : RequestedState as MotionDetectionState; if (target == null) { Console.WriteLine("The -quiet switch only applies to motion detection."); return; } Console.WriteLine($"Motion detection suppressed for {minutes} minutes."); target.SetQuietTime(minutes); } break; case "-snapshot": { Console.WriteLine($"\n\n{command} switch not implemented yet...\n\n"); showHelp = false; } break; case "-video": { Console.WriteLine($"\n\n{command} switch not implemented yet...\n\n"); showHelp = false; if (args.Length != 2) { Console.WriteLine("The -video switch requires a 'seconds' parameter."); return; } } break; case "-stream": { Console.WriteLine($"\n\n{command} switch not implemented yet...\n\n"); showHelp = false; if (args.Length != 2) { Console.WriteLine("The -stream switch requires an 'on' or 'off' parameter."); return; } } break; case "-analysis": { Console.WriteLine($"\n\n{command} switch not implemented yet...\n\n"); showHelp = false; if (args.Length != 2) { Console.WriteLine("The -analysis switch requires an 'on' or 'off' parameter."); return; } } break; case "-getmask": { Console.WriteLine($"\n\n{command} switch not implemented yet...\n\n"); showHelp = false; if (args.Length != 2) { Console.WriteLine("The -getmask switch requires a 'directory' parameter."); return; } } break; case "-?": case "-help": break; default: Console.WriteLine($"\nUnrecognized switch {command}, cancelling requested state"); RequestedState = null; break; } if (showHelp) { Console.WriteLine("\nspicam command-line switches:\n"); Console.WriteLine("-? help (this list)"); Console.WriteLine("-stop terminates an already-running instance of spicam"); Console.WriteLine("-quiet [minutes] disables motion detection for the specified time"); Console.WriteLine("-snapshot write a full-sized timestamped snapshot JPG to the storagepath"); Console.WriteLine("-video [seconds] write full-sized timestamped MP4 video(s) to the storagepath"); Console.WriteLine("-stream [on | off] MJPEG stream of the camera's view"); Console.WriteLine("-analysis [on | off] MJPEG stream of the spicam motion detection algorithm"); Console.WriteLine("-getmask [directory] write a 640 x 480 x 24bpp snapshot.bmp to the directory"); Console.WriteLine("\nSwitches may not be combined. The -quiet, -snapshot, and -video switches are only accepted"); Console.WriteLine("when spicam is already running in normal motion detection mode. The -stream and -analysis"); Console.WriteLine("switches are intended for short-term use. The -stream, -analysis, and -getmask switches will"); Console.WriteLine("interrupt motion detection, if running. Set streaming to 'off' to resume motion detection."); Console.WriteLine(); } }