Adding StateMachine for Session serialization
- adding multiple classes and interfaces for Session Serialization and recovery after restart
This commit is contained in:
parent
8b9929198a
commit
0cdb8c3a1a
58
TelegramBotBase/Args/LoadStateEventArgs.cs
Normal file
58
TelegramBotBase/Args/LoadStateEventArgs.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Args
|
||||||
|
{
|
||||||
|
public class LoadStateEventArgs
|
||||||
|
{
|
||||||
|
public Dictionary<String,object> Values { get; set; }
|
||||||
|
|
||||||
|
public LoadStateEventArgs()
|
||||||
|
{
|
||||||
|
Values = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> Keys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Values.Keys.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String Get(String key)
|
||||||
|
{
|
||||||
|
return Values[key].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetInt(String key)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
if (int.TryParse(Values[key].ToString(), out i))
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GetDouble(String key)
|
||||||
|
{
|
||||||
|
double d = 0;
|
||||||
|
if (double.TryParse(Values[key].ToString(), out d))
|
||||||
|
return d;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetBool(String key)
|
||||||
|
{
|
||||||
|
bool b = false;
|
||||||
|
if (bool.TryParse(Values[key].ToString(), out b))
|
||||||
|
return b;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
37
TelegramBotBase/Args/SaveStateEventArgs.cs
Normal file
37
TelegramBotBase/Args/SaveStateEventArgs.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Args
|
||||||
|
{
|
||||||
|
public class SaveStateEventArgs
|
||||||
|
{
|
||||||
|
public Dictionary<String, object> Values { get; set; }
|
||||||
|
|
||||||
|
public SaveStateEventArgs()
|
||||||
|
{
|
||||||
|
Values = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(String key, String value)
|
||||||
|
{
|
||||||
|
Values[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetInt(String key, int value)
|
||||||
|
{
|
||||||
|
Values[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBool(String key, bool value)
|
||||||
|
{
|
||||||
|
Values[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDouble(String key, double value)
|
||||||
|
{
|
||||||
|
Values[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
20
TelegramBotBase/Args/SaveStatesEventArgs.cs
Normal file
20
TelegramBotBase/Args/SaveStatesEventArgs.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Sessions;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Args
|
||||||
|
{
|
||||||
|
public class SaveStatesEventArgs
|
||||||
|
{
|
||||||
|
public StateContainer States { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public SaveStatesEventArgs(StateContainer states)
|
||||||
|
{
|
||||||
|
this.States = states;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
TelegramBotBase/Attributes/SaveState.cs
Normal file
15
TelegramBotBase/Attributes/SaveState.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Attributes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Declares that the field or property should be save and recovered an restart.
|
||||||
|
/// </summary>
|
||||||
|
public class SaveState : Attribute
|
||||||
|
{
|
||||||
|
public String Key { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
34
TelegramBotBase/Base/StateContainer.cs
Normal file
34
TelegramBotBase/Base/StateContainer.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Base
|
||||||
|
{
|
||||||
|
public partial class StateContainer
|
||||||
|
{
|
||||||
|
public List<StateEntry> States { get; set; }
|
||||||
|
|
||||||
|
public List<long> ChatIds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return States.Where(a => a.DeviceId > 0).Select(a => a.DeviceId).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<long> GroupIds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return States.Where(a => a.DeviceId < 0).Select(a => a.DeviceId).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateContainer()
|
||||||
|
{
|
||||||
|
this.States = new List<StateEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
44
TelegramBotBase/Base/StateEntry.cs
Normal file
44
TelegramBotBase/Base/StateEntry.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Base
|
||||||
|
{
|
||||||
|
|
||||||
|
[DebuggerDisplay("Device: {DeviceId}, {FormUri}")]
|
||||||
|
public class StateEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the DeviceId of the entry.
|
||||||
|
/// </summary>
|
||||||
|
public long DeviceId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the Username (on privat chats) or Group title on groups/channels.
|
||||||
|
/// </summary>
|
||||||
|
public String ChatTitle { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains additional values to save.
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<String, object> Values { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the full qualified namespace of the form to used for reload it via reflection.
|
||||||
|
/// </summary>
|
||||||
|
public String FormUri {get;set;}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the assembly, where to find that form.
|
||||||
|
/// </summary>
|
||||||
|
public String QualifiedName { get; set; }
|
||||||
|
|
||||||
|
public StateEntry()
|
||||||
|
{
|
||||||
|
this.Values = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -63,6 +63,10 @@ namespace TelegramBotBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool LogAllMessages { get; set; } = false;
|
public bool LogAllMessages { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable the SessionState (you need to implement on call forms the IStateForm interface)
|
||||||
|
/// </summary>
|
||||||
|
public IStateMachine StateMachine { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How often could a form navigate to another (within one user action/call/message)
|
/// How often could a form navigate to another (within one user action/call/message)
|
||||||
@ -169,6 +173,10 @@ namespace TelegramBotBase
|
|||||||
this.Client.MessageEdit += Client_MessageEdit;
|
this.Client.MessageEdit += Client_MessageEdit;
|
||||||
this.Client.Action += Client_Action;
|
this.Client.Action += Client_Action;
|
||||||
|
|
||||||
|
if (this.StateMachine != null)
|
||||||
|
{
|
||||||
|
LoadSessionStates();
|
||||||
|
}
|
||||||
|
|
||||||
this.Client.TelegramClient.StartReceiving();
|
this.Client.TelegramClient.StartReceiving();
|
||||||
}
|
}
|
||||||
@ -186,6 +194,11 @@ namespace TelegramBotBase
|
|||||||
this.Client.Action -= Client_Action;
|
this.Client.Action -= Client_Action;
|
||||||
|
|
||||||
this.Client.TelegramClient.StopReceiving();
|
this.Client.TelegramClient.StopReceiving();
|
||||||
|
|
||||||
|
if (this.StateMachine != null)
|
||||||
|
{
|
||||||
|
SaveSessionStates();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -461,6 +474,145 @@ namespace TelegramBotBase
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the previously saved states from the machine.
|
||||||
|
/// </summary>
|
||||||
|
private async void LoadSessionStates()
|
||||||
|
{
|
||||||
|
if (this.StateMachine == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("StateMachine", "No StateMachine defined. Please set one to property BotBase.StateMachine");
|
||||||
|
}
|
||||||
|
|
||||||
|
var container = this.StateMachine.LoadFormStates();
|
||||||
|
|
||||||
|
foreach (var s in container.States)
|
||||||
|
{
|
||||||
|
Type t = Type.GetType(s.QualifiedName);
|
||||||
|
if (t == null || !t.IsSubclassOf(typeof(FormBase)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var form = t.GetConstructor(new Type[] { }).Invoke(new object[] { }) as FormBase;
|
||||||
|
|
||||||
|
if (s.Values != null && s.Values.Count > 0)
|
||||||
|
{
|
||||||
|
var properties = s.Values.Where(a => a.Key.StartsWith("$"));
|
||||||
|
var fields = form.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||||
|
|
||||||
|
foreach (var p in properties)
|
||||||
|
{
|
||||||
|
var f = fields.FirstOrDefault(a => a.Name == p.Key.Substring(1));
|
||||||
|
if (f == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
f.SetValue(form, p.Value);
|
||||||
|
}
|
||||||
|
catch (ArgumentException ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Is Subclass of IStateForm
|
||||||
|
var iform = form as IStateForm;
|
||||||
|
if (iform != null)
|
||||||
|
{
|
||||||
|
var ls = new LoadStateEventArgs();
|
||||||
|
ls.Values = s.Values;
|
||||||
|
iform.LoadState(ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.Client = Client;
|
||||||
|
var device = new DeviceSession(s.DeviceId, form);
|
||||||
|
|
||||||
|
device.ChatTitle = s.ChatTitle;
|
||||||
|
|
||||||
|
this.Sessions.SessionList.Add(s.DeviceId, device);
|
||||||
|
|
||||||
|
await form.OnInit(new InitEventArgs());
|
||||||
|
|
||||||
|
await form.OnOpened(new EventArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves all open states into the machine.
|
||||||
|
/// </summary>
|
||||||
|
private void SaveSessionStates()
|
||||||
|
{
|
||||||
|
if (this.StateMachine == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("StateMachine", "No StateMachine defined. Please set one to property BotBase.StateMachine");
|
||||||
|
}
|
||||||
|
|
||||||
|
var states = new List<StateEntry>();
|
||||||
|
|
||||||
|
foreach (var s in Sessions.SessionList)
|
||||||
|
{
|
||||||
|
if (s.Value == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var form = s.Value.ActiveForm;
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var se = new StateEntry();
|
||||||
|
se.DeviceId = s.Key;
|
||||||
|
se.ChatTitle = s.Value.ChatTitle;
|
||||||
|
se.FormUri = form.GetType().FullName;
|
||||||
|
se.QualifiedName = form.GetType().AssemblyQualifiedName;
|
||||||
|
|
||||||
|
//Is Subclass of IStateForm
|
||||||
|
var iform = form as IStateForm;
|
||||||
|
if (iform != null)
|
||||||
|
{
|
||||||
|
//Loading Session states
|
||||||
|
SaveStateEventArgs ssea = new SaveStateEventArgs();
|
||||||
|
iform.SaveState(ssea);
|
||||||
|
|
||||||
|
se.Values = ssea.Values;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Search for public properties with SaveState attribute
|
||||||
|
var fields = form.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).Where(a => a.GetCustomAttributes(typeof(SaveState), true).Length != 0).ToList();
|
||||||
|
|
||||||
|
foreach (var f in fields)
|
||||||
|
{
|
||||||
|
var val = f.GetValue(form);
|
||||||
|
|
||||||
|
se.Values.Add("$" + f.Name, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
states.Add(se);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//Continue on error (skip this form)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sc = new StateContainer();
|
||||||
|
sc.States = states;
|
||||||
|
|
||||||
|
this.StateMachine.SaveFormStates(new SaveStatesEventArgs(sc));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Will be called if a session/context gets started
|
/// Will be called if a session/context gets started
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
20
TelegramBotBase/Interfaces/IStateForm.cs
Normal file
20
TelegramBotBase/Interfaces/IStateForm.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Base;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Is used to save specific fields into a session state to survive restarts or unhandled exceptions and crashes.
|
||||||
|
/// </summary>
|
||||||
|
public interface IStateForm
|
||||||
|
{
|
||||||
|
|
||||||
|
void LoadState(LoadStateEventArgs e);
|
||||||
|
|
||||||
|
void SaveState(SaveStateEventArgs e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
15
TelegramBotBase/Interfaces/IStateMachine.cs
Normal file
15
TelegramBotBase/Interfaces/IStateMachine.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Base;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.Interfaces
|
||||||
|
{
|
||||||
|
public interface IStateMachine
|
||||||
|
{
|
||||||
|
void SaveFormStates(SaveStatesEventArgs e);
|
||||||
|
|
||||||
|
StateContainer LoadFormStates();
|
||||||
|
}
|
||||||
|
}
|
||||||
83
TelegramBotBase/States/JSONStateMachine.cs
Normal file
83
TelegramBotBase/States/JSONStateMachine.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization.Formatters;
|
||||||
|
using System.Text;
|
||||||
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Interfaces;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.States
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Is used for all complex data types. Use if other default machines are not working.
|
||||||
|
/// </summary>
|
||||||
|
public class JSONStateMachine : IStateMachine
|
||||||
|
{
|
||||||
|
public String FilePath { get; set; }
|
||||||
|
|
||||||
|
public bool Overwrite { get; set; }
|
||||||
|
|
||||||
|
public JSONStateMachine(String file, bool overwrite = true)
|
||||||
|
{
|
||||||
|
if (file is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.FilePath = file;
|
||||||
|
this.Overwrite = overwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateContainer LoadFormStates()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = System.IO.File.ReadAllText(FilePath);
|
||||||
|
|
||||||
|
var sc = Newtonsoft.Json.JsonConvert.DeserializeObject<StateContainer>(content, new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
TypeNameHandling = TypeNameHandling.All,
|
||||||
|
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
|
||||||
|
}) as StateContainer;
|
||||||
|
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StateContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveFormStates(SaveStatesEventArgs e)
|
||||||
|
{
|
||||||
|
if (System.IO.File.Exists(FilePath))
|
||||||
|
{
|
||||||
|
if (!this.Overwrite)
|
||||||
|
{
|
||||||
|
throw new Exception("File exists already.");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.IO.File.Delete(FilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = Newtonsoft.Json.JsonConvert.SerializeObject(e.States, Formatting.Indented, new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
TypeNameHandling = TypeNameHandling.All,
|
||||||
|
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
|
||||||
|
});
|
||||||
|
|
||||||
|
System.IO.File.WriteAllText(FilePath, content);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
75
TelegramBotBase/States/SimpleJSONStateMachine.cs
Normal file
75
TelegramBotBase/States/SimpleJSONStateMachine.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization.Formatters;
|
||||||
|
using System.Text;
|
||||||
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Interfaces;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.States
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Is used for simple object structures like classes, lists or basic datatypes without generics and other compiler based data types.
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleJSONStateMachine : IStateMachine
|
||||||
|
{
|
||||||
|
public String FilePath { get; set; }
|
||||||
|
|
||||||
|
public bool Overwrite { get; set; }
|
||||||
|
|
||||||
|
public SimpleJSONStateMachine(String file, bool overwrite = true)
|
||||||
|
{
|
||||||
|
if (file is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.FilePath = file;
|
||||||
|
this.Overwrite = overwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateContainer LoadFormStates()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = System.IO.File.ReadAllText(FilePath);
|
||||||
|
|
||||||
|
var sc = Newtonsoft.Json.JsonConvert.DeserializeObject<StateContainer>(content) as StateContainer;
|
||||||
|
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StateContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveFormStates(SaveStatesEventArgs e)
|
||||||
|
{
|
||||||
|
if (System.IO.File.Exists(FilePath))
|
||||||
|
{
|
||||||
|
if (!this.Overwrite)
|
||||||
|
{
|
||||||
|
throw new Exception("File exists already.");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.IO.File.Delete(FilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = Newtonsoft.Json.JsonConvert.SerializeObject(e.States, Formatting.Indented);
|
||||||
|
|
||||||
|
System.IO.File.WriteAllText(FilePath, content);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
88
TelegramBotBase/States/XMLStateMachine.cs
Normal file
88
TelegramBotBase/States/XMLStateMachine.cs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using TelegramBotBase.Args;
|
||||||
|
using TelegramBotBase.Base;
|
||||||
|
using TelegramBotBase.Interfaces;
|
||||||
|
|
||||||
|
namespace TelegramBotBase.States
|
||||||
|
{
|
||||||
|
public class XMLStateMachine : IStateMachine
|
||||||
|
{
|
||||||
|
public String FilePath { get; set; }
|
||||||
|
|
||||||
|
public bool Overwrite { get; set; }
|
||||||
|
|
||||||
|
public XMLStateMachine(String file, bool overwrite = true)
|
||||||
|
{
|
||||||
|
if (file is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.FilePath = file;
|
||||||
|
this.Overwrite = overwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateContainer LoadFormStates()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DataContractSerializer serializer = new DataContractSerializer(typeof(StateContainer));
|
||||||
|
|
||||||
|
using (var reader = new StreamReader(FilePath))
|
||||||
|
{
|
||||||
|
using (var xml = new XmlTextReader(reader))
|
||||||
|
{
|
||||||
|
StateContainer sc = serializer.ReadObject(xml) as StateContainer;
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StateContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveFormStates(SaveStatesEventArgs e)
|
||||||
|
{
|
||||||
|
if (System.IO.File.Exists(FilePath))
|
||||||
|
{
|
||||||
|
if (!this.Overwrite)
|
||||||
|
{
|
||||||
|
throw new Exception("File exists already.");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.IO.File.Delete(FilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DataContractSerializer serializer = new DataContractSerializer(typeof(StateContainer));
|
||||||
|
|
||||||
|
using (var sw = new StreamWriter(this.FilePath))
|
||||||
|
{
|
||||||
|
using (var writer = new XmlTextWriter(sw))
|
||||||
|
{
|
||||||
|
writer.Formatting = Formatting.Indented; // indent the Xml so it’s human readable
|
||||||
|
serializer.WriteObject(writer, e.States);
|
||||||
|
writer.Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user