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.Collections.Generic;
2using System.IO;
3using System.Threading.Tasks;
4using System;
5using Waher.Things;
10using Waher.Content;
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 XmppServerModule.IsAdmin(Caller.From);
184 }
185
191 public Task<bool> CanEditAsync(RequestOrigin Caller)
192 {
193 return XmppServerModule.IsAdmin(Caller.From);
194 }
195
201 public Task<bool> CanAddAsync(RequestOrigin Caller)
202 {
203 return XmppServerModule.IsAdmin(Caller.From);
204 }
205
211 public async Task<bool> CanDestroyAsync(RequestOrigin Caller)
212 {
213 if (this.parent is null)
214 return false;
215 else
216 return await XmppServerModule.IsAdmin(Caller.From);
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 using (FileStream fs = File.OpenRead(this.fileName))
241 {
242 this.size = fs.Length;
243 }
244 }
245 catch (Exception)
246 {
247 // Ignore
248 }
249 }
250
251 if (this.created is null)
252 {
253 try
254 {
255 this.created = File.GetCreationTimeUtc(this.fileName);
256 }
257 catch (Exception)
258 {
259 // Ignore
260 }
261 }
262
263 if (this.updated is null)
264 {
265 try
266 {
267 this.updated = File.GetLastWriteTimeUtc(this.fileName);
268 }
269 catch (Exception)
270 {
271 // Ignore
272 }
273 }
274
275 if (this.size.HasValue)
276 {
277 Parameters.AddLast(new Int64Parameter("Bytes", await Language.GetStringAsync(typeof(ProgramDataSource), 14, "Bytes"),
278 this.size.Value));
279 }
280
281 if (this.created.HasValue)
282 {
283 Parameters.AddLast(new DateTimeParameter("Created", await Language.GetStringAsync(typeof(ProgramDataSource), 5, "Created"),
284 this.created.Value));
285
286 if (this.updated.HasValue && this.updated.Value > this.created.Value)
287 {
288 Parameters.AddLast(new DateTimeParameter("Updated", await Language.GetStringAsync(typeof(ProgramDataSource), 6, "Updated"),
289 this.updated.Value));
290 }
291 }
292
293 return Parameters;
294 }
295
300 public Task<IEnumerable<Message>> GetMessagesAsync(RequestOrigin Caller)
301 {
302 return Task.FromResult<IEnumerable<Message>>(null);
303 }
304
310 public Task<bool> MoveUpAsync(RequestOrigin Caller) => Task.FromResult(false);
311
317 public Task<bool> MoveDownAsync(RequestOrigin Caller) => Task.FromResult(false);
318
324 public Task<bool> AcceptsParentAsync(INode Parent)
325 {
326 if (Parent is null)
327 return Task.FromResult(true);
328
329 if (!(Parent is ProgramDataFolder ParentFolder))
330 return Task.FromResult(false);
331
332 if (this.parent is null && string.IsNullOrEmpty(this.fileName))
333 this.parent = ParentFolder;
334
335 return Task.FromResult(true);
336 }
337
343 public Task<bool> AcceptsChildAsync(INode Child)
344 {
345 return Task.FromResult(false);
346 }
347
352 public Task AddAsync(INode Child)
353 {
354 throw new NotSupportedException();
355 }
356
360 public Task UpdateAsync() => Task.CompletedTask;
361
367 public Task<bool> RemoveAsync(INode Child) => Task.FromResult(true);
368
372 public Task DestroyAsync()
373 {
374 if (this.parent is null)
375 throw new UnauthorizedAccessException("File is protected against deletion.");
376
377 if (File.Exists(this.fileName))
378 File.Delete(this.fileName);
379
380 return Task.CompletedTask;
381 }
382
386 public Task<IEnumerable<ICommand>> Commands
387 {
388 get
389 {
390 return this.IsTextFile
391 ? Task.FromResult<IEnumerable<ICommand>>(new ICommand[] { new EditTextCommand(this) })
392 : Task.FromResult<IEnumerable<ICommand>>(null);
393 }
394 }
395
399 public bool IsTextFile
400 {
401 get
402 {
403 if (this.fileName.EndsWith(".config", StringComparison.CurrentCultureIgnoreCase))
404 return true;
405
406 string FileExtension = Path.GetExtension(this.fileName);
407
408 if (!InternetContent.TryGetContentType(FileExtension, out string ContentType))
409 return false;
410
411 if (ContentType.StartsWith("text/", StringComparison.OrdinalIgnoreCase))
412 return true;
413
414 switch (ContentType.ToLower())
415 {
418 case "application/json":
419 case "application/x-tex":
420 case "application/x-webscript":
421 case "application/x-turtle":
422 case "application/link-format":
423 case "application/sparql-query":
424 return true;
425 }
426
427 if (ContentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase) &&
428 (ContentType.EndsWith("+xml", StringComparison.OrdinalIgnoreCase) ||
429 ContentType.EndsWith("+json", StringComparison.OrdinalIgnoreCase)))
430 {
431 return true;
432 }
433
434 return false;
435 }
436 }
437
441 public string ContentType
442 {
443 get
444 {
445 if (this.fileName.EndsWith(".config", StringComparison.CurrentCultureIgnoreCase))
447
448 string FileExtension = Path.GetExtension(this.fileName);
449
450 if (InternetContent.TryGetContentType(FileExtension, out string ContentType))
451 return ContentType;
452
454 }
455 }
456
461 public async Task<ControlParameter[]> GetControlParameters()
462 {
463 List<ControlParameter> Parameters = new List<ControlParameter>();
464 FileAttributes Attributes = File.GetAttributes(this.FileName);
467 string Page = await Namespace.GetStringAsync(16, "Attributes");
468
469 Parameters.Add(new BooleanControlParameter("ReadOnly", Page,
470 await Namespace.GetStringAsync(17, "Read-only"),
471 await Namespace.GetStringAsync(18, "If file is read-only."),
472 GetReadOnly, SetReadOnly));
473
474 Parameters.Add(new BooleanControlParameter("Hidden", Page,
475 await Namespace.GetStringAsync(19, "Hidden"),
476 await Namespace.GetStringAsync(20, "If file is hidden."),
477 GetHidden, SetHidden));
478
479 Parameters.Add(new BooleanControlParameter("System", Page,
480 await Namespace.GetStringAsync(21, "System"),
481 await Namespace.GetStringAsync(22, "If file is a system file."),
482 GetSystem, SetSystem));
483
484 Parameters.Add(new BooleanControlParameter("Archive", Page,
485 await Namespace.GetStringAsync(23, "Archive"),
486 await Namespace.GetStringAsync(24, "If file is a candidate for backup or removal."),
487 GetArchive, SetArchive));
488
489 return Parameters.ToArray();
490 }
491
492 private static Task<bool?> GetReadOnly(IThingReference Node)
493 {
494 return GetAttribute(Node, FileAttributes.ReadOnly);
495 }
496
497 private static Task SetReadOnly(IThingReference Node, bool Value)
498 {
499 return SetAttribute(Node, Value, FileAttributes.ReadOnly);
500 }
501
502 private static Task<bool?> GetHidden(IThingReference Node)
503 {
504 return GetAttribute(Node, FileAttributes.Hidden);
505 }
506
507 private static Task SetHidden(IThingReference Node, bool Value)
508 {
509 return SetAttribute(Node, Value, FileAttributes.Hidden);
510 }
511
512 private static Task<bool?> GetSystem(IThingReference Node)
513 {
514 return GetAttribute(Node, FileAttributes.System);
515 }
516
517 private static Task SetSystem(IThingReference Node, bool Value)
518 {
519 return SetAttribute(Node, Value, FileAttributes.System);
520 }
521
522 private static Task<bool?> GetArchive(IThingReference Node)
523 {
524 return GetAttribute(Node, FileAttributes.Archive);
525 }
526
527 private static Task SetArchive(IThingReference Node, bool Value)
528 {
529 return SetAttribute(Node, Value, FileAttributes.Archive);
530 }
531
532 private static Task<bool?> GetAttribute(IThingReference Node, FileAttributes Attribute)
533 {
534 if (!(Node is ProgramDataFile FileNode))
535 return Task.FromResult<bool?>(null);
536
537 FileAttributes Attr = File.GetAttributes(FileNode.FileName);
538
539 return Task.FromResult<bool?>(Attr.HasFlag(Attribute));
540 }
541
542 private static Task SetAttribute(IThingReference Node, bool Value, FileAttributes Attribute)
543 {
544 if (!(Node is ProgramDataFile FileNode))
545 throw new ArgumentException("Unexpected node type.", nameof(Node));
546
547 FileAttributes Attr = File.GetAttributes(FileNode.FileName);
548 FileAttributes Bak = Attr;
549
550 if (Value)
551 Attr |= Attribute;
552 else
553 Attr &= ~Attribute;
554
555 if (Attr != Bak)
556 File.SetAttributes(FileNode.FileName, Attr);
557
558 return Task.CompletedTask;
559 }
560
561 }
562}
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:16
const string DefaultContentType
Default content type for XML documents.
Definition: XmlCodec.cs:27
const string SchemaContentType
Default content type for XML schema documents.
Definition: XmlCodec.cs:32
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 > 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,...
async Task< bool > CanDestroyAsync(RequestOrigin Caller)
If the node can be destroyed to by the caller.
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 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