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;
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 Task.FromResult(Caller.HasPrivilege("Source." + ProgramDataSource.SourceID + ".Node.View"));
214 }
215
221 public Task<bool> CanEditAsync(RequestOrigin Caller)
222 {
223 return Task.FromResult(Caller.HasPrivilege("Source." + ProgramDataSource.SourceID + ".Node.Edit"));
224 }
225
231 public Task<bool> CanAddAsync(RequestOrigin Caller)
232 {
233 return Task.FromResult(Caller.HasPrivilege("Source." + ProgramDataSource.SourceID + ".Node.Add"));
234 }
235
241 public Task<bool> CanDestroyAsync(RequestOrigin Caller)
242 {
243 if (this.parent is null)
244 return Task.FromResult(false);
245 else
246 return Task.FromResult(Caller.HasPrivilege("Source." + ProgramDataSource.SourceID + ".Node.Destroy"));
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(
354 Child is ProgramDataFolder ||
355 Child is ProgramDataFile);
356 }
357
362 public Task AddAsync(INode Child)
363 {
364 if (Child is ProgramDataFolder ChildFolder)
365 {
366 if (string.IsNullOrEmpty(ChildFolder.FolderName))
367 throw new Exception("Folder name is empty.");
368
369 if (!ChildFolder.FolderName.StartsWith(this.folderName))
370 throw new Exception("Invalid parent folder.");
371
372 if (!Directory.Exists(ChildFolder.FolderName))
373 Directory.CreateDirectory(ChildFolder.FolderName);
374 }
375 else if (Child is ProgramDataFile ChildFile)
376 {
377 if (string.IsNullOrEmpty(ChildFile.FileName))
378 throw new Exception("File name is empty.");
379
380 if (!ChildFile.FileName.StartsWith(this.folderName))
381 throw new Exception("Invalid parent folder.");
382
383 if (!File.Exists(ChildFile.FileName))
384 {
385 FileStream fs = File.Create(ChildFile.FileName);
386 fs.Dispose();
387 }
388 }
389 else
390 throw new Exception("Unable to add child node.");
391
392 return Task.CompletedTask;
393 }
394
398 public Task UpdateAsync() => Task.CompletedTask;
399
405 public Task<bool> RemoveAsync(INode Child) => Task.FromResult(true);
406
410 public Task DestroyAsync()
411 {
412 if (this.parent is null)
413 throw new UnauthorizedAccessException("Folder is protected against deletion.");
414
415 if (Directory.Exists(this.folderName))
416 Directory.Delete(this.folderName, true);
417
418 return Task.CompletedTask;
419 }
420
424 public Task<IEnumerable<ICommand>> Commands
425 {
426 get
427 {
428 return Task.FromResult<IEnumerable<ICommand>>(new ICommand[]
429 {
430 new CreateFolderCommand(this, "0"),
431 new CreateTextFileCommand(this, PlainTextCodec.DefaultContentType, ".txt", 34, "Create Text File...", "CreateTextFile", "1"),
432 new CreateTextFileCommand(this, MarkdownCodec.ContentType, ".md", 40, "Create Markdown File...", "CreateMarkdownFile", "2"),
433 new CreateTextFileCommand(this, XmlCodec.DefaultContentType, ".xml", 35, "Create XML File...", "CreateXmlFile", "3"),
434 new CreateTextFileCommand(this, HtmlCodec.DefaultContentType, ".html", 36, "Create HTML File...", "CreateHtmlFile", "4"),
435 new CreateTextFileCommand(this, CssCodec.DefaultContentType, ".css", 37, "Create CSS File...", "CreateCssFile", "5"),
436 new CreateTextFileCommand(this, "text/cssx", ".cssx", 41, "Create CSSX File...", "CreateCssxFile", "6"),
437 new CreateTextFileCommand(this, JavaScriptCodec.DefaultContentType, ".js", 38, "Create JavaScript File...", "CreateJsFile", "7"),
438 new CreateTextFileCommand(this, "application/x-webscript", ".ws", 39, "Create Webscript File...", "CreateWsFile", "8")
439 });
440 }
441 }
442
447 public async Task<ControlParameter[]> GetControlParameters()
448 {
449 List<ControlParameter> Parameters = new List<ControlParameter>();
450 DirectoryInfo Info = new DirectoryInfo(this.FolderName);
451 FileAttributes Attributes = Info.Attributes;
454 string Page = await Namespace.GetStringAsync(16, "Attributes");
455
456 Parameters.Add(new BooleanControlParameter("ReadOnly", Page,
457 await Namespace.GetStringAsync(17, "Read-only"),
458 await Namespace.GetStringAsync(25, "If folder is read-only."),
459 GetReadOnly, SetReadOnly));
460
461 Parameters.Add(new BooleanControlParameter("Hidden", Page,
462 await Namespace.GetStringAsync(19, "Hidden"),
463 await Namespace.GetStringAsync(26, "If folder is hidden."),
464 GetHidden, SetHidden));
465
466 Parameters.Add(new BooleanControlParameter("System", Page,
467 await Namespace.GetStringAsync(21, "System"),
468 await Namespace.GetStringAsync(27, "If folder is a system file."),
469 GetSystem, SetSystem));
470
471 Parameters.Add(new BooleanControlParameter("Archive", Page,
472 await Namespace.GetStringAsync(23, "Archive"),
473 await Namespace.GetStringAsync(28, "If folder is a candidate for backup or removal."),
474 GetArchive, SetArchive));
475
476 return Parameters.ToArray();
477 }
478
479 private static Task<bool?> GetReadOnly(IThingReference Node)
480 {
481 return GetAttribute(Node, FileAttributes.ReadOnly);
482 }
483
484 private static Task SetReadOnly(IThingReference Node, bool Value)
485 {
486 return SetAttribute(Node, Value, FileAttributes.ReadOnly);
487 }
488
489 private static Task<bool?> GetHidden(IThingReference Node)
490 {
491 return GetAttribute(Node, FileAttributes.Hidden);
492 }
493
494 private static Task SetHidden(IThingReference Node, bool Value)
495 {
496 return SetAttribute(Node, Value, FileAttributes.Hidden);
497 }
498
499 private static Task<bool?> GetSystem(IThingReference Node)
500 {
501 return GetAttribute(Node, FileAttributes.System);
502 }
503
504 private static Task SetSystem(IThingReference Node, bool Value)
505 {
506 return SetAttribute(Node, Value, FileAttributes.System);
507 }
508
509 private static Task<bool?> GetArchive(IThingReference Node)
510 {
511 return GetAttribute(Node, FileAttributes.Archive);
512 }
513
514 private static Task SetArchive(IThingReference Node, bool Value)
515 {
516 return SetAttribute(Node, Value, FileAttributes.Archive);
517 }
518
519 private static Task<bool?> GetAttribute(IThingReference Node, FileAttributes Attribute)
520 {
521 if (!(Node is ProgramDataFolder FolderNode))
522 return Task.FromResult<bool?>(null);
523
524 FileAttributes Attr = FolderNode.dirInfo.Attributes;
525
526 return Task.FromResult<bool?>(Attr.HasFlag(Attribute));
527 }
528
529 private static Task SetAttribute(IThingReference Node, bool Value, FileAttributes Attribute)
530 {
531 if (!(Node is ProgramDataFolder FolderNode))
532 throw new ArgumentException("Unexpected node type.", nameof(Node));
533
534 FileAttributes Attr = FolderNode.dirInfo.Attributes;
535 FileAttributes Bak = Attr;
536
537 if (Value)
538 Attr |= Attribute;
539 else
540 Attr &= ~Attribute;
541
542 if (Attr != Bak)
543 FolderNode.dirInfo.Attributes = Attr;
544
545 return Task.CompletedTask;
546 }
547
548 }
549}
CSS encoder/decoder.
Definition: CssCodec.cs:14
const string DefaultContentType
Content-Type for CSS files.
Definition: CssCodec.cs:25
HTML encoder/decoder.
Definition: HtmlCodec.cs:15
const string DefaultContentType
Default Content-Type for HTML: text/html
Definition: HtmlCodec.cs:26
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:19
const string DefaultContentType
Default content type for XML documents.
Definition: XmlCodec.cs:30
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.
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 SourceID
Data Source ID for the ProgramData source.
Tokens available in request.
Definition: RequestOrigin.cs:9
bool HasPrivilege(string Privilege)
If the origin has a given privilege.
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