const String MODULE = "MAIN: "; // for debug log. static void Main(string[] args) { string baseWorkingDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\PuzzleOracle\\consolidated"; MyConsole.Initialize(); MyConsole.WriteLine("LOG PROCESSOR Version " + VERSION); MyConsole.WriteLine(String.Format("Working directory [{0}]", baseWorkingDir)); MyConsole.WriteLine("Press CTRL-C to quit"); try { if (!initializeLogging(baseWorkingDir)) { // Can't progress... throw new ApplicationException("Cannot initialize logging."); } // Initialie the blocking work queue - it runs all significant processing operations in sequence on the main thread. BlockingWorkQueue workQueue = new BlockingWorkQueue(); //workQueue.enque(null, null, (o, ea) => { Console.WriteLine("TEST WORK ITEM -A-"); }); //workQueue.enque(null, null, (o, ea) => { Console.WriteLine("TEST WORK ITEM -B-"); }); // Register the CTRL-C handler - this lets the user quit the program and potentially enter other commands. // TODO: Currently the handler simply causes the work queue to exit after the latter processes current work items. Perhaps add some // command processing and request confirmation of this behavior. Console.CancelKeyPress += new ConsoleCancelEventHandler((o, ea) => { myCtrlCHandler(ea, workQueue); }); // Create the file copier - responsible for copying files from thumb drives to a staging directory, verifying the file copy and then moving // the source files into an arcive subdir on the thumb drive, and (finally) moving the newly copied files under the "new" directory. FileCopier fileCopier = new FileCopier(baseWorkingDir); // Create a new-drive notifier and hook it up to the file copier - so that the latter will get notified whenever there is a new removable drive // plugged in. //NewDriveNotifier ndn = new NewDriveNotifier((o, e) => { bwq.enque(o, e, (o1, ea1) => { Console.WriteLine("WORK ITEM -NEW DRIVE-" + ((NewDriveNotifierEventArgs)ea1).driveName); }); }); using (NewDriveNotifier driveNotifier = new NewDriveNotifier((o, e) => { workQueue.enque(o, e, fileCopier.newDriveHandler); })) { // Create a log consumer - this processes submission requests pulled from individual puzzle oracle log files. LogConsumer logConsumer = new LogConsumer(baseWorkingDir); // Create the log processor - that processes new log files as they show up in the "new" directory. Hook it up to the log consumer so that the latter // processes the submissions requests. String newLogsDir = fileCopier.newDir; using (LogProcessor lp = new LogProcessor(newLogsDir, (o, e) => { workQueue.enque(o, e, logConsumer.logEventHandler); }, workQueue)) { lp.startListening(); // start listening for new files in the "new directory" driveNotifier.startListening(); // start listening for new thumb drives workQueue.process(); } } } catch (ApplicationException e) { Trace.TraceError("Caught application exception: " + e); MyConsole.WriteError("THE LOG PROCESSOR MUST EXIT.\nPress ENTER to quit."); Trace.Flush(); Console.ReadLine(); } }
private static void myCtrlCHandler(ConsoleCancelEventArgs ea, BlockingWorkQueue workQueue) { Trace.WriteLine(MODULE + "In CTRL-C handler."); ea.Cancel = true; workQueue.enque(null, null, (ox, ex) => { MyConsole.WriteWarning("CTRL-C received. Ok to quit (y/n)?"); String s = "" + (char)Console.Read(); if (s.ToUpperInvariant().IndexOf('Y') == 0) { workQueue.stopWaiting(); } }); }
// Write content to the file, overwriting if it exists. // This is a dangerous utility function, so we restrict it to writing paths that have PuzzleOracle as one of // the sub-dirs internal static void writeTextFile(string path, string content) { // This is a potentially dange if (path.IndexOf("\\PuzzleOracle\\") == -1) { MyConsole.WriteError("INTERNAL ERROR!"); throw new ApplicationException("We don't write random files!"); } using (TextWriter tr = new StreamWriter(path, false)) // false == do NOT append { tr.Write(content); tr.Close(); } }
private void recordSolve(LogEntry le) { // Record the fact that a particular team has solved a particular puzzle. // The way we do this currently is writing out a file <teamID>-<puzzleID>.txt (if it doesn't already exist) String content = String.Format("{0},{1}", le.transactionId, le.timestamp); String solveFile = resultsDir + "\\" + String.Format("{0}-{1}.txt", le.teamId, le.puzzleId); try { if (!File.Exists(solveFile)) { Utils.writeTextFile(solveFile, content); } } catch (IOException ex) { MyConsole.WriteError(String.Format("WARNING Could not write file [{0}]", solveFile)); } }
/// <summary> /// Check if the two (text) files have the same content. /// </summary> /// <param name="p"></param> /// <param name="destPath"></param> /// <returns></returns> internal static bool filesHaveSameContent(string f1, string f2) { bool match = false; // We don't attempt to be efficient - simply read the entire text and compare them! try { using (TextReader tr1 = new StreamReader(f1), tr2 = new StreamReader(f2)) { String allText1 = tr1.ReadToEnd(); String allText2 = tr2.ReadToEnd(); tr1.Close(); tr2.Close(); match = allText1.Equals(allText2); } } catch (IOException e) { MyConsole.WriteError(String.Format("IO Exception attempting to compare two files[{0}] and [{1}]: {2}", f2, f2, e)); } return(match); }
public static void createDirIfNeeded(String dir, Boolean critical) { try { // If directory do not exist, create it. if (!Directory.Exists(dir)) { MyConsole.WriteLine(String.Format("Creating directory [{0}].", dir)); Directory.CreateDirectory(dir); } } catch (IOException e) { String msg = String.Format("Error [{0}] attempting to create director [{1}]", e.ToString(), dir); MyConsole.WriteError(msg); if (critical) { Trace.WriteLine("Throwing application exception on critical error: " + msg); throw new ApplicationException(msg); } } }
private static bool initializeLogging(string baseWorkingDir) { // Check that the base directory exists... if (!Directory.Exists(baseWorkingDir)) { MyConsole.WriteError(String.Format("Working directory [{0}]\ndoes not exist.\nPlease create it and restart the log processor.", baseWorkingDir)); return(false); // ************ EARLY RETURN ************** } // Create a trace listener string debugLogPath = baseWorkingDir + "\\debuglog.txt"; Trace.Listeners.Add(new TextWriterTraceListener(debugLogPath)); Trace.WriteLine("Log Started"); Trace.Flush(); // Verify that the debug log file exists. if (!File.Exists(debugLogPath)) { Trace.TraceWarning(String.Format("Debug log [{0}] is not created.", debugLogPath)); return(false); // ************ EARLY RETURN ************** } return(true); }
public void newDriveHandler(object sender, EventArgs e) { NewDriveNotifierEventArgs nde = (NewDriveNotifierEventArgs)e; MyConsole.WriteLine(String.Format("Processing new drive [{0}].", nde.driveName)); }
public void logEventHandler(object sender, EventArgs ea) { LogEventArgs lea = (LogEventArgs)ea; MyConsole.WriteLine(String.Format("Processing [{0}] ({1} submission(s))", Path.GetFileName(lea.logPath), lea.entries.Length)); Boolean hadErrors = false; foreach (var le in lea.entries) { String s = String.Format("{0},{1},{2},{3},{4},{5},{6}", le.transactionId, le.timestamp, le.teamId, le.teamName, le.puzzleId, le.status, le.extraText ); String suffix = "(OK)"; if (!le.valid) { // TODO: Watch for invalid entries! Report these to the user. // Also, if there are any invalid entries, OR some other error // attempting to submit the entry to the database, // make a note here and do NOT move the file to the "processed" folder (see below) // Instead move the file to the "processed-with-errors" folder. suffix = String.Format("(INVALID - {0})", le.parseError); hadErrors = true; } else { this.processEntry(le); } MyConsole.WriteLine("\t" + le.rowIndex + ":" + s + suffix); } // // TODO: Actually process / commit the data. // If ALL entries have been successfully committed to the database, one can // move the file to the processed subdirectory, like so... // String processedDir = (hadErrors ? processedWithErrorsDir : this.processedDir); if (!Directory.Exists(processedDir)) { MyConsole.WriteError("ERROR: Processed dir does not exist: " + processedDir); } else { String destPath = processedDir + "\\" + Path.GetFileName(lea.logPath); try { if (File.Exists(destPath)) { Trace.WriteLine(MODULE + String.Format("WARNING: File with same name as\n[{0}]exists in the processed dir.", lea.logPath)); if (Utils.filesHaveSameContent(lea.logPath, destPath)) { Trace.WriteLine(MODULE + String.Format("Files have same content.")); File.Delete(lea.logPath); } else { MyConsole.WriteError(String.Format("\tFile with same name but DIFFERENT content exists in processed directory!")); throw new ArgumentException("Attempting to move file to processed dir when one with different content already exists."); } } else { File.Move(lea.logPath, destPath); Trace.WriteLine(MODULE + "Moved file to " + destPath); } } catch (Exception ex) { if (ex is IOException || ex is ArgumentException) { MyConsole.WriteError("\tERROR: Exception while moving path. ex=" + ex.Message); } else { throw ex; } } } }