2using System.Collections.Generic;
4using System.IO.Compression;
5using System.Security.Cryptography;
7using System.Threading.Tasks;
30 internal static Aes aes = GetCryptoProvider();
36 : base(
"/StartExport")
40 private static Aes GetCryptoProvider()
42 Aes Result = Aes.Create();
44 Result.BlockSize = 128;
46 Result.Mode = CipherMode.CBC;
47 Result.Padding = PaddingMode.None;
82 if (!RequestObj.TryGetValue(
"TypeOfFile", out
object Obj) || !(Obj is
string TypeOfFile))
85 if (!RequestObj.TryGetValue(
"Database", out Obj) || !(Obj is
bool Database))
88 if (!RequestObj.TryGetValue(
"Ledger", out Obj) || !(Obj is
bool Ledger))
91 if (!RequestObj.TryGetValue(
"WebContent", out Obj) || !(Obj is
bool WebContent))
94 if (!RequestObj.TryGetValue(
"OnlySelectedCollections", out Obj) || !(Obj is
bool OnlySelectedCollections))
97 if (!RequestObj.TryGetValue(
"selectedCollections", out Obj) || !(Obj is Array SelectedCollections))
100 if (!RequestObj.TryGetValue(
"exportOnly", out Obj) || !(Obj is
bool ExportOnly))
103 ExportInfo ExportInfo = await GetExporter(TypeOfFile, OnlySelectedCollections, SelectedCollections);
110 Response.StatusCode = 409;
111 Response.StatusMessage =
"Conflict";
113 T = Response.
Write(
"Export is underway.");
130 Export.ExportType = TypeOfFile;
132 Export.ExportLedger =
Ledger;
133 Export.ExportWebContent = WebContent;
136 List<string> Folders =
new List<string>();
140 if (RequestObj.TryGetValue(FolderCategory.CategoryId, out Obj) && Obj is
bool b)
146 Folders.AddRange(FolderCategory.Folders);
150 Task _ = DoExport(ExportInfo,
Database,
Ledger, WebContent, Folders.ToArray());
152 Response.StatusCode = 200;
154 await Response.
Write(ExportInfo.LocalBackupFileName);
162 private static bool exporting =
false;
163 private static readonly
object synchObject =
new object();
165 internal class ExportInfo
167 public string LocalBackupFileName;
168 public string LocalKeyFileName;
169 public string FullBackupFileName;
170 public string FullKeyFileName;
174 internal static async Task<ExportInfo> GetExporter(
string TypeOfFile,
bool OnlySelectedCollections, Array SelectedCollections)
176 ExportInfo Result =
new ExportInfo();
179 if (!Directory.Exists(BasePath))
180 Directory.CreateDirectory(BasePath);
182 BasePath += Path.DirectorySeparatorChar;
184 Result.FullBackupFileName = BasePath + DateTime.Now.ToString(
"yyyy-MM-dd HH_mm_ss");
189 Result.FullBackupFileName =
GetUniqueFileName(Result.FullBackupFileName,
".xml");
190 FileStream fs =
new FileStream(Result.FullBackupFileName, FileMode.Create, FileAccess.Write);
191 DateTime Created = File.GetCreationTime(Result.FullBackupFileName);
193 Settings.Async =
true;
194 XmlWriter XmlOutput = XmlWriter.Create(fs, Settings);
195 Result.LocalBackupFileName = Result.FullBackupFileName.Substring(BasePath.Length);
196 Result.Exporter =
new XmlExportFormat(Result.LocalBackupFileName, Created, XmlOutput, fs, OnlySelectedCollections, SelectedCollections);
200 Result.FullBackupFileName =
GetUniqueFileName(Result.FullBackupFileName,
".bin");
201 fs =
new FileStream(Result.FullBackupFileName, FileMode.Create, FileAccess.Write);
202 Created = File.GetCreationTime(Result.FullBackupFileName);
203 Result.LocalBackupFileName = Result.FullBackupFileName.Substring(BasePath.Length);
204 Result.Exporter =
new BinaryExportFormat(Result.LocalBackupFileName, Created, fs, fs, OnlySelectedCollections, SelectedCollections);
209 fs =
new FileStream(Result.FullBackupFileName, FileMode.Create, FileAccess.Write);
210 Created = File.GetCreationTime(Result.FullBackupFileName);
211 Result.LocalBackupFileName = Result.FullBackupFileName.Substring(BasePath.Length);
212 GZipStream gz =
new GZipStream(fs, CompressionLevel.Optimal,
false);
213 Result.Exporter =
new BinaryExportFormat(Result.LocalBackupFileName, Created, gz, fs, OnlySelectedCollections, SelectedCollections);
217 Result.FullBackupFileName =
GetUniqueFileName(Result.FullBackupFileName,
".bak");
218 fs =
new FileStream(Result.FullBackupFileName, FileMode.Create, FileAccess.Write);
219 Created = File.GetCreationTime(Result.FullBackupFileName);
220 Result.LocalBackupFileName = Result.FullBackupFileName.Substring(BasePath.Length);
225 ICryptoTransform AesTransform = aes.CreateEncryptor(Key, IV);
226 CryptoStream cs =
new CryptoStream(fs, AesTransform, CryptoStreamMode.Write);
228 gz =
new GZipStream(cs, CompressionLevel.Optimal,
false);
229 Result.Exporter =
new BinaryExportFormat(Result.LocalBackupFileName, Created, gz, fs, cs, 32, OnlySelectedCollections, SelectedCollections);
233 if (!Directory.Exists(BasePath2))
234 Directory.CreateDirectory(BasePath2);
236 BasePath2 += Path.DirectorySeparatorChar;
237 Result.LocalKeyFileName = Result.LocalBackupFileName.Replace(
".bak",
".key");
238 Result.FullKeyFileName = BasePath2 + Result.LocalKeyFileName;
240 using (XmlOutput = XmlWriter.Create(Result.FullKeyFileName,
XML.
WriterSettings(
true,
false)))
242 XmlOutput.WriteStartDocument();
244 XmlOutput.WriteAttributeString(
"key", Convert.ToBase64String(Key));
245 XmlOutput.WriteAttributeString(
"iv", Convert.ToBase64String(IV));
246 XmlOutput.WriteEndElement();
247 XmlOutput.WriteEndDocument();
254 using (fs = File.OpenRead(Result.FullKeyFileName))
265 Created = File.GetCreationTime(Result.FullKeyFileName);
271 throw new NotSupportedException(
"Unsupported file type.");
285 string Suffix =
string.Empty;
291 s = Base + Suffix + Extension;
296 Suffix =
" (" + i.ToString() +
")";
308 internal static async Task DoExport(ExportInfo ExportInfo,
bool Database,
bool Ledger,
bool WebContent,
string[] Folders)
316 List<KeyValuePair<string, object>> Tags =
new List<KeyValuePair<string, object>>()
318 new KeyValuePair<string, object>(
"Database",
Database),
319 new KeyValuePair<string, object>(
"Ledger",
Ledger)
322 foreach (
string Folder
in Folders)
323 Tags.Add(
new KeyValuePair<string, object>(Folder,
true));
325 Log.
Informational(
"Starting export.", ExportInfo.Exporter.FileName, Tags.ToArray());
327 await ExportInfo.Exporter.Start();
333 StringBuilder Temp =
new StringBuilder();
334 string[] RepairedCollections;
339 "Transforms",
"DbStatXmlToHtml.xslt"), Path.Combine(
Gateway.
RootFolder,
"Data"),
false,
true,
343 if (RepairedCollections.Length > 0)
345 string Xml = Temp.ToString();
346 string ReportFileName = Path.Combine(Path.GetDirectoryName(ExportInfo.FullBackupFileName),
347 "AutoRepair " + DateTime.Now.ToString(
"yyyy-MM-ddTHH.mm.ss.ffffff") +
".xml");
351 SortedDictionary<string, bool> CollectionsToExport =
new SortedDictionary<string, bool>();
353 if (ExportInfo.Exporter.CollectionNames is
null)
355 foreach (
string Collection
in await Persistence.Database.GetCollections())
356 CollectionsToExport[Collection] =
true;
360 foreach (
string Collection
in ExportInfo.Exporter.CollectionNames)
361 CollectionsToExport[Collection] =
true;
364 foreach (
string Collection
in Persistence.Database.GetExcludedCollections())
365 CollectionsToExport.Remove(Collection);
367 string[] ToExport =
new string[CollectionsToExport.Count];
368 CollectionsToExport.Keys.CopyTo(ToExport, 0);
370 await Persistence.Database.Export(ExportInfo.Exporter, ToExport,
380 CollectionNames = ExportInfo.Exporter.CollectionNames
383 await Persistence.Ledger.Export(ExportInfo.Exporter, Restricion,
387 if (WebContent || Folders.Length > 0)
391 await ExportInfo.Exporter.StartFiles();
400 if (File.Exists(ConfigFileName))
401 await ExportFile(ConfigFileName, ExportInfo.Exporter);
403 FileNames = Directory.GetFiles(
Gateway.
RootFolder,
"*.*", SearchOption.TopDirectoryOnly);
405 foreach (
string FileName
in FileNames)
406 await ExportFile(FileName, ExportInfo.Exporter);
410 foreach (
string Folder
in Directory.GetDirectories(
Gateway.
RootFolder,
"*.*", SearchOption.TopDirectoryOnly))
412 bool IsWebContent =
true;
416 foreach (
string Folder3
in FolderCategory.Folders)
418 if (
string.Compare(Folder3, Folder,
true) == 0)
420 IsWebContent =
false;
431 FileNames = Directory.GetFiles(Folder,
"*.*", SearchOption.AllDirectories);
433 foreach (
string FileName
in FileNames)
434 await ExportFile(FileName, ExportInfo.Exporter);
439 foreach (
string Folder
in Folders)
443 FileNames = Directory.GetFiles(Folder2,
"*.*", SearchOption.AllDirectories);
445 foreach (
string FileName
in FileNames)
446 await ExportFile(FileName, ExportInfo.Exporter);
452 await ExportInfo.Exporter.EndFiles();
456 Log.
Informational(
"Export successfully completed.", ExportInfo.Exporter.FileName);
474 await ExportInfo.Exporter.End();
475 ExportInfo.Exporter.Dispose();
492 await UploadBackupFile(ExportInfo.LocalBackupFileName, ExportInfo.FullBackupFileName,
false, Thread);
493 if (!
string.IsNullOrEmpty(ExportInfo.FullKeyFileName))
494 await UploadBackupFile(ExportInfo.LocalKeyFileName, ExportInfo.FullKeyFileName,
true, Thread);
513 private static async Task<bool> ExportFile(
string FileName,
IExportFormat Output)
515 using (FileStream fs = File.OpenRead(FileName))
527 private static Task UploadBackupFile(
string LocalFileName,
string FullFileName,
bool IsKey,
ProfilerThread Thread)
529 return UploadBackupFile(
new BackupInfo()
531 LocalFileName = LocalFileName,
532 FullFileName = FullFileName,
539 private class BackupInfo
541 public string LocalFileName;
542 public string FullFileName;
544 public bool Rescheduled;
545 public Dictionary<string, bool> Recipients =
null;
549 private static async Task UploadBackupFile(
object State)
551 BackupInfo BackupInfo = (BackupInfo)State;
552 bool Reschedule =
false;
557 if (!File.Exists(BackupInfo.FullFileName))
559 Log.
Warning(Msg =
"Backup file has been removed. Upload cancelled.", BackupInfo.LocalFileName);
561 if (BackupInfo.Rescheduled)
570 if (BackupInfo.Recipients is
null)
572 BackupInfo.Recipients =
new Dictionary<string, bool>();
576 if (BackupInfo.IsKey && !(Hosts is
null))
578 foreach (
string Host
in Hosts)
579 BackupInfo.Recipients[Host] =
false;
584 if (!BackupInfo.IsKey && !(Hosts is
null))
586 foreach (
string Host
in Hosts)
587 BackupInfo.Recipients[Host] =
false;
591 LinkedList<string> Recipients =
new LinkedList<string>();
594 foreach (KeyValuePair<string, bool> P
in BackupInfo.Recipients)
597 Recipients.AddLast(P.Key);
600 while (!((Recipient = Recipients.First?.Value) is
null))
602 Recipients.RemoveFirst();
604 if (Recipient.IndexOf(
'@') >= 0)
619 BackupInfo.Thread?.NewState(
"Discover_" + Recipient);
627 using (FileStream fs = File.OpenRead(BackupInfo.FullFileName))
629 BackupInfo.Thread?.NewState(
"Prepare_" + Recipient);
631 StringBuilder Xml =
new StringBuilder();
632 long FileSize = fs.Length;
634 Xml.Append(
"<prepare xmlns='http://waher.se/Schema/Backups.xsd' filename='");
635 Xml.Append(
XML.
Encode(BackupInfo.LocalFileName));
636 Xml.Append(
"' size='");
637 Xml.Append(FileSize.ToString());
638 Xml.Append(
"' content-type='application/octet-stream'/>");
640 BackupInfo.Thread?.NewState(
"Get_Slot_" + Recipient);
651 BackupInfo.Thread?.NewState(
"Upload_" + Recipient);
653 if (BackupInfo.IsKey)
654 Log.
Informational(
"Uploading key file to " + Recipient +
".", BackupInfo.LocalFileName);
656 Log.
Informational(
"Uploading backup file to " + Recipient +
".", BackupInfo.LocalFileName);
660 if (BackupInfo.IsKey)
661 Log.
Informational(
"Key file uploaded to " + Recipient +
".", BackupInfo.LocalFileName);
663 Log.
Informational(
"Backup file uploaded to " + Recipient +
".", BackupInfo.LocalFileName);
670 BackupInfo.Thread?.Exception(ex, BackupInfo.LocalFileName);
682 BackupInfo.Thread?.Exception(ex);
690 BackupInfo.Thread?.NewState(
"Reschedule");
691 BackupInfo.Rescheduled =
true;
695 else if (BackupInfo.Rescheduled)
697 await
Gateway.
SendNotification(
"Backup file has been successfully been uploaded. The initial attempt to upload the backup file failed, but a sequent rescheduled upload succeeded.");
698 BackupInfo.Rescheduled =
false;
701 BackupInfo.Thread =
null;
const string DefaultContentType
text/plain
Helps with parsing of commong data types.
static string JsonStringEncode(string s)
Encodes a string for inclusion in JSON.
Contains a markdown document. This markdown document class supports original markdown,...
static string Encode(string s)
Encodes all special characters in a string so that it can be included in a markdown document without ...
Static class managing loading of resources stored as embedded resources or in content files.
static Task WriteAllTextAsync(string FileName, string Text)
Creates a text file asynchronously.
Plain text encoder/decoder.
const string DefaultContentType
text/plain
Helps with common XML-related tasks.
static string Encode(string s)
Encodes a string for use in XML.
static XmlWriterSettings WriterSettings(bool Indent, bool OmitXmlDeclaration)
Gets an XML writer settings object.
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
The ClientEvents class allows applications to push information asynchronously to web clients connecte...
static string[] GetTabIDsForLocation(string Location)
Gets the Tab IDs of all tabs that display a particular resource.
static Task< int > PushEvent(string[] TabIDs, string Type, object Data)
Puses an event to a set of Tabs, given their Tab IDs.
Information about an exportable folder category
Static class managing data export.
static async Task< string[]> GetKeyHostsAsync()
Secondary key hosts.
static async Task< string > GetFullExportFolderAsync()
Full path to export folder.
static FolderCategory[] GetRegisteredFolders()
Gets registered exportable folders.
static async Task< string > GetFullKeyExportFolderAsync()
Full path to key folder.
static async Task< string[]> GetBackupHostsAsync()
Secondary backup hosts.
static async Task SetExportFolderAsync(string Value)
Export folder.
Static class managing the runtime environment of the IoT Gateway.
static IUser AssertUserAuthenticated(HttpRequest Request, string Privilege)
Makes sure a request is being made from a session with a successful user login.
static string ConfigFilePath
Full path to Gateway.config file.
static byte[] NextBytes(int NrBytes)
Generates an array of random bytes.
static string AppDataFolder
Application data folder.
static Task SendNotification(Graph Graph)
Sends a graph as a notification message to configured notification recipients.
static DateTime ScheduleEvent(ScheduledEventCallback Callback, DateTime When, object State)
Schedules a one-time event.
static XmppClient XmppClient
XMPP Client connection of gateway.
static string RootFolder
Web root folder.
async Task POST(HttpRequest Request, HttpResponse Response)
Executes the POST method on the resource.
StartExport()
Starts data export
static string GetUniqueFileName(string Base, string Extension)
Gets a unique filename.
override bool UserSessions
If the resource uses user sessions.
override bool HandlesSubPaths
If the resource handles sub-paths.
bool AllowsPOST
If the POST method is allowed.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
Represents an HTTP request.
bool HasData
If the request has data.
async Task< object > DecodeDataAsync()
Decodes data sent in request.
Represets a response of an HTTP client request.
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
async Task Write(byte[] Data)
Returns binary data in the response.
Base class for all synchronous HTTP resources. A synchronous resource responds within the method hand...
bool Ok
If the response is an OK result response (true), or an error response (false).
XmppException StanzaError
Any stanza error returned.
Class managing HTTP File uploads, as defined in XEP-0363.
Task DiscoverAsync()
Searches for HTTP File Upload support on the current broker.
bool HasSupport
If support has been found.
Task< HttpFileUploadEventArgs > RequestUploadSlotAsync(string FileName, string ContentType, long ContentSize)
Uploads a file to the upload component.
string FileUploadJid
JID of HTTP File Upload component.
Event arguments for HTTP File Upload callback methods.
async Task PUT(byte[] Content, string ContentType, int Timeout)
Uploads file content to the server.
Maintains information about an item in the roster.
bool HasLastPresence
If the roster item has received presence from an online resource having the given bare JID.
PresenceEventArgs LastPresence
Last presence received from a resource having this bare JID.
XmppState State
Current state of connection.
async Task< XmlElement > IqSetAsync(string To, string Xml)
Performs an asynchronous IQ Set request/response operation.
Base class of XMPP exceptions
XmppClient Client
XMPP Client.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Contains basic ledger export restrictions.
Static interface for ledger persistence. In order to work, a ledger provider has to be assigned to it...
static bool HasProvider
If a ledger provider is registered.
Simple ledger that records anything that happens in the database to XML files in the program data fol...
const string Namespace
http://waher.se/Schema/Export.xsd
Class that keeps track of events and timing.
void Stop()
Stops measuring time.
ProfilerThread CreateThread(string Name, ProfilerThreadType Type)
Creates a new profiler thread.
void NewState(string State)
Main Thread changes state.
void Exception(System.Exception Exception)
Event occurred on main thread
void Start()
Starts measuring time.
Class that keeps track of events and timing for one thread.
POST Interface for HTTP resources.
XmppState
State of XMPP connection.
ProfilerThreadType
Type of profiler thread.