Merge pull request #139 from PepperDash/hotfix/vc4-simpl-json-evaluateFile

Hotfix/vc4 simpl json evaluate file
This commit is contained in:
Neil Dorin
2022-06-15 10:45:58 -06:00
committed by GitHub
2 changed files with 269 additions and 162 deletions

View File

@@ -20,10 +20,25 @@ namespace PepperDash.Core.JsonToSimpl
/// </summary> /// </summary>
public const ushort JsonIsValidBoolChange = 2; public const ushort JsonIsValidBoolChange = 2;
/// <summary>
/// Reports the if the device is 3-series compatible
/// </summary>
public const ushort ProgramCompatibility3SeriesChange = 3;
/// <summary>
/// Reports the if the device is 4-series compatible
/// </summary>
public const ushort ProgramCompatibility4SeriesChange = 4;
/// <summary>
/// Reports the device platform enum value
/// </summary>
public const ushort DevicePlatformValueChange = 5;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort UshortValueChange = 101; public const ushort UshortValueChange = 101;
/// <summary> /// <summary>
/// ///
@@ -46,6 +61,21 @@ namespace PepperDash.Core.JsonToSimpl
/// ///
/// </summary> /// </summary>
public const ushort FilePathResolvedChange = 205; public const ushort FilePathResolvedChange = 205;
/// <summary>
/// Reports the root directory change
/// </summary>
public const ushort RootDirectoryChange = 206;
/// <summary>
/// Reports the room ID change
/// </summary>
public const ushort RoomIdChange = 207;
/// <summary>
/// Reports the room name change
/// </summary>
public const ushort RoomNameChange = 208;
} }
/// <summary> /// <summary>

View File

