APIs

Show:
  1. "use strict";
  2.  
  3. /**
  4. * @module opcua.address_space
  5. */
  6. const assert = require("node-opcua-assert").assert;
  7. const util = require("util");
  8. const _ = require("underscore");
  9.  
  10.  
  11.  
  12. const NodeClass = require("node-opcua-data-model").NodeClass;
  13. const AttributeIds = require("node-opcua-data-model").AttributeIds;
  14.  
  15. const DataValue = require("node-opcua-data-value").DataValue;
  16.  
  17. const DataType = require("node-opcua-variant").DataType;
  18. const Variant = require("node-opcua-variant").Variant;
  19.  
  20. const StatusCodes = require("node-opcua-status-code").StatusCodes;
  21.  
  22. const BaseNode = require("./base_node").BaseNode;
  23. const UAVariable = require("./ua_variable").UAVariable;
  24. const SessionContext = require("./session_context").SessionContext;
  25.  
  26.  
  27. function UAMethod(options) {
  28.  
  29. BaseNode.apply(this, arguments);
  30. // assert(this.typeDefinition.value === resolveNodeId("MethodType").value);
  31. this.value = options.value;
  32. this.methodDeclarationId = options.methodDeclarationId;
  33.  
  34. }
  35. util.inherits(UAMethod, BaseNode);
  36. UAMethod.prototype.nodeClass = NodeClass.Method;
  37.  
  38.  
  39. UAMethod.prototype.getExecutableFlag = function (context) {
  40. assert(context instanceof SessionContext);
  41. if (!_.isFunction(this._asyncExecutionFunction)) {
  42. return false;
  43. }
  44. if (this._getExecutableFlag) {
  45. return this._getExecutableFlag(context);
  46. }
  47. return true;
  48. };
  49.  
  50. UAMethod.prototype.readAttribute = function (context, attributeId) {
  51.  
  52. assert(context instanceof SessionContext);
  53.  
  54. const self = this;
  55. const options = {};
  56. switch (attributeId) {
  57. case AttributeIds.Executable:
  58. options.value = {dataType: DataType.Boolean, value: self.getExecutableFlag(context)};
  59. options.statusCode = StatusCodes.Good;
  60. break;
  61. case AttributeIds.UserExecutable:
  62. options.value = {dataType: DataType.Boolean, value: self.getExecutableFlag(context)};
  63. options.statusCode = StatusCodes.Good;
  64. break;
  65. default:
  66. return BaseNode.prototype.readAttribute.call(this, context, attributeId);
  67. }
  68. return new DataValue(options);
  69. };
  70.  
  71.  
  72.  
  73.  
  74. function default_check_valid_argument(arg) {
  75. return arg.constructor.name === "Argument";
  76. /*
  77. var Argument = require("./_generated_/_auto_generated_Argument").Argument;
  78. return arg instanceof Argument
  79. */
  80. }
  81.  
  82. UAMethod.checkValidArgument = default_check_valid_argument;
  83.  
  84. UAMethod.prototype._getArguments = function (name) {
  85.  
  86. assert(name === "InputArguments" || name === "OutputArguments");
  87. const argsVariable = this.getPropertyByName(name);
  88. if (!argsVariable) { return [];}
  89.  
  90. assert(argsVariable instanceof UAVariable);
  91.  
  92. const args = argsVariable.readValue().value.value;
  93.  
  94. // a list of extension object
  95. assert(_.isArray(args));
  96. assert(args.length === 0 || UAMethod.checkValidArgument(args[0]) );
  97. return args;
  98.  
  99. };
  100.  
  101. UAMethod.prototype.getInputArguments = function () {
  102. return this._getArguments("InputArguments");
  103. };
  104.  
  105. UAMethod.prototype.getOutputArguments = function () {
  106. return this._getArguments("OutputArguments");
  107.  
  108. };
  109.  
  110. /**
  111. * @method bindMethod
  112. * @param async_func {Function}
  113. * @param async_func.inputArguments
  114. * @param async_func.context
  115. * @param async_func.callback {Function}
  116. * @param async_func.callback.err {Error|null}
  117. * @param async_func.callback.callMethodResponse.statusCode {StatusCode}
  118. * @param async_func.callback.callMethodResponse.outputArguments {Variant[]}
  119. */
  120. UAMethod.prototype.bindMethod = function (async_func) {
  121. assert(_.isFunction(async_func));
  122. const self = this;
  123. self._asyncExecutionFunction = async_func;
  124. };
  125.  
  126.  
  127. /**
  128. * @method execute
  129. * @async
  130. * @param context {SessionContext}
  131. * @param inputArguments {null|Variant[]} input arguments as array of variant
  132. * @param callback
  133. * @async
  134. */
  135. UAMethod.prototype.execute = function (inputArguments, context, callback) {
  136. assert(inputArguments === null || _.isArray(inputArguments));
  137. assert(context instanceof SessionContext);
  138. inputArguments = inputArguments ||[];
  139. inputArguments = inputArguments.map(Variant.coerce);
  140. assert(inputArguments.length === 0 || inputArguments[0] instanceof Variant);
  141. assert(_.isObject(context));
  142. assert(_.isFunction(callback));
  143. const self = this;
  144.  
  145. // a context object must be provided
  146. if (!context.object) {
  147. context.object = self.parent;
  148. }
  149.  
  150. assert(context.object instanceof BaseNode);
  151.  
  152. //xx inputArguments = inputArguments.map(function(a) { return Variant.coerce(a); });
  153. //xx inputArguments.forEach(function(arg){ assert(arg instanceof Variant); });
  154.  
  155. if (!self._asyncExecutionFunction) {
  156. console.log("Method " + self.nodeId.toString() + " " + self.browseName.toString() + "_ has not been bound");
  157.  
  158. return callback(null, {statusCode: StatusCodes.BadInternalError});
  159. }
  160.  
  161. if (!self.getExecutableFlag(context)) {
  162. console.log("Method " + self.nodeId.toString() + " " + self.browseName.toString() + "_ is not executable");
  163. // todo : find the correct Status code to return here
  164. return callback(null, {statusCode: StatusCodes.BadMethodInvalid});
  165. }
  166. // verify that input arguments are correct
  167. // todo :
  168. const inputArgumentResults = [];
  169. const inputArgumentDiagnosticInfos = [];
  170.  
  171. try {
  172. self._asyncExecutionFunction(inputArguments, context, function (err, callMethodResponse) {
  173.  
  174. callMethodResponse = callMethodResponse || {};
  175.  
  176. callMethodResponse.statusCode = callMethodResponse.statusCode || StatusCodes.Good;
  177. callMethodResponse.outputArguments = callMethodResponse.outputArguments || [];
  178.  
  179. callMethodResponse.inputArgumentResults = inputArgumentResults;
  180. callMethodResponse.inputArgumentDiagnosticInfos = inputArgumentDiagnosticInfos;
  181.  
  182. // verify that output arguments are correct according to schema
  183. // Todo : ...
  184. const outputArgsDef = self.getOutputArguments();
  185.  
  186. //xx assert(outputArgsDef.length === callMethodResponse.outputArguments.length,
  187. //xx "_asyncExecutionFunction did not provide the expected number of output arguments");
  188. // to be continued ...
  189.  
  190.  
  191. callback(err, callMethodResponse);
  192.  
  193. });
  194.  
  195. } catch(err){
  196. console.log("ERR in method handler".red,err.message);
  197. console.error(err.stack);
  198. const callMethodResponse = { statusCode: StatusCodes.BadInternalError};
  199. callback(err, callMethodResponse);
  200.  
  201. }
  202.  
  203. };
  204.  
  205.  
  206.  
  207. UAMethod.prototype.clone = function (options,optionalFilter,extraInfo) {
  208.  
  209. const Namespace = require("./namespace").Namespace;
  210.  
  211. assert(!options.componentOf || options.componentOf,"trying to create an orphan method ?");
  212.  
  213. const self = this;
  214. options = options || {};
  215. options = _.extend(_.clone(options),{
  216. methodDeclarationId: self.nodeId
  217. });
  218. options.references = options.references||[];
  219.  
  220. const addressSpace = self.addressSpace;
  221. Namespace._handle_hierarchy_parent(addressSpace,options.references,options);
  222.  
  223. const clonedMethod = self._clone(UAMethod,options, optionalFilter, extraInfo);
  224. clonedMethod._asyncExecutionFunction = self._asyncExecutionFunction;
  225. clonedMethod._getExecutableFlag = self._getExecutableFlag;
  226.  
  227. if (options.componentOf) {
  228. //Xx console.log("Options ",options.componentOf.browseName.toString());
  229. const m = options.componentOf.getMethodByName(clonedMethod.browseName.name);
  230. assert(m);
  231. }
  232.  
  233.  
  234. return clonedMethod;
  235. };
  236. exports.UAMethod = UAMethod;
  237.  
  238.