Added automatic save and restoration of RunnerManager sessions

This commit is contained in:
ruri
2020-03-23 03:59:55 +01:00
10 changed files with 159 additions and 49 deletions
+13 -2
View File
@@ -36,6 +36,7 @@ namespace OpenBullet
private int snowBuffer = 0;
public RunnerManager RunnerManagerPage { get; set; }
// TODO: Do not create a different View for each RunnerInstance, but instead just replace the vm!
public Runner CurrentRunnerPage { get; set; }
public ProxyManager ProxyManagerPage { get; set; }
public WordlistManager WordlistManagerPage { get; set; }
@@ -196,9 +197,15 @@ namespace OpenBullet
OB.HitsDB = new HitsDBViewModel();
// Views
RunnerManagerPage = new RunnerManager(OB.OBSettings.General.AutoCreateRunner);
if (OB.OBSettings.General.AutoCreateRunner)
RunnerManagerPage = new RunnerManager();
// If we create first runner and there was no session to restore
if (OB.OBSettings.General.AutoCreateRunner & !OB.RunnerManager.RestoreSession())
{
var firstRunner = OB.RunnerManager.Create();
CurrentRunnerPage = OB.RunnerManager.RunnersCollection.FirstOrDefault().View;
}
OB.Logger.LogInfo(Components.Main, "Initialized RunnerManager");
ProxyManagerPage = new ProxyManager();
OB.Logger.LogInfo(Components.Main, "Initialized ProxyManager");
@@ -410,6 +417,10 @@ namespace OpenBullet
"Confirmation", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.No)
return false;
}
OB.Logger.LogInfo(Components.Main, "Saving RunnerManager session to the database");
OB.RunnerManager.SaveSession();
OB.Logger.LogInfo(Components.Main, "Quit sequence initiated");
return true;
}
@@ -1,22 +1,32 @@
using OpenBullet.Views.Main.Runner;
using OpenBullet.Repositories;
using OpenBullet.Views.Main.Runner;
using RuriLib.Interfaces;
using RuriLib.Models;
using RuriLib.Runner;
using RuriLib.ViewModels;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
namespace OpenBullet.ViewModels
{
public class RunnerManagerViewModel : ViewModelBase, IRunnerManager
{
private LiteDBRepository<RunnerSessionData> _repo;
public ObservableCollection<RunnerInstance> RunnersCollection { get; set; } = new ObservableCollection<RunnerInstance>();
public IEnumerable<IRunner> Runners => RunnersCollection.Select(i => i.ViewModel);
private Random rand = new Random();
public RunnerManagerViewModel()
{
_repo = new LiteDBRepository<RunnerSessionData>(OB.dataBaseFile, "runners");
}
public RunnerInstance Get(int id)
{
return RunnersCollection.Where(r => r.Id == id).First();
@@ -25,6 +35,8 @@ namespace OpenBullet.ViewModels
public IRunner Create()
{
var instance = new RunnerInstance(rand.Next());
instance.ViewModel.ConfigChanged += OnRunnerSessionChanged;
instance.ViewModel.WordlistChanged += OnRunnerSessionChanged;
RunnersCollection.Add(instance);
return instance.ViewModel;
}
@@ -43,10 +55,74 @@ namespace OpenBullet.ViewModels
{
RunnersCollection.Clear();
}
public void OnRunnerSessionChanged(IRunnerMessaging obj)
{
SaveSession();
}
public void SaveSession()
{
_repo.RemoveAll();
_repo.Add(RunnersCollection
.Select(r => r.ViewModel)
.Select(r => new RunnerSessionData()
{
Bots = r.BotsAmount,
Config = r.Config != null ? r.ConfigName : "",
Wordlist = r.Wordlist != null ? r.Wordlist.Path : "",
ProxyMode = r.ProxyMode
}
));
}
// Returns true if a session was found
public bool RestoreSession()
{
var runners = _repo.Get().ToArray();
if (runners.Length == 0) return false;
foreach (var r in runners)
{
try
{
var instance = Create();
instance.BotsAmount = r.Bots;
instance.ProxyMode = r.ProxyMode;
var configVM = OB.ConfigManager.Configs.FirstOrDefault(c => c.Name == r.Config)
?? throw new Exception($"The Config {r.Config} was not found in the ConfigManager");
instance.SetConfig(configVM.Config, false);
// Try to get the Wordlist from the Manager
var wordlist = OB.WordlistManager.Wordlists.FirstOrDefault(w => w.Path == r.Wordlist);
// If not found, try to get it from disk
if (wordlist == null)
{
if (!File.Exists(r.Wordlist))
throw new Exception($"The Wordlist {r.Wordlist} was not found in the WordlistManager or on Disk");
wordlist = WordlistManagerViewModel.FileToWordlist(r.Wordlist);
}
instance.SetWordlist(wordlist);
}
catch (Exception ex)
{
OB.Logger.LogError(Components.RunnerManager, ex.Message);
}
}
return true;
}
}
public class RunnerInstance
{
// TODO: Remove the View from here! It shouldn't be here and nothing should reference this View!
public Runner View { get; private set; }
public RunnerViewModel ViewModel { get; private set; }
@@ -34,6 +34,7 @@ namespace OpenBullet.ViewModels
{
_repo = new LiteDBRepository<Wordlist>(OB.dataBaseFile, "wordlists");
WordlistsCollection = new ObservableCollection<Wordlist>();
RefreshList();
}
public Wordlist GetWordlistByName(string name)
@@ -41,6 +42,20 @@ namespace OpenBullet.ViewModels
return WordlistsCollection.Where(x => x.Name == name).First();
}
public static Wordlist FileToWordlist(string path)
{
// Build the wordlist object
var wordlist = new Wordlist(Path.GetFileNameWithoutExtension(path), path, OB.Settings.Environment.WordlistTypes.First().Name, "");
// Get the first line
var first = File.ReadLines(wordlist.Path).First();
// Set the correct wordlist type
wordlist.Type = OB.Settings.Environment.RecognizeWordlistType(first);
return wordlist;
}
#region CRUD Operations
// Create
public void Add(Wordlist wordlist)
@@ -1,4 +1,5 @@
using OpenBullet.Views.Main.Runner;
using OpenBullet.ViewModels;
using OpenBullet.Views.Main.Runner;
using OpenBullet.Views.UserControls;
using RuriLib.Models;
using System.ComponentModel;
@@ -80,17 +81,8 @@ namespace OpenBullet
ofd.ShowDialog();
try
{
// Build the wordlist object
var wordlist = new Wordlist(Path.GetFileNameWithoutExtension(ofd.FileName), ofd.FileName, OB.Settings.Environment.WordlistTypes.First().Name, "");
// Get the first line
var first = File.ReadLines(wordlist.Path).First();
// Set the correct wordlist type
wordlist.Type = OB.Settings.Environment.RecognizeWordlistType(first);
// Add the wordlist to the runner
((Runner)Caller).SetWordlist(wordlist);
((Runner)Caller).SetWordlist(WordlistManagerViewModel.FileToWordlist(ofd.FileName));
((MainDialog)Parent).Close();
}
-5
View File
@@ -14,11 +14,6 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock x:Name="helpMessageLabel" Grid.Row="0" Grid.RowSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="25" FontWeight="Bold" Foreground="{DynamicResource ForegroundMain}" TextAlignment="Center" >
Welcome to Open Bullet!<LineBreak/>
Create a Runner to get started.
</TextBlock>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Button x:Name="addRunnerButton" Click="addRunnerButton_Click">
<StackPanel Orientation="Horizontal">
+1 -7
View File
@@ -24,24 +24,18 @@ namespace OpenBullet.Views.Main
StartRunner?.Invoke(this, EventArgs.Empty);
}
public RunnerManager(bool createFirst)
public RunnerManager()
{
vm = OB.RunnerManager;
DataContext = vm;
InitializeComponent();
if (createFirst)
{
addRunnerButton_Click(this, null);
}
}
#region Buttons
private void addRunnerButton_Click(object sender, RoutedEventArgs e)
{
vm.Create();
helpMessageLabel.Visibility = Visibility.Collapsed;
}
private void removeRunnerButton_Click(object sender, RoutedEventArgs e)
@@ -29,8 +29,6 @@ namespace OpenBullet.Views.Main
DataContext = vm;
InitializeComponent();
vm.RefreshList();
}
public void AddWordlist(Wordlist wordlist)
+23
View File
@@ -0,0 +1,23 @@
using RuriLib.Runner;
using System;
namespace RuriLib.Models
{
/// <summary>
/// Contains the essential information of a Runner Session.
/// </summary>
public class RunnerSessionData : Persistable<Guid>
{
/// <summary>The name of the selected Config.</summary>
public string Config { get; set; } = "";
/// <summary>The name of the selected Wordlist.</summary>
public string Wordlist { get; set; } = "";
/// <summary>The amount of bots selected.</summary>
public int Bots { get; set; } = 1;
/// <summary>The proxy mode selected.</summary>
public ProxyMode ProxyMode { get; set; } = ProxyMode.Default;
}
}
+26 -21
View File
@@ -35,6 +35,7 @@ namespace RuriLib.Runner
/// <summary>
/// Main class that handles all the multi-threaded checking of a Wordlist given a Config.
/// </summary>
// TODO: Split this into partial classes
public class RunnerViewModel : ViewModelBase, IRunnerMessaging, IRunner
{
#region Constructor
@@ -349,6 +350,7 @@ namespace RuriLib.Runner
Config = config;
if (setRecommended) BotsAmount = Clamp(config.Settings.SuggestedBots, 1, 200);
OnPropertyChanged("ConfigName");
RaiseConfigChanged();
}
/// <summary>
@@ -360,6 +362,7 @@ namespace RuriLib.Runner
Wordlist = wordlist;
OnPropertyChanged("WordlistName");
OnPropertyChanged("WordlistSize");
RaiseWordlistChanged();
}
#endregion
@@ -1052,41 +1055,33 @@ namespace RuriLib.Runner
#endregion
#region Events
/// <summary>
/// Fired when a new message needs to be logged.
/// </summary>
/// <summary>Fired when a new message needs to be logged.</summary>
public event Action<IRunnerMessaging, LogLevel, string, bool, int> MessageArrived;
/// <summary>
/// Fired when the Master Worker status changed.
/// </summary>
/// <summary>Fired when the Master Worker status changed.</summary>
public event Action<IRunnerMessaging> WorkerStatusChanged;
/// <summary>
/// Fired when a Hit was found.
/// </summary>
/// <summary>Fired when a Hit was found.</summary>
public event Action<IRunnerMessaging, Hit> FoundHit;
/// <summary>
/// Fired when proxies need to be reloaded.
/// </summary>
/// <summary>Fired when proxies need to be reloaded.</summary>
public event Action<IRunnerMessaging> ReloadProxies;
/// <summary>
/// Fired when an Action could change the UI and needs to be dispatched to another thread (usually it's handled by the UI thread).
/// </summary>
/// <summary>/// Fired when an Action could change the UI and needs to be dispatched to another thread (usually it's handled by the UI thread).</summary>
public event Action<IRunnerMessaging, Action> DispatchAction;
/// <summary>
/// Fired when the progress record needs to be saved to the Database.
/// </summary>
/// <summary>Fired when the progress record needs to be saved to the Database.</summary>
public event Action<IRunnerMessaging> SaveProgress;
/// <summary>
/// Fired when custom inputs from the user are required.
/// </summary>
/// <summary>Fired when custom inputs from the user are required.</summary>
public event Action<IRunnerMessaging> AskCustomInputs;
/// <summary>Fired when the currently selected Config changed.</summary>
public event Action<IRunnerMessaging> ConfigChanged;
/// <summary>Fired when the currently selected Wordlist changed.</summary>
public event Action<IRunnerMessaging> WordlistChanged;
private void RaiseMessageArrived(LogLevel level, string message, bool prompt = false, int timeout = 0)
{
MessageArrived?.Invoke(this, level, message, prompt, timeout);
@@ -1122,6 +1117,16 @@ namespace RuriLib.Runner
{
AskCustomInputs?.Invoke(this);
}
private void RaiseConfigChanged()
{
ConfigChanged?.Invoke(this);
}
private void RaiseWordlistChanged()
{
WordlistChanged?.Invoke(this);
}
#endregion
#region Proxy Management Methods
+1
View File
@@ -285,6 +285,7 @@
<Compile Include="Models\DataPool.cs" />
<Compile Include="Models\Persistable.cs" />
<Compile Include="Models\ProxyResult.cs" />
<Compile Include="Models\RunnerSessionData.cs" />
<Compile Include="Models\Stats\ProxyManagerStats.cs" />
<Compile Include="Models\ProxyPool.cs" />
<Compile Include="Models\RemoteProxySource.cs" />