Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ProgramDataFile.cs
1using System;
3using System.IO;
4using System.Threading.Tasks;
5using Waher.Content;
10using Waher.Things;
14
16{
21 {
22 private ProgramDataFolder parent;
23 private string fileName;
24 private string fileLocalName;
25 private DateTime? created;
26 private DateTime? updated;
27 private long? size;
28
33 : this(string.Empty, null, null, null, null)
34 {
35 }
36
42 public ProgramDataFile(string FileName, ProgramDataFolder Parent, DateTime? Created, DateTime? Updated, long? Size)
43 {
44 this.fileName = FileName;
45 this.parent = Parent;
46 this.created = Created;
47 this.updated = Updated;
48 this.size = Size;
49
50 if (string.IsNullOrEmpty(this.fileName))
51 this.fileLocalName = null;
52 else
53 this.fileLocalName = Path.GetFileName(this.fileName);
54 }
55
56 [Page(7, "File System", 100)]
57 [Header(12, "File Name:")]
58 [ToolTip(13, "Local file name.")]
59 [Required]
60 public string FileLocalName
61 {
62 get => this.fileLocalName;
63 set
64 {
65 if (this.fileLocalName != value)
66 {
67 if (this.parent is null)
68 throw new Exception("You are not allowed to change the file name.");
69
70 string FullPath = Path.Combine(this.parent.FolderName, value);
71 if (!FullPath.StartsWith(this.parent.FolderName, StringComparison.CurrentCultureIgnoreCase))
72 throw new Exception("Invalid local file name.");
73
74 if (!string.IsNullOrEmpty(this.fileName))
75 {
76 if (File.Exists(FullPath) || Directory.Exists(FullPath))
77 throw new Exception("File or folder already exists.");
78
79 File.Move(this.fileName, FullPath);
80 }
81
82 this.fileLocalName = value;
83 this.fileName = FullPath;
84 }
85 }
86 }
87
91 [Page(7, "File System", 100)]
92 [Header(10, "Full Path:")]
93 [ToolTip(15, "Full path to file.")]
94 [ReadOnly]
95 public string FileName => this.fileName;
96
100 public string NodeId => this.fileName;
101
106
110 public string Partition => string.Empty;
111
115 public string LocalId => Path.GetFileName(this.fileName);
116
120 public string LogId => this.fileName;
121
126 public Task<string> GetTypeNameAsync(Language Language)
127 {
128 return Language.GetStringAsync(typeof(ProgramDataSource), 4, "File");
129 }
130
134 public bool HasChildren => false;
135
139 public bool ChildrenOrdered => false;
140
144 public bool IsReadable => false; // TODO
145
149 public bool IsControllable => true;
150
154 public bool HasCommands => true;
155
159 public INode Parent => this.parent;
160
164 public DateTime LastChanged => File.GetLastWriteTimeUtc(this.fileName);
165
169 public NodeState State => NodeState.None;
170
174 public Task<IEnumerable<INode>> ChildNodes => Task.FromResult<IEnumerable<INode>>(null);
175
181 public Task<bool> CanViewAsync(RequestOrigin Caller)
182 {
183 return Task.FromResult(Caller.HasPrivilege("Source." + ProgramDataSource.SourceID + ".Node.View"));
184 }
185
191 public Task<bool> CanEditAsync(RequestOrigin Caller)
192 {
193 return Task.FromResult(Caller.HasPrivilege("Source." + ProgramDataSource.SourceID + ".Node.Edit"));
194 }
195
201 public Task<bool> CanAddAsync(RequestOrigin Caller)
202 {
203 return Task.FromResult(Caller.HasPrivilege("Source." + ProgramDataSource.SourceID + ".Node.Add"));
204 }
205
211 public Task<bool> CanDestroyAsync(RequestOrigin Caller)
212 {
213 if (this.parent is null)
214 return Task.FromResult(false);
215 else
216 return Task.FromResult(Caller.HasPrivilege("Source." + ProgramDataSource.SourceID + ".Node.Destroy"));
217 }
218
219 internal void FileUpdated()
220 {
221 this.created = null;
222 this.updated = null;
223 this.size = null;
224 }
225
232 public async Task<IEnumerable<Parameter>> GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
233 {
234 LinkedList<Parameter> Parameters = new LinkedList<Parameter>();
235
236 if (!this.size.HasValue)
237 {
238 try
239 {
240 FileInfo FileInfo = new FileInfo(this.fileName);
241 this.size = FileInfo.Length;
242 }
243 catch (Exception)
244 {
245 // Ignore
246 }
247 }
248
249 if (this.created is null)
250 {
251 try
252 {
253 this.created = File.GetCreationTimeUtc(this.fileName);
254 }
255 catch (Exception)
256 {
257 // Ignore
258 }
259 }
260
261 if (this.updated is null)
262 {
263 try
264 {
265 this.updated = File.GetLastWriteTimeUtc(this.fileName);
266 }
267 catch (Exception)
268 {
269 // Ignore
270 }
271 }
272
273 if (this.size.HasValue)
274 {
275 Parameters.AddLast(new Int64Parameter("Bytes", await Language.GetStringAsync(typeof(ProgramDataSource), 14, "Bytes"),
276 this.size.Value));
277 }
278
279 if (this.created.HasValue)
280 {
281 Parameters.AddLast(new DateTimeParameter("Created", await Language.GetStringAsync(typeof(ProgramDataSource), 5, "Created"),
282 this.created.Value));
283
284 if (this.updated.HasValue && this.updated.Value > this.created.Value)
285 {
286 Parameters.AddLast(new DateTimeParameter("Updated", await Language.GetStringAsync(typeof(ProgramDataSource), 6, "Updated"),
287 this.updated.Value));
288 }
289 }
290
291 return Parameters;
292 }
293
298 public Task<IEnumerable<Message>> GetMessagesAsync(RequestOrigin Caller)
299 {
300 return Task.FromResult<IEnumerable<Message>>(null);
301 }
302
308 public Task<bool> MoveUpAsync(RequestOrigin Caller) => Task.FromResult(false);
309
315 public Task<bool> MoveDownAsync(RequestOrigin Caller) => Task.FromResult(false);
316
322 public Task<bool> AcceptsParentAsync(INode Parent)
323 {
324 if (Parent is null)
325 return Task.FromResult(true);
326
327 if (!(Parent is ProgramDataFolder ParentFolder))
328 return Task.FromResult(false);
329
330 if (this.parent is null && string.IsNullOrEmpty(this.fileName))
331 this.parent = ParentFolder;
332
333 return Task.FromResult(true);
334 }
335
341 public Task<bool> AcceptsChildAsync(INode Child)
342 {
343 return Task.FromResult(false);
344 }
345
350 public Task AddAsync(INode Child)
351 {
352 throw new NotSupportedException();
353 }
354
358 public Task UpdateAsync() => Task.CompletedTask;
359
365 public Task<bool> RemoveAsync(INode Child) => Task.FromResult(true);
366
370 public Task DestroyAsync()
371 {
372 if (this.parent is null)
373 throw new UnauthorizedAccessException("File is protected against deletion.");
374
375 if (File.Exists(this.fileName))
376 File.Delete(this.fileName);
377
378 return Task.CompletedTask;
379 }
380
384 public Task<IEnumerable<ICommand>> Commands
385 {
386 get
387 {
388 return this.IsTextFile
389 ? Task.FromResult<IEnumerable<ICommand>>(new ICommand[] { new EditTextCommand(this) })
390 : Task.FromResult<IEnumerable<ICommand>>(null);
391 }
392 }
393
397 public bool IsTextFile
398 {
399 get
400 {
401 if (this.fileName.EndsWith(".config", StringComparison.CurrentCultureIgnoreCase))
402 return true;
403
404 string FileExtension = Path.GetExtension(this.fileName);
405
406 if (!InternetContent.TryGetContentType(FileExtension, out string ContentType))
407 return false;
408
409 if (ContentType.StartsWith("text/", StringComparison.OrdinalIgnoreCase))
410 return true;
411
412 switch (ContentType.ToLower())
413 {
416 case "application/json":
417 case "application/x-tex":
418 case "application/x-webscript":
419 case "application/x-turtle":
420 case "application/link-format":
421 case "application/sparql-query":
422 return true;
423 }
424
425 if (ContentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase) &&
426 (ContentType.EndsWith("+xml", StringComparison.OrdinalIgnoreCase) ||
427 ContentType.EndsWith("+json", StringComparison.OrdinalIgnoreCase)))
428 {
429 return true;
430 }
431
432 return false;
433 }
434 }
435
439 public string ContentType
440 {
441 get
442 {
443 if (this.fileName.EndsWith(".config", StringComparison.CurrentCultureIgnoreCase))
445
446 string FileExtension = Path.GetExtension(this.fileName);
447
448 if (InternetContent.TryGetContentType(FileExtension, out string ContentType))
449 return ContentType;
450
452 }
453 }
454
459 public async Task<ControlParameter[]> GetControlParameters()
460 {
461 List<ControlParameter> Parameters = new List<ControlParameter>();
462 FileAttributes Attributes = File.GetAttributes(this.FileName);
465 string Page = await Namespace.GetStringAsync(16, "Attributes");
466
467 Parameters.Add(new BooleanControlParameter("ReadOnly", Page,
468 await Namespace.GetStringAsync(17, "Read-only"),
469 await Namespace.GetStringAsync(18, "If file is read-only."),
470 GetReadOnly, SetReadOnly));
471
472 Parameters.Add(new BooleanControlParameter("Hidden", Page,
473 await Namespace.GetStringAsync(19, "Hidden"),
474 await Namespace.GetStringAsync(20, "If file is hidden."),
475 GetHidden, SetHidden));
476
477 Parameters.Add(new BooleanControlParameter("System", Page,
478 await Namespace.GetStringAsync(21, "System"),
479 await Namespace.GetStringAsync(22, "If file is a system file."),
480 GetSystem, SetSystem));
481
482 Parameters.Add(new BooleanControlParameter("Archive", Page,
483 await Namespace.GetStringAsync(23, "Archive"),
484 await Namespace.GetStringAsync(24, "If file is a candidate for backup or removal."),
485 GetArchive, SetArchive));
486
487 return Parameters.ToArray();
488 }
489
490 private static Task<bool?> GetReadOnly(IThingReference Node)
491 {
492 return GetAttribute(Node, FileAttributes.ReadOnly);
493 }
494
495 private static Task SetReadOnly(IThingReference Node, bool Value)
496 {
497 return SetAttribute(Node, Value, FileAttributes.ReadOnly);
498 }
499
500 private static Task<bool?> GetHidden(IThingReference Node)
501 {
502 return GetAttribute(Node, FileAttributes.Hidden);
503 }
504
505 private static Task SetHidden(IThingReference Node, bool Value)
506 {
507 return SetAttribute(Node, Value, FileAttributes.Hidden);
508 }
509
510 private static Task<bool?> GetSystem(IThingReference Node)
511 {
512 return GetAttribute(Node, FileAttributes.System);
513 }
514
515 private static Task SetSystem(IThingReference Node, bool Value)
516 {
517 return SetAttribute(Node, Value, FileAttributes.System);
518 }
519
520 private static Task<bool?> GetArchive(IThingReference Node)
521 {
522 return GetAttribute(Node, FileAttributes.Archive);
523 }
524
525 private static Task SetArchive(IThingReference Node, bool Value)
526 {
527 return SetAttribute(Node, Value, FileAttributes.Archive);
528 }
529
530 private static Task<bool?> GetAttribute(IThingReference Node, FileAttributes Attribute)
531 {
532 if (!(Node is ProgramDataFile FileNode))
533 return Task.FromResult<bool?>(null);
534
535 FileAttributes Attr = File.GetAttributes(FileNode.FileName);
536
537 return Task.FromResult<bool?>(Attr.HasFlag(Attribute));
538 }
539
540 private static Task SetAttribute(IThingReference Node, bool Value, FileAttributes Attribute)
541 {
542 if (!(Node is ProgramDataFile FileNode))
543 throw new ArgumentException("Unexpected node type.", nameof(Node));
544
545 FileAttributes Attr = File.GetAttributes(FileNode.FileName);
546 FileAttributes Bak = Attr;
547
548 if (Value)
549 Attr |= Attribute;
550 else
551 Attr &= ~Attribute;
552
553 if (Attr != Bak)
554 File.SetAttributes(FileNode.FileName, Attr);
555
556 return Task.CompletedTask;
557 }
558
559 }
560}
const string DefaultContentType
application/javascript
Static class managing encoding and decoding of internet content.
static bool TryGetContentType(string FileExtension, out string ContentType)
Tries to get the content type of an item, given its file extension.
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
const string SchemaContentType
Default content type for XML schema documents.
Definition: XmlCodec.cs:35
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.
Task AddAsync(INode Child)
Adds a new child to the node.
bool HasChildren
If the source has any child sources.
string ContentType
If the referenced file is a text file.
Task UpdateAsync()
Updates the node (in persisted storage).
string Partition
Optional partition in which the Node ID is unique.
Task< bool > CanDestroyAsync(RequestOrigin Caller)
If the node can be destroyed to by the caller.
Task< bool > MoveUpAsync(RequestOrigin Caller)
Tries to move the node up.
Task< bool > MoveDownAsync(RequestOrigin Caller)
Tries to move the node down.
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 ...
INode Parent
Parent Node, or null if a root node.
Task< IEnumerable< INode > > ChildNodes
Child nodes. If no child nodes are available, null is returned.
string LocalId
If provided, an ID for the node, but unique locally between siblings. Can be null,...
async Task< ControlParameter[]> GetControlParameters()
Get control parameters for the actuator.
async Task< IEnumerable< Parameter > > GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
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.
ProgramDataFile()
Reference to a file in the ProgramData folder of the broker.
NodeState State
Current overall state of the node.
ProgramDataFile(string FileName, ProgramDataFolder Parent, DateTime? Created, DateTime? Updated, long? Size)
Reference to a file in the ProgramData folder of the broker.
Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
Task DestroyAsync()
Destroys the node. If it is a child to a parent node, it is removed from the parent first.
Task< bool > CanEditAsync(RequestOrigin Caller)
If the node can be edited by the caller.
DateTime LastChanged
When the node was last updated.
string LogId
If provided, an ID for the node, as it would appear or be used in system logs. Can be null,...
bool IsTextFile
If the referenced file is a text file.
bool ChildrenOrdered
If the children of the node have an intrinsic order (true), or if the order is not important (false).
string SourceId
Optional ID of source containing node.
Task< IEnumerable< Message > > GetMessagesAsync(RequestOrigin Caller)
Gets messages logged on the node.
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 > RemoveAsync(INode Child)
Removes a child from the node.
Task< IEnumerable< ICommand > > Commands
Available command objects. If no commands are available, null is returned.
bool HasCommands
If the node has registered commands or not.
Reference to a folder in the ProgramData folder of the broker.
Data source mirroring the ProgramData folder for the broker.
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