Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ProgramDataFolder.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Threading.Tasks;
12using Waher.Things;
16
18{
23 {
24 private ProgramDataFolder parent;
25 private DirectoryInfo dirInfo;
26 private string folderName;
27 private string folderLocalName;
28 private DateTime? created;
29 private DateTime? updated;
30
35 : this(string.Empty, null, null, null)
36 {
37 }
38
46 public ProgramDataFolder(string FolderName, ProgramDataFolder Parent, DateTime? Created, DateTime? Updated)
47 {
48 this.folderName = FolderName;
49 this.parent = Parent;
50 this.created = Created;
51 this.updated = Updated;
52
53 if (string.IsNullOrEmpty(this.folderName))
54 {
55 this.dirInfo = null;
56 this.folderLocalName = null;
57 }
58 else
59 {
60 this.dirInfo = new DirectoryInfo(this.folderName);
61 this.folderLocalName = Path.GetFileName(this.folderName);
62 }
63 }
64
68 [Page(7, "File System", 100)]
69 [Header(8, "Folder:")]
70 [ToolTip(9, "Local path to folder.")]
71 [Required]
72 public string FolderLocalName
73 {
74 get => this.folderLocalName;
75 set
76 {
77 if (this.folderLocalName != value)
78 {
79 if (this.parent is null)
80 throw new Exception("You are not allowed to change the folder name.");
81
82 string FullPath = Path.Combine(this.parent.folderName, value);
83 if (!FullPath.StartsWith(this.parent.FolderName, StringComparison.CurrentCultureIgnoreCase))
84 throw new Exception("Invalid local folder name.");
85
86 if (!string.IsNullOrEmpty(this.folderName))
87 {
88 if (Directory.Exists(FullPath) || File.Exists(FullPath))
89 throw new Exception("Folder or file already exists.");
90
91 Directory.Move(this.folderName, FullPath);
92 }
93
94 this.folderLocalName = value;
95 this.folderName = FullPath;
96 this.dirInfo = new DirectoryInfo(FullPath);
97 }
98 }
99 }
100
104 [Page(7, "File System", 100)]
105 [Header(10, "Full Path:")]
106 [ToolTip(11, "Full path to folder.")]
107 [ReadOnly]
108 public string FolderName => this.folderName;
109
113 public string NodeId => this.folderName;
114
119
123 public string Partition => string.Empty;
124
128 public string LocalId => this.folderLocalName;
129
133 public string LogId => this.folderName;
134
139 public Task<string> GetTypeNameAsync(Language Language)
140 {
141 return Language.GetStringAsync(typeof(ProgramDataSource), 2, "Folder");
142 }
143
147 public bool HasChildren
148 {
149 get
150 {
151 if (this.dirInfo is null || !this.dirInfo.Exists)
152 return false;
153
154 DirectoryInfo[] Directories = this.dirInfo.GetDirectories();
155 if (Directories.Length > 0)
156 return true;
157
158 FileInfo[] Files = this.dirInfo.GetFiles();
159 if (Files.Length > 0)
160 return true;
161
162 return false;
163 }
164 }
165
169 public bool ChildrenOrdered => false;
170
174 public bool IsReadable => false; // TODO
175
179 public bool IsControllable => true;
180
184 public bool HasCommands => true;
185
189 public INode Parent => this.parent;
190
194 public DateTime LastChanged => File.GetLastWriteTimeUtc(this.folderName);
195
199 public NodeState State => NodeState.None;
200
204 public Task<IEnumerable<INode>> ChildNodes => Task.FromResult(ProgramDataSource.GetChildNodes(this, this.folderName));
205
211 public Task<bool> CanViewAsync(RequestOrigin Caller)
212 {
213 return XmppServerModule.IsAdmin(Caller.From);
214 }
215
221 public Task<bool> CanEditAsync(RequestOrigin Caller)
222 {
223 return XmppServerModule.IsAdmin(Caller.From);
224 }
225
231 public Task<bool> CanAddAsync(RequestOrigin Caller)
232 {
233 return XmppServerModule.IsAdmin(Caller.From);
234 }
235
241 public async Task<bool> CanDestroyAsync(RequestOrigin Caller)
242 {
243 if (this.parent is null)
244 return false;
245 else
246 return await XmppServerModule.IsAdmin(Caller.From);
247 }
248
249 internal void FolderUpdated()
250 {
251 this.created = null;
252 this.updated = null;
253 }
254
261 public async Task<IEnumerable<Parameter>> GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
262 {
263 LinkedList<Parameter> Parameters = new LinkedList<Parameter>();
264
265 if (this.created is null)
266 {
267 try
268 {
269 this.created = Directory.GetCreationTimeUtc(this.folderName);
270 }
271 catch (Exception)
272 {
273 // Ignore
274 }
275 }
276
277 if (this.updated is null)
278 {
279 try
280 {
281 this.updated = Directory.GetLastWriteTimeUtc(this.folderName);
282 }
283 catch (Exception)
284 {
285 // Ignore
286 }
287 }
288
289 if (this.created.HasValue)
290 {
291 Parameters.AddLast(new DateTimeParameter("Created", await Language.GetStringAsync(typeof(ProgramDataSource), 5, "Created"),
292 this.created.Value));
293
294 if (this.updated.HasValue && this.updated.Value > this.created.Value)
295 {
296 Parameters.AddLast(new DateTimeParameter("Updated", await Language.GetStringAsync(typeof(ProgramDataSource), 6, "Updated"),
297 this.updated.Value));
298 }
299 }
300
301 return Parameters;
302 }
303
308 public Task<IEnumerable<Message>> GetMessagesAsync(RequestOrigin Caller)
309 {
310 return Task.FromResult<IEnumerable<Message>>(null);
311 }
312
318 public Task<bool> MoveUpAsync(RequestOrigin Caller) => Task.FromResult(false);
319
325 public Task<bool> MoveDownAsync(RequestOrigin Caller) => Task.FromResult(false);
326
332 public Task<bool> AcceptsParentAsync(INode Parent)
333 {
334 if (Parent is null)
335 return Task.FromResult(true);
336
337 if (!(Parent is ProgramDataFolder ParentFolder))
338 return Task.FromResult(false);
339
340 if (this.parent is null && string.IsNullOrEmpty(this.folderName))
341 this.parent = ParentFolder;
342
343 return Task.FromResult(true);
344 }
345
351 public Task<bool> AcceptsChildAsync(INode Child)
352 {
353 return Task.FromResult(Child is ProgramDataFolder || Child is ProgramDataFile);
354 }
355
360 public Task AddAsync(INode Child)
361 {
362 if (Child is ProgramDataFolder ChildFolder)
363 {
364 if (string.IsNullOrEmpty(ChildFolder.FolderName))
365 throw new Exception("Folder name is empty.");
366
367 if (!ChildFolder.FolderName.StartsWith(this.folderName))
368 throw new Exception("Invalid parent folder.");
369
370 if (!Directory.Exists(ChildFolder.FolderName))
371 Directory.CreateDirectory(ChildFolder.FolderName);
372 }
373 else if (Child is ProgramDataFile ChildFile)
374 {
375 if (string.IsNullOrEmpty(ChildFile.FileName))
376 throw new Exception("File name is empty.");
377
378 if (!ChildFile.FileName.StartsWith(this.folderName))
379 throw new Exception("Invalid parent folder.");
380
381 if (!File.Exists(ChildFile.FileName))
382 {
383 FileStream fs = File.Create(ChildFile.FileName);
384 fs.Dispose();
385 }
386 }
387 else
388 throw new Exception("Unable to add child node.");
389
390 return Task.CompletedTask;
391 }
392
396 public Task UpdateAsync() => Task.CompletedTask;
397
403 public Task<bool> RemoveAsync(INode Child) => Task.FromResult(true);
404
408 public Task DestroyAsync()
409 {
410 if (this.parent is null)
411 throw new UnauthorizedAccessException("Folder is protected against deletion.");
412
413 if (Directory.Exists(this.folderName))
414 Directory.Delete(this.folderName, true);
415
416 return Task.CompletedTask;
417 }
418
422 public Task<IEnumerable<ICommand>> Commands
423 {
424 get
425 {
426 return Task.FromResult<IEnumerable<ICommand>>(new ICommand[]
427 {
428 new CreateFolderCommand(this, "0"),
429 new CreateTextFileCommand(this, PlainTextCodec.DefaultContentType, ".txt", 34, "Create Text File...", "CreateTextFile", "1"),
430 new CreateTextFileCommand(this, MarkdownCodec.ContentType, ".md", 40, "Create Markdown File...", "CreateMarkdownFile", "2"),
431 new CreateTextFileCommand(this, XmlCodec.DefaultContentType, ".xml", 35, "Create XML File...", "CreateXmlFile", "3"),
432 new CreateTextFileCommand(this, HtmlCodec.DefaultContentType, ".html", 36, "Create HTML File...", "CreateHtmlFile", "4"),
433 new CreateTextFileCommand(this, CssCodec.ContentType, ".css", 37, "Create CSS File...", "CreateCssFile", "5"),
434 new CreateTextFileCommand(this, "text/cssx", ".cssx", 41, "Create CSSX File...", "CreateCssxFile", "6"),
435 new CreateTextFileCommand(this, JavaScriptCodec.DefaultContentType, ".js", 38, "Create JavaScript File...", "CreateJsFile", "7"),
436 new CreateTextFileCommand(this, "application/x-webscript", ".ws", 39, "Create Webscript File...", "CreateWsFile", "8")
437 });
438 }
439 }
440
445 public async Task<ControlParameter[]> GetControlParameters()
446 {
447 List<ControlParameter> Parameters = new List<ControlParameter>();
448 DirectoryInfo Info = new DirectoryInfo(this.FolderName);
449 FileAttributes Attributes = Info.Attributes;
452 string Page = await Namespace.GetStringAsync(16, "Attributes");
453
454 Parameters.Add(new BooleanControlParameter("ReadOnly", Page,
455 await Namespace.GetStringAsync(17, "Read-only"),
456 await Namespace.GetStringAsync(25, "If folder is read-only."),
457 GetReadOnly, SetReadOnly));
458
459 Parameters.Add(new BooleanControlParameter("Hidden", Page,
460 await Namespace.GetStringAsync(19, "Hidden"),
461 await Namespace.GetStringAsync(26, "If folder is hidden."),
462 GetHidden, SetHidden));
463
464 Parameters.Add(new BooleanControlParameter("System", Page,
465 await Namespace.GetStringAsync(21, "System"),
466 await Namespace.GetStringAsync(27, "If folder is a system file."),
467 GetSystem, SetSystem));
468
469 Parameters.Add(new BooleanControlParameter("Archive", Page,
470 await Namespace.GetStringAsync(23, "Archive"),
471 await Namespace.GetStringAsync(28, "If folder is a candidate for backup or removal."),
472 GetArchive, SetArchive));
473
474 return Parameters.ToArray();
475 }
476
477 private static Task<bool?> GetReadOnly(IThingReference Node)
478 {
479 return GetAttribute(Node, FileAttributes.ReadOnly);
480 }
481
482 private static Task SetReadOnly(IThingReference Node, bool Value)
483 {
484 return SetAttribute(Node, Value, FileAttributes.ReadOnly);
485 }
486
487 private static Task<bool?> GetHidden(IThingReference Node)
488 {
489 return GetAttribute(Node, FileAttributes.Hidden);
490 }
491
492 private static Task SetHidden(IThingReference Node, bool Value)
493 {
494 return SetAttribute(Node, Value, FileAttributes.Hidden);
495 }
496
497 private static Task<bool?> GetSystem(IThingReference Node)
498 {
499 return GetAttribute(Node, FileAttributes.System);
500 }
501
502 private static Task SetSystem(IThingReference Node, bool Value)
503 {
504 return SetAttribute(Node, Value, FileAttributes.System);
505 }
506
507 private static Task<bool?> GetArchive(IThingReference Node)
508 {
509 return GetAttribute(Node, FileAttributes.Archive);
510 }
511
512 private static Task SetArchive(IThingReference Node, bool Value)
513 {
514 return SetAttribute(Node, Value, FileAttributes.Archive);
515 }
516
517 private static Task<bool?> GetAttribute(IThingReference Node, FileAttributes Attribute)
518 {
519 if (!(Node is ProgramDataFolder FolderNode))
520 return Task.FromResult<bool?>(null);
521
522 FileAttributes Attr = FolderNode.dirInfo.Attributes;
523
524 return Task.FromResult<bool?>(Attr.HasFlag(Attribute));
525 }
526
527 private static Task SetAttribute(IThingReference Node, bool Value, FileAttributes Attribute)
528 {
529 if (!(Node is ProgramDataFolder FolderNode))
530 throw new ArgumentException("Unexpected node type.", nameof(Node));
531
532 FileAttributes Attr = FolderNode.dirInfo.Attributes;
533 FileAttributes Bak = Attr;
534
535 if (Value)
536 Attr |= Attribute;
537 else
538 Attr &= ~Attribute;
539
540 if (Attr != Bak)
541 FolderNode.dirInfo.Attributes = Attr;
542
543 return Task.CompletedTask;
544 }
545
546 }
547}
CSS encoder/decoder.
Definition: CssCodec.cs:13
const string ContentType
Content-Type for CSS files.
Definition: CssCodec.cs:24
HTML encoder/decoder.
Definition: HtmlCodec.cs:13
const string DefaultContentType
Default Content-Type for HTML: text/html
Definition: HtmlCodec.cs:24
const string DefaultContentType
application/javascript
const string ContentType
Markdown content type.
Plain text encoder/decoder.
const string DefaultContentType
text/plain
XML encoder/decoder.
Definition: XmlCodec.cs:16
const string DefaultContentType
Default content type for XML documents.
Definition: XmlCodec.cs:27
Contains information about a language.
Definition: Language.cs:17
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
Definition: Language.cs:209
async Task< Namespace > GetNamespaceAsync(string Name)
Gets the namespace object, given its name, if available.
Definition: Language.cs:99
Contains information about a namespace in a language.
Definition: Namespace.cs:17
Task< LanguageString > GetStringAsync(int Id)
Gets the string object, given its ID, if available.
Definition: Namespace.cs:65
Basic access point for runtime language localization.
Definition: Translator.cs:16
static async Task< Language > GetDefaultLanguageAsync()
Gets the default language.
Definition: Translator.cs:223
Reference to a file in the ProgramData folder of the broker.
Reference to a folder in the ProgramData folder of the broker.
Task< bool > RemoveAsync(INode Child)
Removes a child from the node.
bool ChildrenOrdered
If the children of the node have an intrinsic order (true), or if the order is not important (false).
Task DestroyAsync()
Destroys the node. If it is a child to a parent node, it is removed from the parent first.
NodeState State
Current overall state of the node.
ProgramDataFolder()
Reference to a folder in the ProgramData folder of the broker.
ProgramDataFolder(string FolderName, ProgramDataFolder Parent, DateTime? Created, DateTime? Updated)
Reference to a folder in the ProgramData folder of the broker.
Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
string LogId
If provided, an ID for the node, as it would appear or be used in system logs. Can be null,...
string LocalId
If provided, an ID for the node, but unique locally between siblings. Can be null,...
async Task< IEnumerable< Parameter > > GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
bool HasCommands
If the node has registered commands or not.
async Task< ControlParameter[]> GetControlParameters()
Get control parameters for the actuator.
Task< bool > CanAddAsync(RequestOrigin Caller)
If the node can be added to by the caller.
Task< bool > CanViewAsync(RequestOrigin Caller)
If the node is visible to the caller.
string SourceId
Optional ID of source containing node.
Task AddAsync(INode Child)
Adds a new child to the node.
Task< bool > CanEditAsync(RequestOrigin Caller)
If the node can be edited by the caller.
Task< bool > MoveDownAsync(RequestOrigin Caller)
Tries to move the node down.
Task UpdateAsync()
Updates the node (in persisted storage).
Task< IEnumerable< Message > > GetMessagesAsync(RequestOrigin Caller)
Gets messages logged on the node.
string Partition
Optional partition in which the Node ID is unique.
Task< bool > AcceptsChildAsync(INode Child)
If the node accepts a presumptive child, i.e. can receive as a child (if that child accepts the node ...
Task< IEnumerable< INode > > ChildNodes
Child nodes. If no child nodes are available, null is returned.
Task< bool > AcceptsParentAsync(INode Parent)
If the node accepts a presumptive parent, i.e. can be added to that parent (if that parent accepts th...
Task< bool > MoveUpAsync(RequestOrigin Caller)
Tries to move the node up.
Task< IEnumerable< ICommand > > Commands
Available command objects. If no commands are available, null is returned.
async Task< bool > CanDestroyAsync(RequestOrigin Caller)
If the node can be destroyed to by the caller.
Data source mirroring the ProgramData folder for the broker.
static IEnumerable< INode > GetChildNodes(ProgramDataFolder FolderNode, string FolderPath)
Gets a set of program data child nodes, for a folder.
const string ProgramDataSourceID
Data Source ID for the ProgramData source.
Service Module hosting the XMPP broker and its components.
Tokens available in request.
Definition: RequestOrigin.cs:9
string From
Address of caller.
Interface for actuator nodes.
Definition: IActuator.cs:10
Interface for commands.
Definition: ICommand.cs:32
Interface for nodes that are published through the concentrator interface.
Definition: INode.cs:49
Interface for thing references.
NodeState
State of a node.
Definition: INode.cs:13