public RylobotModel(Robot robot) { m_sym_cache = new Cache <string, Symbol> { ThreadSafe = true, Mode = CacheMode.StandardCache }; Robot = robot; var settings_filepath = Util.ResolveAppDataPath("Rylogic", "Rylobot", "Settings.xml"); Settings = new Settings(settings_filepath) { AutoSaveOnChanges = true }; // Ensure the instrument settings directory exists if (!Path_.DirExists(Settings.General.InstrumentSettingsDir)) { Directory.CreateDirectory(Settings.General.InstrumentSettingsDir); } // Create the account Acct = new Account(this, Robot.Account); // Create the instrument Instrument = new Instrument(this); // Create a strategy Strategy = new StrategyPotLuck(this); // ToDo: // Restore SnR levels + other indicators }
public History(MainModel model) { Model = model; // Ensure the acct data cache directory exists if (!Path_.DirExists(Model.Settings.General.AcctDataCacheDir)) { Directory.CreateDirectory(Model.Settings.General.AcctDataCacheDir); } }
/// <summary>Write this string to a file</summary> public static void ToFile(this string str, string filepath, bool append = false, bool create_dir_if_necessary = true) { // Ensure the directory exists var dir = Path_.Directory(filepath); if (create_dir_if_necessary && !Path_.DirExists(dir)) { Directory.CreateDirectory(dir); } using (var f = new StreamWriter(new FileStream(filepath, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.ReadWrite))) f.Write(str); }
protected override void OnContentRendered(EventArgs e) { base.OnContentRendered(e); // On first time startup, display the settings before creating the data directory if (!Path_.DirExists(Settings.Instance.DataPath)) { ShowSettings.Execute(); // Ensure the data directory exists Path_.CreateDirs(Settings.Instance.DataPath); } // Apply settings Settings.Instance.NotifySettingChanged(nameof(Settings.Origin)); Settings.Instance.NotifySettingChanged(nameof(Settings.Destination)); }
/// <summary>Write an ldr string to a file</summary> public static void Write(string ldr_str, string filepath, bool append = false) { try { // Ensure the directory exists var dir = Path_.Directory(filepath); if (!Path_.DirExists(dir)) { Directory.CreateDirectory(dir); } // Lock, then write the file using (Path_.LockFile(filepath)) using (var f = new StreamWriter(new FileStream(filepath, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.Read))) f.Write(ldr_str); } catch (Exception ex) { Debug.WriteLine($"Failed to write Ldr script to '{filepath}'. {ex.Message}"); } }
// Market data contains a set of 'Instruments' (currency pairs). // Each pair has a separate database containing tables of candles for // each time frame public MarketData(MainModel model) { Model = model; Instruments = new BindingSource <Instrument> { DataSource = new BindingListEx <Instrument>(), PerItemClear = true }; // Ensure the price data cache directory exists if (!Path_.DirExists(Model.Settings.General.PriceDataCacheDir)) { Directory.CreateDirectory(Model.Settings.General.PriceDataCacheDir); } // Add instruments for the price data we know about const string price_data_file_pattern = @"PriceData_(\w+)\.db"; foreach (var fd in Path_.EnumFileSystem(Model.Settings.General.PriceDataCacheDir, regex_filter:price_data_file_pattern)) { var sym = fd.FileName.SubstringRegex(price_data_file_pattern, RegexOptions.IgnoreCase)[0]; GetOrCreateInstrument(sym); } }
/// <summary>Load and parse the startup options</summary> public StartupOptions(string[] args) { var exe_dir = Util.ResolveAppPath(); if (!Directory.Exists(exe_dir)) { throw new ArgumentException("Cannot determine the current executable directory"); } // Check the command line options for (int i = 0, iend = args.Length; i != iend; ++i) { var arg = args[i].ToLowerInvariant(); // No option character implies the file to load if (arg[0] != '-' && arg[0] != '/') { if (FileToLoad != null) { throw new ArgumentException("Command line should specify a single file path only. If the file path contains white space, remember to use quotes. e.g. RyLogViewer \"my file.txt\""); } FileToLoad = arg; continue; } // Helper for comparing option strings bool IsOption(string opt) => string.CompareOrdinal(arg, 0, opt, 0, opt.Length) == 0; // (order these by longest option first) if (IsOption(CmdLineOption.RDelim)) { RowDelim = arg.Substring(CmdLineOption.RDelim.Length); } else if (IsOption(CmdLineOption.CDelim)) { ColDelim = arg.Substring(CmdLineOption.CDelim.Length); } else if (IsOption(CmdLineOption.NoGUI)) { NoGUI = true; } else if (IsOption(CmdLineOption.Silent)) { Silent = true; } else if (IsOption(CmdLineOption.PatternSet)) { PatternSetFilepath = arg.Substring(CmdLineOption.PatternSet.Length); } else if (IsOption(CmdLineOption.SettingsPath)) { SettingsPath = arg.Substring(CmdLineOption.SettingsPath.Length); } else if (IsOption(CmdLineOption.LogFilePath)) { LogFilePath = arg.Substring(CmdLineOption.LogFilePath.Length); } else if (IsOption(CmdLineOption.Export)) { ExportPath = arg.Substring(CmdLineOption.Export.Length); } else if (IsOption(CmdLineOption.Portable)) { PortableMode = true; } else if (IsOption(CmdLineOption.ShowHelp)) { ShowHelp = true; } else if (IsOption(CmdLineOption.ShowHelp2)) { ShowHelp = true; } else { throw new ArgumentException("Unknown command line option '" + arg + "'."); } } // Determine whether to run the app in portable mode PortableMode |= Path_.FileExists(Path.Combine(exe_dir, "portable")); // Set the UserDataDir based on whether we're running in portable mode or not UserDataDir = Path.GetFullPath(PortableMode ? exe_dir : Util.ResolveUserDocumentsPath(Application.CompanyName, Application.ProductName)); // If we're in portable mode, check that we have write access to the local directory if (PortableMode) { if (!Path_.DirExists(UserDataDir) || (new DirectoryInfo(UserDataDir).Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { throw new IOException("Unable to run in portable mode as the directory ('" + UserDataDir + "') is readonly."); } } // If not in portable mode, check the UserDataDir directory exists (or can be created) else { if (!Path_.DirExists(UserDataDir)) { Directory.CreateDirectory(UserDataDir); } } // If the export option is given, a 'FileToLoad' must also be given if (ExportPath != null && FileToLoad == null) { throw new ArgumentException("A file to export must be given if the '-e' option is used"); } // If a settings path has not been given, use the defaults if (SettingsPath == null) { SettingsPath = Path.Combine(UserDataDir, "settings.xml"); } // Set the licence file path LicenceFilepath = PortableMode ? Path.Combine(exe_dir, "licence.xml") : Path.Combine(UserDataDir, "licence.xml"); // If no licence file exists, create the free one if (!Path_.FileExists(LicenceFilepath)) { new Licence().WriteLicenceFile(LicenceFilepath); } }
// Notes: // - Parsed command line options public StartupOptions(string[] args) { FilesToLoad = new List <string>(); SettingsPath = null !; var exe_dir = Util.ResolveAppPath(); if (!Path_.DirExists(exe_dir)) { throw new ArgumentException("Cannot determine the current executable directory"); } // Check the command line options for (int i = 0, iend = args.Length; i != iend; ++i) { var arg = args[i].ToLowerInvariant(); // No option character implies the file to load if (arg[0] != '-' && arg[0] != '/') { FilesToLoad.Add(arg); continue; } // Helper for comparing option strings bool IsOption(string opt) => string.CompareOrdinal(arg, 0, opt, 0, opt.Length) == 0; // (order these by longest option first) if (IsOption(CmdLine.SettingsPath)) { SettingsPath = arg.Substring(CmdLine.SettingsPath.Length); } else if (IsOption(CmdLine.Portable)) { PortableMode = true; } else if (IsOption(CmdLine.ShowHelp)) { ShowHelp = true; } else if (IsOption(CmdLine.ShowHelp2)) { ShowHelp = true; } else { throw new ArgumentException($"Unknown command line option '{arg}'."); } } // Determine whether to run the app in portable mode PortableMode |= Path_.FileExists(Path_.CombinePath(exe_dir, "portable")); // Set the UserDataDir based on whether we're running in portable mode or not UserDataDir = Path.GetFullPath(PortableMode ? Path_.CombinePath(exe_dir, "UserData") : Util.ResolveUserDocumentsPath("Rylogic", "LDraw")); Path_.CreateDirs(UserDataDir); // Check that we have write access to the user data directory if (!Path_.DirExists(UserDataDir) || (new DirectoryInfo(UserDataDir).Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { throw new IOException($"The user data directory ('{UserDataDir}') is readonly."); } // If a settings path has not been given, use the defaults SettingsPath ??= Path_.CombinePath(UserDataDir, "settings2.xml"); }
/// <summary>Watch for settings changes</summary> private async void HandleSettingChange(object sender, SettingChangeEventArgs e) { if (e.Before) { return; } Log.Write(ELogLevel.Debug, $"Setting {e.Key} changed to {e.Value}"); switch (e.Key) { case nameof(Settings.JournalFilesDir): { // Enable the journal file monitor if the ED journal path is set m_journal_monitor.Run = Path_.DirExists(Settings.Instance.JournalFilesDir); break; } case nameof(Settings.Origin): { // If a origin station is selected but the current system id is // still null, set it to the system that owns the station. if (Settings.Instance.Origin.StationID != null && Settings.Instance.Origin.StarSystemID == null) { var station = Src.GetStation(Settings.Instance.Origin.StationID.Value).Result; Settings.Instance.Origin = new LocationID(station.SystemID, station.ID); } InvalidateTradeRoutes(); break; } case nameof(Settings.Destination): { // If a destination station is selected but the current system id is // still null, set it to the system that owns the station. if (Settings.Instance.Destination.StationID != null && Settings.Instance.Destination.StarSystemID == null) { var station = Src.GetStation(Settings.Instance.Destination.StationID.Value).Result; Settings.Instance.Destination = new LocationID(station.SystemID, station.ID); } InvalidateTradeRoutes(); break; } case nameof(Settings.UseCurrentLocation): { if (Settings.Instance.UseCurrentLocation) { await SetLocationFromJournal(); } InvalidateTradeRoutes(); break; } case nameof(Settings.ReadCargoCapacityFromLoadout): { if (Settings.Instance.ReadCargoCapacityFromLoadout && JournalMonitor.CargoCapacity != null) { Settings.Instance.CargoCapacity = JournalMonitor.CargoCapacity.Value; } InvalidateTradeRoutes(); break; } case nameof(Settings.ReadMaxJumpRangeFromLoadout): { if (Settings.Instance.ReadMaxJumpRangeFromLoadout && JournalMonitor.MaxJumpRange != null) { Settings.Instance.MaxJumpRange = JournalMonitor.MaxJumpRange.Value; } InvalidateTradeRoutes(); break; } } }
/// <summary> /// Smart copy from 'src' to 'dst'. Loosely like XCopy. /// 'src' can be a single file, a comma separated list of files, or a directory<para/> /// 'dst' can be a /// if 'src' is a directory, </summary> public static void Copy(string src, string dst, bool overwrite = false, bool only_if_modified = false, bool ignore_non_existing = false, Action <string>?feedback = null, bool show_unchanged = false) { var src_is_dir = Path_.IsDirectory(src); var dst_is_dir = Path_.IsDirectory(dst) || dst.EndsWith("/") || dst.EndsWith("\\") || src_is_dir; // Find the names of the source files to copy var files = new List <string>(); if (src_is_dir) { files = Path_.EnumFileSystem(src, SearchOption.AllDirectories).Select(x => x.FullName).ToList(); } else if (Path_.FileExists(src)) { files = new List <string>() { src } } ; else if (src.Contains('*') || src.Contains('?')) { files = Path_.EnumFileSystem(src, SearchOption.AllDirectories, new Pattern(EPattern.Wildcard, src).RegexString).Select(x => x.FullName).ToList(); } else if (!ignore_non_existing) { throw new FileNotFoundException($"'{src}' does not exist"); } // If the 'src' represents multiple files, 'dst' must be a directory if (src_is_dir || files.Count > 1) { // if 'dst' doesn't exist, assume it's a directory if (!Path_.DirExists(dst)) { dst_is_dir = true; } // or if it does exist, check that it is actually a directory else if (!dst_is_dir) { throw new FileNotFoundException($"'{dst}' is not a valid directory"); } } // Ensure that 'dstdir' exists. (Canonicalise fixes the case where 'dst' is a drive, e.g. 'C:\') var dstdir = Path_.Canonicalise((dst_is_dir ? dst : Path_.Directory(dst)).TrimEnd('/', '\\')); if (!Path_.DirExists(dstdir)) { Directory.CreateDirectory(dstdir); } // Copy the file(s) to 'dst' foreach (var srcfile in files) { // If 'dst' is a directory, use the same filename from 'srcfile' var dstfile = string.Empty; if (dst_is_dir) { var spath = src_is_dir ? Path_.RelativePath(src, srcfile) : Path_.FileName(srcfile); dstfile = Path_.CombinePath(dstdir, spath); } else { dstfile = dst; } // If 'srcfile' is a directory, ensure the directory exists at the destination if (Path_.IsDirectory(srcfile)) { if (!dst_is_dir) { throw new Exception($"ERROR: {dst} is not a directory"); } // Create the directory at the destination if (!Path_.DirExists(dstfile)) { System.IO.Directory.CreateDirectory(dstfile); } if (feedback != null) { feedback(srcfile + " --> " + dstfile); } } else { // Copy if modified or always based on the flag if (only_if_modified && !Path_.DiffContent(srcfile, dstfile)) { if (feedback != null && show_unchanged) { feedback(srcfile + " --> unchanged"); } continue; } // Ensure the directory path exists var d = Path_.Directory(dstfile); var f = Path_.FileName(dstfile); if (!Path_.DirExists(d)) { System.IO.Directory.CreateDirectory(d); } if (feedback != null) { feedback(srcfile + " --> " + dstfile); } File.Copy(srcfile, dstfile, overwrite); } } }
public static IEnumerable <FileData> EnumFileSystem(string path, SearchOption search_flags = SearchOption.TopDirectoryOnly, string?regex_filter = null, RegexOptions regex_options = RegexOptions.IgnoreCase, FileAttributes exclude = FileAttributes.Hidden, Func <string, bool>?progress = null) { /// <remarks> /// A fast enumerator of files in a directory. /// Use this if you need to get attributes for all files in a directory. /// This enumerator is substantially faster than using <see cref="Directory.GetFiles(string)"/> /// and then creating a new FileInfo object for each path. Use this version when you /// will need to look at the attributes of each file returned (for example, you need /// to check each file in a directory to see if it was modified after a specific date). /// </remarks> Debug.Assert(Path_.DirExists(path), "Attempting to enumerate an invalid directory path"); // Default progress callback if (progress == null) { progress = s => true; } // File/Directory name filter var filter = regex_filter != null ? new Regex(regex_filter, regex_options) : null; // For drive letters, add a \, 'FileIOPermission' needs it if (path.EndsWith(":")) { path += "\\"; } // Local stack for recursion var stack = new Stack <string>(20); for (stack.Push(path); stack.Count != 0;) { // Report progress var dir = stack.Pop(); if (!progress(dir)) { break; } // Skip paths we don't have access to try { new FileIOPermission(FileIOPermissionAccess.PathDiscovery, dir).Demand(); } catch { continue; } // Use the win32 find files var pattern = Path.Combine(dir, "*"); var find_data = new Win32.WIN32_FIND_DATA(); using (var handle = FindFirstFile(pattern, ref find_data)) { for (var more = !handle.IsInvalid; more; more = FindNextFile(handle, ref find_data)) { // Exclude files with any of the exclude attributes if ((find_data.Attributes & exclude) != 0) { continue; } // Filter if provided if (find_data.FileName != "." && find_data.FileName != "..") { Match m; if (filter == null) { yield return(new FileData(dir, ref find_data)); } else if ((m = filter.Match(find_data.FileName)).Success) { yield return(new FileData(dir, ref find_data, m)); } } // If the found object is a directory, see if we should be recursing if (search_flags == SearchOption.AllDirectories && (find_data.Attributes & FileAttributes.Directory) == FileAttributes.Directory) { if (find_data.FileName == "." || find_data.FileName == "..") { continue; } stack.Push(Path.Combine(dir, find_data.FileName)); } } } } }
/// <summary> /// Delete a directory and all contained files/subdirectories. /// Returns true if successful and not interrupted</summary> public static bool DelTree(string root, EDelTreeOpts opts, Func <string, EAbortIgnoreRetry> prompt, int timeout_ms = 1000) { prompt = prompt ?? (_ => EAbortIgnoreRetry.Abort); for (;;) { try { // Generate a list of all contained files var files = Directory.GetFiles(root, "*", SearchOption.AllDirectories); if (files.Length != 0) { if (!opts.HasFlag(EDelTreeOpts.FilesOnly) && !opts.HasFlag(EDelTreeOpts.EvenIfNotEmpty)) { throw new IOException($"Cannot delete {root}, directory still contains {files.Length} files"); } // Check for processes holding locks on the files for (;;) { // Find the lock holding processes/services var lockers = FileLockHolders(files); if (!lockers.Any()) { break; } // Prompt the user, Abort, Retry or Ignore var r = prompt( $"The following processes hold locks on files within {root}:\r\n" + $"\t{string.Join("\r\n\t", lockers.Select(x => x.ProcessName))}"); if (r == EAbortIgnoreRetry.Abort) { return(false); } if (r == EAbortIgnoreRetry.Ignore) { break; } } // Delete the contained files if (opts.HasFlag(EDelTreeOpts.FilesOnly) || opts.HasFlag(EDelTreeOpts.EvenIfNotEmpty)) { foreach (var file in files) { if (Path_.FileExists(file)) { File.Delete(file); } } } } // Try to delete the root directory. This can fail because the file system // doesn't necessarily update as soon as the files are deleted. Try to delete, // if that fails, wait a bit, then try again. If that fails, defer to the user. const int Attempts = 3; for (int retries = Attempts; retries-- != 0;) { try { if (opts.HasFlag(EDelTreeOpts.DeleteRoot)) { Directory.Delete(root, true); } else { // Delete the contained directories var dirs = System.IO.Directory.GetDirectories(root, "*", SearchOption.TopDirectoryOnly); foreach (var dir in dirs) { if (Path_.DirExists(dir)) { Directory.Delete(dir, true); } } } return(true); } catch (IOException) { if (retries == 0) { throw; } Thread.Sleep(Math.Max(100, timeout_ms / Attempts)); } } } catch (Exception ex) { var r = prompt( $"Failed to delete directory '{root}'\r\n" + $"{ex.Message}\r\n"); if (r == EAbortIgnoreRetry.Abort) { return(false); } if (r == EAbortIgnoreRetry.Ignore) { return(true); } } } }
/// <summary>Search for duplicate files using the command line parameters</summary> private int RunCmdline() { try { // Build a map of the files in 'm_dst_dir' Console.WriteLine("Building a map of existing files"); var existing = BuildMap(m_dst_dir, m_regex_ignore); // Get the files that might be duplicates Console.WriteLine("Building a map of potentially duplicate files"); var newfiles = BuildMap(m_src_dir, null); // Ensure the duplicates directory exists if (m_mv_dir != null) { if (!Path_.DirExists(m_mv_dir)) { Directory.CreateDirectory(m_mv_dir); } } // Create the file that contains the duplicates list var lst = (m_lst != null) ? new StreamWriter(m_lst) : null; Console.WriteLine("Finding Duplicates"); foreach (var finfo in newfiles) { if (existing.TryGetValue(finfo.Key, out var original)) { if (m_show_dups) { Console.WriteLine($"{finfo.Value.FullName} is a duplicate of {original.FullName}"); } if (lst != null) { lst.WriteLine(finfo.Value.FullName); } if (m_mv_dir != null) { var dstfile = Path.Combine(m_mv_dir, finfo.Value.Name); if (File.Exists(dstfile)) { File.Delete(dstfile); } File.Move(finfo.Value.FullName, dstfile); } } } if (lst != null) { lst.Dispose(); } return(0); } catch (Exception ex) { Console.WriteLine("Error: " + ex.Message); return(-1); } }