No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RSTP_DSLink.cs 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. using DSLink;
  2. using DSLink.Nodes;
  3. using DSLink.Nodes.Actions;
  4. using DSLink.Request;
  5. using Newtonsoft.Json.Linq;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using Serilog;
  11. using CommandLine;
  12. using System.IO;
  13. using RTSP_DSLink;
  14. namespace RTSP_DSLink
  15. {
  16. public class RSTP_DSLink : DSLinkContainer
  17. {
  18. private readonly Dictionary<string, Node> _rngValues;
  19. private readonly Random _random;
  20. private readonly Thread _randomNumberThread;
  21. private static void Main(string[] args)
  22. {
  23. Parser.Default.ParseArguments<CommandLineArguments>(args)
  24. .WithParsed(cmdLineOptions =>
  25. {
  26. cmdLineOptions = ProcessDSLinkJson(cmdLineOptions);
  27. //Init the logging engine
  28. InitializeLogging(cmdLineOptions);
  29. //Construct a link Configuration
  30. var config = new Configuration(cmdLineOptions.LinkName, true, true);
  31. //Construct our custom link
  32. var dslink = new RSTP_DSLink(config, cmdLineOptions);
  33. InitializeLink(dslink).Wait();
  34. })
  35. .WithNotParsed(errors => { Environment.Exit(-1); });
  36. while (true)
  37. {
  38. Thread.Sleep(1000);
  39. }
  40. }
  41. public static async Task InitializeLink(RSTP_DSLink dsLink)
  42. {
  43. await dsLink.Connect();
  44. await dsLink.SaveNodes();
  45. }
  46. public RSTP_DSLink(Configuration config, CommandLineArguments cmdLineOptions) : base(config)
  47. {
  48. //Perform any configuration overrides from command line options
  49. if (cmdLineOptions.BrokerUrl != null)
  50. {
  51. config.BrokerUrl = cmdLineOptions.BrokerUrl;
  52. }
  53. if (cmdLineOptions.Token != null)
  54. {
  55. config.Token = cmdLineOptions.Token;
  56. }
  57. if (cmdLineOptions.NodesFileName != null)
  58. {
  59. config.NodesFilename = cmdLineOptions.NodesFileName;
  60. }
  61. if (cmdLineOptions.KeysFolder != null)
  62. {
  63. config.KeysFolder = cmdLineOptions.KeysFolder;
  64. }
  65. _rngValues = new Dictionary<string, Node>();
  66. _random = new Random();
  67. Responder.AddNodeClass("rngAdd", delegate(Node node)
  68. {
  69. node.Configs.Set(ConfigType.DisplayName, new Value("Create RNG"));
  70. node.AddParameter(new Parameter
  71. {
  72. Name = "rngName",
  73. ValueType = DSLink.Nodes.ValueType.String
  74. });
  75. node.SetAction(new ActionHandler(Permission.Config, _createRngAction));
  76. });
  77. Responder.AddNodeClass("rng", delegate(Node node)
  78. {
  79. node.Configs.Set(ConfigType.Writable, new Value(Permission.Read.Permit));
  80. node.Configs.Set(ConfigType.ValueType, DSLink.Nodes.ValueType.Number.TypeValue);
  81. node.Value.Set(0);
  82. lock (_rngValues)
  83. {
  84. _rngValues.Add(node.Name, node);
  85. }
  86. });
  87. Responder.AddNodeClass("number", delegate (Node node)
  88. {
  89. node.Configs.Set(ConfigType.Writable, new Value(Permission.Read.Permit));
  90. node.Configs.Set(ConfigType.ValueType, DSLink.Nodes.ValueType.Number.TypeValue);
  91. node.Value.Set(0);
  92. });
  93. _randomNumberThread = new Thread(_updateRandomNumbers);
  94. _randomNumberThread.Start();
  95. }
  96. public override void InitializeDefaultNodes()
  97. {
  98. Responder.SuperRoot.CreateChild("createRNG", "rngAdd").BuildNode();
  99. }
  100. private void _updateRandomNumbers()
  101. {
  102. while (Thread.CurrentThread.IsAlive)
  103. {
  104. lock (_rngValues)
  105. {
  106. foreach (var n in _rngValues)
  107. {
  108. Node minChild, maxChild;
  109. n.Value.Children.TryGetValue("min", out minChild);
  110. n.Value.Children.TryGetValue("max", out maxChild);
  111. //Si les enfants ne sont pas initialisés, on met les valeurs de min et max à 0
  112. // Code équivalent à :
  113. //int min, max;
  114. //if (minChild != null) {
  115. // min = minChild.Value.Int;
  116. //}
  117. //else {
  118. // min = 0;
  119. //}
  120. //if (maxChild != null) {
  121. // max = maxChild.Value.Int;
  122. //}
  123. //else {
  124. // max = 0;
  125. //}
  126. int min = (minChild != null ? minChild.Value.Int : 0);
  127. int max = (maxChild != null ? maxChild.Value.Int : 0);
  128. n.Value.Value.Set(_random.Next(min, max+1));
  129. }
  130. }
  131. Thread.Sleep(10000);
  132. }
  133. }
  134. private async void _createRngAction(InvokeRequest request)
  135. {
  136. var rngName = request.Parameters["rngName"].Value<string>();
  137. if (string.IsNullOrEmpty(rngName)) return;
  138. if (Responder.SuperRoot.Children.ContainsKey(rngName)) return;
  139. var newRng = Responder.SuperRoot.CreateChild(rngName, "rng").BuildNode();
  140. newRng.CreateChild("min", "number").BuildNode();
  141. newRng.CreateChild("max", "number").BuildNode();
  142. await request.Close();
  143. await SaveNodes();
  144. }
  145. #region Initialize Logging
  146. /// <summary>
  147. /// This method initializes the logging engine. In this case Serilog is used, but you
  148. /// may use a variety of logging engines so long as they are compatible with
  149. /// Liblog (the interface used by the DSLink SDK)
  150. /// </summary>
  151. /// <param name="cmdLineOptions"></param>
  152. private static void InitializeLogging(CommandLineArguments cmdLineOptions)
  153. {
  154. if (cmdLineOptions.LogFileFolder != null &&
  155. !cmdLineOptions.LogFileFolder.EndsWith(Path.DirectorySeparatorChar))
  156. {
  157. throw new ArgumentException($"Specified LogFileFolder must end with '{Path.DirectorySeparatorChar}'");
  158. }
  159. var logConfig = new LoggerConfiguration();
  160. switch (cmdLineOptions.LogLevel)
  161. {
  162. case LogLevel.Debug:
  163. logConfig.MinimumLevel.Debug();
  164. break;
  165. case LogLevel.Unspecified:
  166. case LogLevel.Info:
  167. logConfig.MinimumLevel.Information();
  168. break;
  169. case LogLevel.Warning:
  170. logConfig.MinimumLevel.Warning();
  171. break;
  172. case LogLevel.Error:
  173. logConfig.MinimumLevel.Error();
  174. break;
  175. }
  176. logConfig.WriteTo.Console(
  177. outputTemplate:
  178. "{Timestamp:MM/dd/yyyy HH:mm:ss} {SourceContext} [{Level}] {Message}{NewLine}{Exception}");
  179. logConfig.WriteTo.Logger(lc =>
  180. {
  181. lc.WriteTo.RollingFile(cmdLineOptions.LogFileFolder + "log-{Date}.txt", retainedFileCountLimit: 3);
  182. });
  183. Log.Logger = logConfig.CreateLogger();
  184. }
  185. #endregion
  186. #region dslink-json file processing
  187. /// <summary>
  188. /// This method will return an instance of CommandLineArguments build with the following logic rules.
  189. /// The file dslink.json can be utilized to specifiy command line arguments. These live within the config block
  190. /// of the file. Here is an example:
  191. /// ...
  192. /// "configs" : {
  193. /// "broker" : {
  194. /// "type": "url",
  195. /// "value": "mybroker",
  196. /// "default": "http:localhost:8080\conn"
  197. /// },
  198. /// }
  199. ///
  200. /// The code in this method considers only the attribute's name ("broker") and value ("mybroker") in this example).
  201. /// "type" and "default" are not used.
  202. ///
  203. /// The receives an instance of CommandLineArguments previously built from the parser. If the dslink-json paramater
  204. /// is not null the code will use the value specified rather than the default value of "dslink.json" for the file
  205. /// to read containing the information.
  206. ///
  207. /// Options specified on the command line wins out over those specified in the file.
  208. ///
  209. /// </summary>
  210. /// <param name="cmdLineOptions"></param>
  211. /// <returns></returns>
  212. private static CommandLineArguments ProcessDSLinkJson(CommandLineArguments cmdLineOptions)
  213. {
  214. bool errorIfNotFound = false;
  215. string fileName = "dslink.json";
  216. //If filename is specified then error if it is not found
  217. if (!String.IsNullOrEmpty(cmdLineOptions.DSLinkJsonFilename))
  218. {
  219. errorIfNotFound = true;
  220. fileName = cmdLineOptions.DSLinkJsonFilename;
  221. }
  222. string fileData = "";
  223. if (File.Exists(fileName))
  224. {
  225. fileData = File.ReadAllText(fileName);
  226. Console.WriteLine(
  227. $"Will use a combination of options specified from the command line and those specified in {fileName}");
  228. }
  229. else
  230. {
  231. if (errorIfNotFound == true)
  232. {
  233. throw new ArgumentException($"Specified dslink-json file <{fileName}> was not found");
  234. }
  235. else
  236. {
  237. return cmdLineOptions;
  238. }
  239. }
  240. JObject dslinkJson = JObject.Parse(fileData);
  241. var dsLinkJsonConfig = dslinkJson["configs"];
  242. var cmdLineOptionsDslinkJson = new CommandLineArguments();
  243. cmdLineOptionsDslinkJson.BrokerUrl =
  244. GetDsLinkStringValueForAttributeName(dsLinkJsonConfig, "broker", cmdLineOptions.BrokerUrl);
  245. cmdLineOptionsDslinkJson.LinkName =
  246. GetDsLinkStringValueForAttributeName(dsLinkJsonConfig, "name", cmdLineOptions.LinkName);
  247. cmdLineOptionsDslinkJson.LogFileFolder =
  248. GetDsLinkStringValueForAttributeName(dsLinkJsonConfig, "log-file", cmdLineOptions.LogFileFolder);
  249. cmdLineOptionsDslinkJson.KeysFolder =
  250. GetDsLinkStringValueForAttributeName(dsLinkJsonConfig, "key", cmdLineOptions.KeysFolder);
  251. cmdLineOptionsDslinkJson.NodesFileName =
  252. GetDsLinkStringValueForAttributeName(dsLinkJsonConfig, "nodes", cmdLineOptions.NodesFileName);
  253. cmdLineOptionsDslinkJson.Token =
  254. GetDsLinkStringValueForAttributeName(dsLinkJsonConfig, "token", cmdLineOptions.Token);
  255. cmdLineOptionsDslinkJson.LogLevel = GetDsLinkLogLevel(dsLinkJsonConfig, cmdLineOptions.LogLevel);
  256. return cmdLineOptionsDslinkJson;
  257. }
  258. private static LogLevel GetDsLinkLogLevel(JToken configObj, LogLevel logLevel)
  259. {
  260. if (logLevel != LogLevel.Unspecified)
  261. {
  262. return logLevel;
  263. }
  264. string testString = "";
  265. try
  266. {
  267. testString = configObj["log"]["value"].ToString();
  268. }
  269. catch
  270. {
  271. }
  272. ;
  273. LogLevel useLogLevel = LogLevel.Info;
  274. if (!Enum.TryParse(testString, out useLogLevel))
  275. {
  276. throw new ArgumentException("Invalid 'value' specified for 'log' value in dslink-json file");
  277. }
  278. return useLogLevel;
  279. }
  280. private static string GetDsLinkStringValueForAttributeName(JToken configObj, string attributeName,
  281. string cmdLineValue)
  282. {
  283. //use cmdLineValue if specified else attempt to use the one from the dslink-json
  284. if (cmdLineValue != null)
  285. {
  286. return cmdLineValue;
  287. }
  288. try
  289. {
  290. return configObj[attributeName]["value"].ToString();
  291. }
  292. catch
  293. {
  294. return null;
  295. }
  296. }
  297. #endregion processingq
  298. }
  299. }