@@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json; using Newtonsoft.Json;
@@ -13,202 +14,278 @@ namespace PepperDash.Core.JsonToSimpl
/// <summary> /// <summary>
/// Represents a JSON file that can be read and written to /// Represents a JSON file that can be read and written to
/// </summary> /// </summary>
public class JsonToSimplFileMaster : JsonToSimplMaster public class JsonToSimplFileMaster : JsonToSimplMaster
{ {
/// <summary> /// <summary>
/// Sets the filepath as well as registers this with the Global.Masters list /// Sets the filepath as well as registers this with the Global.Masters list
/// </summary> /// </summary>
public string Filepath { get; private set; } public string Filepath { get; private set; }
/// <summary> /// <summary>
/// Filepath to the actual file that will be read (Portal or local) /// Filepath to the actual file that will be read (Portal or local)
/// </summary> /// </summary>
public string ActualFilePath { get; private set; } public string ActualFilePath { get; private set; }
/// <summary>
///
/// </summary>
public string Filename { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string FilePathName { get; private set; } public string Filename { get; private set; }
/// <summary>
///
/// </summary>
public string FilePathName { get; private set; }
/*****************************************************************************************/ /*****************************************************************************************/
/** Privates **/ /** Privates **/
// The JSON file in JObject form // The JSON file in JObject form
// For gathering the incoming data // For gathering the incoming data
object StringBuilderLock = new object(); object StringBuilderLock = new object();
// To prevent multiple same-file access // To prevent multiple same-file access
static object FileLock = new object(); static object FileLock = new object();
/*****************************************************************************************/ /*****************************************************************************************/
/// <summary> /// <summary>
/// SIMPL+ default constructor. /// SIMPL+ default constructor.
/// </summary> /// </summary>
public JsonToSimplFileMaster() public JsonToSimplFileMaster()
{ {
} }
/// <summary> /// <summary>
/// Read, evaluate and udpate status /// Read, evaluate and udpate status
/// </summary> /// </summary>
public void EvaluateFile(string filepath) public void EvaluateFile(string filepath)
{ {
Filepath = filepath; try
{
OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange);
OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); var dirSeparator = Path.DirectorySeparatorChar;
if (string.IsNullOrEmpty(Filepath)) var dirSeparatorAlt = Path.AltDirectorySeparatorChar;
{
CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set");
return;
}
// Resolve wildcard var series = CrestronEnvironment.ProgramCompatibility;
var dir = Path.GetDirectoryName(Filepath);
Debug.Console(1, "Checking directory {0}", dir);
var fileName = Path.GetFileName(Filepath);
var directory = new DirectoryInfo(dir);
var actualFile = directory.GetFiles(fileName).FirstOrDefault(); var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3));
if (actualFile == null) OnBoolChange(is3Series, 0,
{ JsonToSimplConstants.ProgramCompatibility3SeriesChange);
var msg = string.Format("JSON file not found: {0}", Filepath);
CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg);
return;
}
// \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4));
// \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json OnBoolChange(is4Series, 0,
ActualFilePath = actualFile.FullName; JsonToSimplConstants.ProgramCompatibility4SeriesChange);
OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange);
Debug.Console(1, "Actual JSON file is {0}", ActualFilePath);
Filename = actualFile.Name; var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server;
OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange); OnBoolChange(isServer, 0,
Debug.Console(1, "JSON Filename is {0}", Filename); JsonToSimplConstants.DevicePlatformValueChange);
FilePathName = string.Format(@"{0}\", actualFile.DirectoryName); // get the roomID
OnStringChange(FilePathName, 0, JsonToSimplConstants.FilePathResolvedChange); var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId;
Debug.Console(1, "JSON File Path is {0}", FilePathName); if (!string.IsNullOrEmpty(roomId))
{
OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange);
}
string json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII); // get the roomName
var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName;
if (!string.IsNullOrEmpty(roomName))
{
OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange);
}
try var rootDirectory = Directory.GetApplicationRootDirectory();
{ OnStringChange(rootDirectory, 0, JsonToSimplConstants.RootDirectoryChange);
JsonObject = JObject.Parse(json);
foreach (var child in Children) var splusPath = string.Empty;
child.ProcessAll(); if (Regex.IsMatch(filepath, @"user", RegexOptions.IgnoreCase))
OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); {
} if (is4Series)
catch (Exception e) splusPath = Regex.Replace(filepath, "user", "user", RegexOptions.IgnoreCase);
{ else if (isServer)
var msg = string.Format("JSON parsing failed:\r{0}", e); splusPath = Regex.Replace(filepath, "user", "User", RegexOptions.IgnoreCase);
CrestronConsole.PrintLine(msg); else
ErrorLog.Error(msg); splusPath = filepath;
return; }
}
} filepath = splusPath.Replace(dirSeparatorAlt, dirSeparator);
Filepath = string.Format("{1}{0}{2}", dirSeparator, rootDirectory,
filepath.TrimStart(dirSeparator, dirSeparatorAlt));
OnStringChange(string.Format("Attempting to evaluate {0}", Filepath), 0, JsonToSimplConstants.StringValueChange);
if (string.IsNullOrEmpty(Filepath))
{
OnStringChange(string.Format("Cannot evaluate file. JSON file path not set"), 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set");
return;
}
// get file directory and name to search
var fileDirectory = Path.GetDirectoryName(Filepath);
var fileName = Path.GetFileName(Filepath);
OnStringChange(string.Format("Checking '{0}' for '{1}'", fileDirectory, fileName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Checking '{0}' for '{1}'", fileDirectory, fileName);
if (Directory.Exists(fileDirectory))
{
// get the directory info
var directoryInfo = new DirectoryInfo(fileDirectory);
// get the file to be read
var actualFile = directoryInfo.GetFiles(fileName).FirstOrDefault();
if (actualFile == null)
{
var msg = string.Format("JSON file not found: {0}", Filepath);
OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg);
return;
}
// \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json
// \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json
ActualFilePath = actualFile.FullName;
OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange);
OnStringChange(string.Format("Actual JSON file is {0}", ActualFilePath), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Actual JSON file is {0}", ActualFilePath);
Filename = actualFile.Name;
OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange);
OnStringChange(string.Format("JSON Filename is {0}", Filename), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "JSON Filename is {0}", Filename);
FilePathName = string.Format(@"{0}{1}", actualFile.DirectoryName, dirSeparator);
OnStringChange(string.Format(@"{0}", actualFile.DirectoryName), 0, JsonToSimplConstants.FilePathResolvedChange);
OnStringChange(string.Format(@"JSON File Path is {0}", actualFile.DirectoryName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "JSON File Path is {0}", FilePathName);
var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII);
JsonObject = JObject.Parse(json);
foreach (var child in Children)
child.ProcessAll();
OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange);
}
else
{
OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "'{0}' not found", fileDirectory);
}
}
catch (Exception e)
{
var msg = string.Format("EvaluateFile Exception: Message\r{0}", e.Message);
OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg);
var stackTrace = string.Format("EvaluateFile: Stack Trace\r{0}", e.StackTrace);
OnStringChange(stackTrace, 0, JsonToSimplConstants.StringValueChange);
CrestronConsole.PrintLine(stackTrace);
ErrorLog.Error(stackTrace);
}
}
/// <summary> /// <summary>
/// Sets the debug level /// Sets the debug level
/// </summary> /// </summary>
/// <param name="level"></param> /// <param name="level"></param>
public void setDebugLevel(int level) public void setDebugLevel(int level)
{ {
Debug.SetDebugLevel(level); Debug.SetDebugLevel(level);
} }
/// <summary> /// <summary>
/// Saves the values to the file /// Saves the values to the file
/// </summary> /// </summary>
public override void Save() public override void Save()
{ {
// this code is duplicated in the other masters!!!!!!!!!!!!! // this code is duplicated in the other masters!!!!!!!!!!!!!
UnsavedValues = new Dictionary<string, JValue>(); UnsavedValues = new Dictionary<string, JValue>();
// Make each child update their values into master object // Make each child update their values into master object
foreach (var child in Children) foreach (var child in Children)
{ {
Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key); Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key);
child.UpdateInputsForMaster(); child.UpdateInputsForMaster();
} }
if (UnsavedValues == null || UnsavedValues.Count == 0) if (UnsavedValues == null || UnsavedValues.Count == 0)
{ {
Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID); Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID);
return; return;
} }
lock (FileLock) lock (FileLock)
{ {
Debug.Console(1, "Saving"); Debug.Console(1, "Saving");
foreach (var path in UnsavedValues.Keys) foreach (var path in UnsavedValues.Keys)
{ {
var tokenToReplace = JsonObject.SelectToken(path); var tokenToReplace = JsonObject.SelectToken(path);
if (tokenToReplace != null) if (tokenToReplace != null)
{// It's found {// It's found
tokenToReplace.Replace(UnsavedValues[path]); tokenToReplace.Replace(UnsavedValues[path]);
Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path); Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path);
} }
else // No token. Let's make one else // No token. Let's make one
{ {
//http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net //http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net
Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path); Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path);
// JContainer jpart = JsonObject; // JContainer jpart = JsonObject;
// // walk down the path and find where it goes // // walk down the path and find where it goes
//#warning Does not handle arrays. //#warning Does not handle arrays.
// foreach (var part in path.Split('.')) // foreach (var part in path.Split('.'))
// { // {
// var openPos = part.IndexOf('['); // var openPos = part.IndexOf('[');
// if (openPos > -1) // if (openPos > -1)
// { // {
// openPos++; // move to number // openPos++; // move to number
// var closePos = part.IndexOf(']'); // var closePos = part.IndexOf(']');
// var arrayName = part.Substring(0, openPos - 1); // get the name // var arrayName = part.Substring(0, openPos - 1); // get the name
// var index = Convert.ToInt32(part.Substring(openPos, closePos - openPos)); // var index = Convert.ToInt32(part.Substring(openPos, closePos - openPos));
// // Check if the array itself exists and add the item if so // // Check if the array itself exists and add the item if so
// if (jpart[arrayName] != null) // if (jpart[arrayName] != null)
// { // {
// var arrayObj = jpart[arrayName] as JArray; // var arrayObj = jpart[arrayName] as JArray;
// var item = arrayObj[index]; // var item = arrayObj[index];
// if (item == null) // if (item == null)
// arrayObj.Add(new JObject()); // arrayObj.Add(new JObject());
// } // }
// Debug.Console(0, "IGNORING MISSING ARRAY VALUE FOR NOW"); // Debug.Console(0, "IGNORING MISSING ARRAY VALUE FOR NOW");
// continue; // continue;
// } // }
// // Build the // // Build the
// if (jpart[part] == null) // if (jpart[part] == null)
// jpart.Add(new JProperty(part, new JObject())); // jpart.Add(new JProperty(part, new JObject()));
// jpart = jpart[part] as JContainer; // jpart = jpart[part] as JContainer;
// } // }
// jpart.Replace(UnsavedValues[path]); // jpart.Replace(UnsavedValues[path]);
} }
} }
using (StreamWriter sw = new StreamWriter(ActualFilePath)) using (StreamWriter sw = new StreamWriter(ActualFilePath))
{ {
try try
{ {
sw.Write(JsonObject.ToString()); sw.Write(JsonObject.ToString());
sw.Flush(); sw.Flush();
} }
catch (Exception e) catch (Exception e)
{ {
string err = string.Format("Error writing JSON file:\r{0}", e); string err = string.Format("Error writing JSON file:\r{0}", e);
Debug.Console(0, err); Debug.Console(0, err);
ErrorLog.Warn(err); ErrorLog.Warn(err);
return; return;
} }
} }
} }
} }
} }
} }