node-red-contrib-opcua-server
Version:
Node-RED contribution nodes with next generation OPC UA in a compact and less dependencies package.
673 lines (610 loc) • 31.1 kB
HTML
<!--
MIT License
Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
--> <script type='text/x-red' data-help-name='opcua-compact-server'> <h2>OPC UA Compact Server</h2> <p>
The Compact Server node is an OPC UA server with a programmable address space to build your own information model. The address space is to expand with JS source code based on node-opcua API and OPC UA specification.
</p> The product URI have to be unique if you set some other name as the default is! (default: NodeOPCUA-Server-(port))
<p>Default enpoint: opc.tcp://localhost:54840</p> <p>Named enpoint: opc.tcp://localhost:54840/UA/NodeRED/Compact</p> <p>
Default discovery: opc.tcp://localhost:4840/UADiscovery</p> <p>all discovery: opc.tcp://localhost:4840/</p> <h3>Options
</h3> <p>If you need more information about all options read the node-opcua API, please!</p> <p>
The 'Delay Before Init' is to init the server node after some delay.</p> <p>
The 'Shutdown Timeout' is to tell node-opcua the server shutdown timeout.</p> <p>
The 'Delay On Close' is to close the server node with delay to all other nodes.</p> <h3>Certificates</h3> <p>
The server provides simple NodeOPCUA demo certificates and private keys.</p> <p>
You could set up your own certificate and private key files. This is optional.</p> <h3>User</h3> <p>
The user list is to set up users to the server. It is stored with Node-RED credentials best practice.</p> <h3>
XML NodeSets</h3> <p>That is static for now to add ISA95, DI, and Auto-ID to a server via XML NodeSet.</p> <h3>
AddressSpace</h3> <p>A function like programming editor to construct your own address space in the server.</p> <h3>
Discovery</h3> <p>
That gives you access to the servers discovery node-opcua parameters. Be sure to have a LDS running if you set LDS instead of HIDDEN.
</p> <p>Set showErrors to get errors from node-opcua on browse.</p> </script> <script type='text/javascript'>
RED.nodes.registerType("opcua-compact-server", { category: "opcua",
color: "#20B2aa",
defaults: {
port: {
value: 54840,
required: true,
validate: val => {
return val === "" || RED.validators.number(val);
}
},
endpoint: { value: "" },
productUri: { value: "" },
acceptExternalCommands: { value: true },
maxAllowedSessionNumber: {
value: 10,
validate: function(v) {
return v === "" || (RED.validators.number(v) && v > 0 && v <= 10);
}
},
maxConnectionsPerEndpoint: {
value: 10,
validate: function(v) {
return v === "" || (RED.validators.number(v) && v > 0 && v <= 10);
}
},
maxAllowedSubscriptionNumber: {
value: 100,
validate: function(v) {
return v === "" || (RED.validators.number(v) && v > 0 && v <= 10000);
}
},
alternateHostname: { value: "" },
name: { value: "" },
showStatusActivities: { value: false },
showErrors: { value: false },
allowAnonymous: { value: true },
individualCerts: { value: false },
isAuditing: { value: false },
serverDiscovery: { value: true },
users: { value: [] },
xmlsetsOPCUA: { value: [] },
publicCertificateFile: { value: "" },
privateCertificateFile: { value: "" },
registerServerMethod: { value: 1 },
discoveryServerEndpointUrl: { value: "" },
capabilitiesForMDNS: { value: "" },
maxNodesPerRead: {
value: 1000,
validate: function(v) {
return (
v === "" || (RED.validators.number(v) && v >= 0 && v <= 100000)
);
}
},
maxNodesPerWrite: {
value: 1000,
validate: function(v) {
return (
v === "" || (RED.validators.number(v) && v >= 0 && v <= 100000)
);
}
},
maxNodesPerHistoryReadData: {
value: 100,
validate: function(v) {
return v === "" || (RED.validators.number(v) && v >= 0 && v <= 10000);
}
},
maxNodesPerBrowse: {
value: 3000,
validate: function(v) {
return (
v === "" || (RED.validators.number(v) && v >= 0 && v <= 200000)
);
}
},
maxBrowseContinuationPoints: {
value: 10,
validate: function(v) {
return v === "" || (RED.validators.number(v) && v >= 0 && v <= 100);
}
},
maxHistoryContinuationPoints: {
value: 10,
validate: function(v) {
return v === "" || (RED.validators.number(v) && v >= 0 && v <= 100);
}
},
delayToInit: {
value: 1000,
validate: function(v) {
return (
v === "" || (RED.validators.number(v) && v >= 10 && v <= 200000)
);
}
},
delayToClose: {
value: 200,
validate: function(v) {
return (
v === "" || (RED.validators.number(v) && v >= 10 && v <= 15000)
);
}
},
serverShutdownTimeout: {
value: 100,
validate: function(v) {
return (
v === "" || (RED.validators.number(v) && v >= 10 && v <= 15000)
);
}
},
addressSpaceScript: {
value:
'function constructAlarmAddressSpace(server, addressSpace, eventObjects, done) {\n // server = the created node-opcua server\n // addressSpace = address space of the node-opcua server\n // eventObjects = add event variables here to hold them in memory from this script\n\n // internal sandbox objects are:\n // node = the compact server node,\n // coreServer = core compact server object for debug and access to NodeOPCUA\n // this.sandboxNodeContext = node context node-red\n // this.sandboxFlowContext = flow context node-red\n // this.sandboxGlobalContext = global context node-red\n // this.sandboxEnv = env variables\n // timeout and interval functions as expected from nodejs\n\n const opcua = coreServer.choreCompact.opcua;\n const rootFolder = addressSpace.findNode("RootFolder");\n const namespace = addressSpace.getOwnNamespace();\n\n // your code here\n \n done();\n}\n'
}
},
inputs: 0,
outputs: 0,
align: "right",
icon: "icon.png",
label: function() {
return this.name || "Compact-Server";
},
labelStyle: function() {
return this.name ? "node_label_italic" : "";
},
oneditprepare: function() {
let node = this;
node.xmlsetSelect = [];
let cacheItemCount = 0;
let cacheItemCountSet = 0;
let tabs = RED.tabs.create({
id: "node-input-server-tabs",
onchange: function(tab) {
$("#node-input-server-tabs-content")
.children()
.hide();
$("#" + tab.id).show();
}
});
tabs.addTab({
id: "compact-server-tab-settings",
label: this._("opcua-compact-contrib.tabs-label.settings")
});
tabs.addTab({
id: "compact-server-tab-limits",
label: this._("opcua-compact-contrib.tabs-label.limits")
});
tabs.addTab({
id: "compact-server-tab-security",
label: this._("opcua-compact-contrib.tabs-label.security")
});
tabs.addTab({
id: "compact-server-tab-users",
label: this._("opcua-compact-contrib.tabs-label.users")
});
tabs.addTab({
id: "compact-server-tab-ass",
label: this._("opcua-compact-contrib.tabs-label.ass")
});
tabs.addTab({
id: "compact-server-tab-discovery",
label: this._("opcua-compact-contrib.tabs-label.discovery")
});
// User Management
if (node.users && node.users.length > 0) {
cacheItemCount = node.users.length;
node.users.forEach(function(element, index, array) {
generateUserEntry(element, index);
});
}
// XML-Set Management
if (node.xmlsetsOPCUA && node.xmlsetsOPCUA.length > 0) {
cacheItemCountSet = node.xmlsetsOPCUA.length;
node.xmlsetsOPCUA.forEach(function(element, index, array) {
generateXMLSetEntry(element, index);
});
}
function generateUserEntry(user, id) {
let container = $("<li/>", {
style:
"background: #fefefe; margin:0; padding:8px 0px; border-bottom: 1px solid #ccc;"
});
let row = $('<div id="row' + id + '"/>').appendTo(container);
$(
'<i style="color: #eee; cursor: move;" class="node-input-server-users-handle fa fa-bars"></i>'
).appendTo(row);
let userField = $("<input/>", {
id: "node-input-server-users-name" + id,
class: "opcuaUserName",
type: "text",
style: "margin-left:5px;width:160px;",
placeholder: "name"
}).appendTo(row);
let passwordField = $("<input/>", {
id: "node-input-server-users-password" + id,
class: "opcuaUserPassword",
type: "password",
style: "margin: 0 auto;width:55%;min-width:60px;margin-left:5px",
placeholder: "password"
}).appendTo(row);
userField.val(user.name);
passwordField.val(user.password);
let finalspan = $("<span/>", {
style: "float: right;margin-right: 10px;"
}).appendTo(row);
let removeUserButton = $("<a/>", {
href: "#",
id: "node-button-user-remove" + id,
class: "editor-button editor-button-small",
style: "margin-top: 7px; margin-left: 5px;"
}).appendTo(finalspan);
$("<i/>", { class: "fa fa-remove" }).appendTo(removeUserButton);
removeUserButton.click(function() {
container.css({ background: "#fee" });
container.fadeOut(300, function() {
$(this).remove();
});
});
$("#node-input-server-users-container").append(container);
}
function generateXMLSetEntry(xmlset, id) {
let container = $("<li/>", {
style:
"background: #fefefe; margin:0; padding:8px 0px; border-bottom: 1px solid #ccc;"
});
let row = $('<div id="xmlsetRow' + id + '"/>').appendTo(container);
$(
'<i style="color: #eee; cursor: move;" class="node-input-server-xmlsets-handle fa fa-bars"></i>'
).appendTo(row);
let nameField = $("<input/>", {
id: "node-input-server-xmlsets-name" + id,
type: "text",
class: "xmlsetName",
style: "margin-left:5px;width:30%;min-width:60px",
placeholder: "name"
}).appendTo(row);
let pathField = $("<input/>", {
id: "node-input-server-xmlsets-path" + id,
class: "xmlsetPath",
type: "text",
style: "margin: 0 auto;width:60%;min-width:70px;margin-left:5px",
placeholder: "public/nodesets/Opc.Ua.Di.NodeSet2.xml"
}).appendTo(row);
nameField.val(xmlset.name);
pathField.val(xmlset.path);
let finalspan = $("<span/>", {
style: "float: right;margin-right: 10px;"
}).appendTo(row);
let lookupItemButton = $("<a/>", {
href: "#",
id: "node-button-xmlsets-lookup" + id,
class: "editor-button editor-button-small",
style: "margin-top: 7px; margin-left: 5px;"
}).appendTo(finalspan);
lookupItemButton.click(function() {
let xmlsetLookupButton = $("#node-button-xmlsets-lookup" + id);
let xmlsetLookupField = $(
"#xmlsetRow" + id + " #node-input-server-xmlsets-path" + id
);
xmlsetLookupButton.addClass("disabled");
$.getJSON("/OPCUA/compact/xmlsets/public", function(data) {
xmlsetLookupButton.removeClass("disabled");
node.xmlsetSelect = [];
$.each(data, function(i, filename) {
node.xmlsetSelect.push(filename);
});
xmlsetLookupField
.autocomplete({
source: node.xmlsetSelect,
minLength: 0,
close: function(event, ui) {
xmlsetLookupField.autocomplete("destroy");
}
})
.autocomplete("search", "");
});
});
$("<i/>", { class: "fa fa-search" }).appendTo(lookupItemButton);
let removeXMLSetButton = $("<a/>", {
href: "#",
id: "node-button-xmlset-remove" + id,
class: "editor-button editor-button-small",
style: "margin-top:7px;margin-left:5px;"
}).appendTo(finalspan);
$("<i/>", { class: "fa fa-remove" }).appendTo(removeXMLSetButton);
removeXMLSetButton.click(function() {
container.css({ background: "#fee" });
container.fadeOut(300, function() {
$(this).remove();
});
});
$("#node-input-server-xmlsets-container").append(container);
}
$("#node-input-server-users-container").sortable({
axis: "y",
handle: ".node-input-server-users-handle",
cursor: "move"
});
$("#node-input-server-xmlsets-container").sortable({
axis: "y",
handle: ".node-input-server-xmlsets-handle",
cursor: "move"
});
$(
"#node-input-server-users-container .node-input-server-users-handle"
).disableSelection();
$(
"#node-input-server-xmlsets-container .node-input-server-xmlsets-handle"
).disableSelection();
$("#node-input-server-users-add").click(function() {
if (!cacheItemCount || cacheItemCount < 0) {
cacheItemCount = 0;
}
generateUserEntry({ name: "", password: "" }, cacheItemCount++); // length is every time one more than index
$("#node-input-server-users-container-div").scrollTop(
$("#node-input-server-users-container-div").get(0).scrollHeight
);
});
$("#node-input-server-xmlsets-add").click(function() {
if (!cacheItemCountSet || cacheItemCountSet < 0) {
cacheItemCountSet = 0;
}
generateXMLSetEntry({ name: "", path: "" }, cacheItemCountSet++); // length is every time one more than index
$("#node-input-server-xmlsets-container-div").scrollTop(
$("#node-input-server-xmlsets-container-div").get(0).scrollHeight
);
});
function switchDialogResize() {
switchUserDialogResize();
switchXMLSetDialogSetResize();
}
// dialog User handling
function switchUserDialogResize() {
let rows = $(
"#dialog-form>div:not(.node-input-server-users-container-row)"
);
let height = $("#dialog-form").height();
rows.each(function(index, row) {
height -= row.outerHeight(true);
});
let editorRow = $(
"#dialog-form>div.node-input-server-users-container-row"
);
height -=
parseInt(editorRow.css("marginTop")) +
parseInt(editorRow.css("marginBottom"));
$("#node-input-server-users-container-div").css(
"height",
height + "px"
);
}
// dialog XML-Set handling
function switchXMLSetDialogSetResize() {
let rows = $(
"#dialogSet-form>div:not(.node-input-server-xmlsets-container-row)"
);
let height = $("#dialogSet-form").height();
rows.each(function(index, row) {
height -= row.outerHeight(true);
});
let editorRow = $(
"#dialogSet-form>div.node-input-server-xmlsets-container-row"
);
height -=
parseInt(editorRow.css("marginTop")) +
parseInt(editorRow.css("marginBottom"));
$("#node-input-server-xmlsets-container-div").css(
"height",
height + "px"
);
}
$("#dialog").on("dialogresize", switchDialogResize);
$("#dialog").on("dialogopen", function(ev) {
let size = $("#dialog").dialog("option", "sizeCache-switch");
if (size) {
$("#dialog").dialog("option", "width", size.width);
$("#dialog").dialog("option", "height", size.height);
switchDialogResize();
} else {
setTimeout(switchDialogResize, 10);
}
});
$("#dialog").on("dialogclose", function(ev, ui) {
$("#dialog").off("dialogresize", switchDialogResize);
});
// address space script
node.editorAddressSpaceScript = RED.editor.createEditor({
id: "node-input-func-editor-addressSpaceScript",
mode: "ace/mode/javascript",
value: $("#node-input-addressSpaceScript").val(),
globals: {
msg: true,
context: true,
RED: true,
util: true,
flow: true,
global: true,
console: true,
Buffer: true,
setTimeout: true,
clearTimeout: true,
setInterval: true,
clearInterval: true,
draggable: true
}
});
$(function() {
$("#node-input-func-editor-addressSpaceScript").resizable();
});
let element = document.getElementById(
"node-input-func-editor-addressSpaceScript"
);
element.addEventListener("mouseup", resizeScript, false);
function resizeScript() {
node.editorAddressSpaceScript.resize();
}
// Certificate Management
try {
let certsCheckbox = $("#node-input-individualCerts");
let configCertFields = $("#node-config-certFiles");
if (node.individualCerts) {
certsCheckbox.prop("checked", true);
configCertFields.show();
} else {
certsCheckbox.prop("checked", false);
configCertFields.hide();
}
certsCheckbox.change(function() {
if ($(this).is(":checked")) {
configCertFields.show();
} else {
configCertFields.hide();
$("#node-config-input-publicCertificateFile").val("");
$("#node-config-input-privateKeyFile").val("");
}
});
} catch (err) {
this.error(err);
}
},
oneditsave: function() {
let node = this;
let cacheUsers = $("#node-input-server-users-container").children();
node.users = [];
cacheUsers.each(function() {
node.users.push({
name: $(this)
.find(".opcuaUserName")
.val(),
password: $(this)
.find(".opcuaUserPassword")
.val()
});
});
let cacheXMLSets = $("#node-input-server-xmlsets-container").children();
node.xmlsetsOPCUA = [];
cacheXMLSets.each(function() {
node.xmlsetsOPCUA.push({
name: $(this)
.find(".xmlsetName")
.val(),
path: $(this)
.find(".xmlsetPath")
.val()
});
});
$("#node-input-addressSpaceScript").val(
this.editorAddressSpaceScript.getValue()
);
this.editorAddressSpaceScript.destroy();
delete this.editorAddressSpaceScript;
// console.log('well done editsave ...')
}
}); </script> <script type='text/x-red' data-template-name='opcua-compact-server'>
<div class='form-row'> <ul style='background:#fff;min-width:600px;margin-bottom:20px' id='node-input-server-tabs'></ul>
</div> <div id='node-input-server-tabs-content' style='min-height:170px'> <div id='compact-server-tab-settings'
style='display:none'> <div class='form-row'> <label for='node-input-port'><i class='fa fa-fort-awesom'></i> <span
data-i18n='opcua-compact-contrib.label.port'></span></label>
<!-- dynamic Ports from 49152 to 65535 (c000hex bis FFFFhex) --> <input type='text' id='node-input-port'
placeholder='Ports 49152 bis 65535 (c000hex bis FFFFhex)'> </div> <div class='form-row'> <label
for='node-input-endpoint'><i class='icon-tasks'></i> <span data-i18n='opcua-compact-contrib.label.endpoint'></span>
</label> <input type='text' id='node-input-endpoint' placeholder='UA/NodeRED/Compact'> </div> <div class='form-row'>
<label for='node-input-productUri'><i class='icon-tasks'></i> <span data-i18n='opcua-compact-contrib.label.productUri'>
</span></label> <input type='text' id='node-input-productUri' placeholder='NodeOPCUA-Server-(port)'> </div> <div
class='form-row'> <label for='node-input-alternateHostname'><i class='fa fa-server'></i> <span
data-i18n='opcua-compact-contrib.label.alternateHostname'></span></label> <input type='text'
id='node-input-alternateHostname' placeholder=''> </div> <hr> <div class='form-row'> <label
for='node-input-delayToInit'><i class='icon-time'></i> <span data-i18n='opcua-compact-contrib.label.delayToInit'></span>
</label> <input type='text' id='node-input-delayToInit' placeholder='1000' style='width:80px'> </div> <div
class='form-row'> <label for='node-input-serverShutdownTimeout'><i class='icon-time'></i> <span
data-i18n='opcua-compact-contrib.label.serverShutdownTimeout'></span></label> <input type='text'
id='node-input-serverShutdownTimeout' placeholder='100' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-delayToClose'><i class='icon-time'></i> <span data-i18n='opcua-compact-contrib.label.delayToClose'>
</span></label> <input type='text' id='node-input-delayToClose' placeholder='200' style='width:80px'> </div> <div
class='form-row'> <label for='node-input-name'><i class='fa fa-tag'></i> <span data-i18n='node-red:common.label.name'>
</span></label> <input type='text' id='node-input-name' placeholder=''> </div> <div class='form-row'> <label
style='min-width:160px' for='node-input-isAuditing'><i class='fa fa-th'></i> <span
data-i18n='opcua-compact-contrib.label.isAuditing'></span></label> <input type='checkbox' id='node-input-isAuditing'
style='max-width:30px'> </div> <hr> <div class='form-row'> <label style='min-width:160px'
for='node-input-showStatusActivities'><i class='fa fa-bolt'></i> <span
data-i18n='opcua-compact-contrib.label.showActivities'></span></label> <input type='checkbox'
id='node-input-showStatusActivities' style='max-width:30px'> </div> <div class='form-row'> <label
style='min-width:160px' for='node-input-showErrors'><i class='fa fa-exclamation-circle'></i> <span
data-i18n='opcua-compact-contrib.label.showErrors'></span></label> <input type='checkbox' id='node-input-showErrors'
style='max-width:30px'> </div> </div> <div id='compact-server-tab-limits' style='display:none'> <div class='form-row'>
<label for='node-input-maxAllowedSessionNumber'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxAllowedSessionNumber'></span></label> <input type='text'
id='node-input-maxAllowedSessionNumber' placeholder='10' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-maxConnectionsPerEndpoint'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxConnectionsPerEndpoint'></span></label> <input type='text'
id='node-input-maxConnectionsPerEndpoint' placeholder='10' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-maxAllowedSubscriptionNumber'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxAllowedSubscriptionNumber'></span></label> <input type='text'
id='node-input-maxAllowedSubscriptionNumber' placeholder='100' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-maxNodesPerRead'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxNodesPerRead'></span></label> <input type='text'
id='node-input-maxNodesPerRead' placeholder='1000' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-maxNodesPerHistoryReadData'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxNodesPerHistoryReadData'></span></label> <input type='text'
id='node-input-maxNodesPerHistoryReadData' placeholder='100' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-maxNodesPerWrite'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxNodesPerWrite'></span></label> <input type='text'
id='node-input-maxNodesPerWrite' placeholder='1000' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-maxNodesPerBrowse'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxNodesPerBrowse'></span></label> <input type='text'
id='node-input-maxNodesPerBrowse' placeholder='3000' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-maxBrowseContinuationPoints'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxBrowseContinuationPoints'></span></label> <input type='text'
id='node-input-maxBrowseContinuationPoints' placeholder='10' style='width:80px'> </div> <div class='form-row'> <label
for='node-input-maxHistoryContinuationPoints'><i class='icon-list'></i> <span
data-i18n='opcua-compact-contrib.label.maxHistoryContinuationPoints'></span></label> <input type='text'
id='node-input-maxHistoryContinuationPoints' placeholder='10' style='width:80px'> </div> </div> <div
id='compact-server-tab-security' style='display:none'> <div class='form-row'> <!-- SecurityPolicy enum via REST -->
<label for='node-input-securityPolicy' style='min-width:140px'><i class='fa fa-certificate'></i> <span
data-i18n='opcua-compact-contrib.label.securityPolicy'></span></label> <ul style='margin-left:80px'> <li>None</li> <li>
Basic128Rsa15</li> <li>Basic256</li> <li>Basic256Sha256</li> </ul> </div> <div class='form-row'>
<!-- MessageSecurityMode enum via REST --> <label for='node-input-securityMode' style='min-width:140px'><i
class='fa fa-key'></i> <span data-i18n='opcua-compact-contrib.label.securityMode'></span></label> <ul
style='margin-left:80px'> <li>None</li> <li>Sign</li> <li>Sign&Encrypt</li> </ul> </div> <div class='form-row'> <label
style='min-width:140px'> <i class='fa fa-certificate'></i> <span
data-i18n='opcua-compact-contrib.label.certificateFiles'></span> </label> </div> <div class='form-row'> <label
style='min-width:240px'> <i class='fa fa-file'></i> <span data-i18n='opcua-compact-contrib.label.individualCerts'>
</span> <input type='checkbox' id='node-input-individualCerts' style='max-width:30px'> </label> </div> <div
id='node-config-certFiles'> <hr> <div class='form-row'> <label for='node-input-publicCertificateFile'><i
class='fa fa-file'></i> <span data-i18n='opcua-compact-contrib.label.publicCertificateFile'></span></label> <input
type='text' id='node-input-publicCertificateFile' placeholder='../certificates/server_selfsigned_cert_2048.pem'
style='min-width:480px;width:100%'> </div> <div class='form-row'> <label for='node-input-privateCertificateFile'><i
class='fa fa-file'></i> <span data-i18n='opcua-compact-contrib.label.privateCertificateFile'></span></label> <input
type='text' id='node-input-privateCertificateFile' placeholder='../certificates/server_key_2048.pem'
style='min-width:480px;width:100%'> </div> <hr> </div> <div class='form-row'> <label for='node-input-allowAnonymous'
style='min-width:140px'><i class='icon-lock'></i> <span data-i18n='opcua-compact-contrib.label.allowAnonymous'></span>
</label> <input type='checkbox' id='node-input-allowAnonymous' style='max-width:35px'> </div> </div> <div
id='compact-server-tab-users' style='display:none'> <h4><span data-i18n='opcua-compact-contrib.label.users'></span></h4>
<div class='form-row node-input-server-users-container-row' style='margin-bottom:0'> <div
id='node-input-server-users-container-div'
style='box-sizing:border-box;border-radius:5px;height:210px;padding:5px;border:1px solid #ccc;overflow-y:scroll'> <ol
id='node-input-server-users-container' style='list-style-type:none;margin:0'></ol> </div> </div> <div class='form-row'>
<a href='#' class='editor-button editor-button-small' id='node-input-server-users-add' style='margin-top:4px'><i
class='fa fa-plus'></i> <span data-i18n='opcua-compact-contrib.label.addButton'></span></a> </div> <h4><span
data-i18n='opcua-compact-contrib.label.xmlsets'></span></h4> <div
class='form-row node-input-server-xmlsets-container-row' style='margin-bottom:0'> <div
id='node-input-server-xmlsets-container-div'
style='box-sizing:border-box;border-radius:5px;height:240px;padding:5px;border:1px solid #ccc;overflow-y:scroll'> <ol
id='node-input-server-xmlsets-container' style='list-style-type:none;margin:0'></ol> </div> </div> <div
class='form-row'> <a href='#' class='editor-button editor-button-small' id='node-input-server-xmlsets-add'
style='margin-top:4px'><i class='fa fa-plus'></i> <span data-i18n='opcua-compact-contrib.label.addButton'></span></a>
</div> </div> <div id='compact-server-tab-ass' style='display:none'> <div class='form-row' style='margin-bottom:0'>
<label for='node-input-addressSpaceScript' style='width:50%'><i class='fa fa-wrench'></i> <span
data-i18n='opcua-compact-contrib.label.function'></span></label> <input type='hidden'
id='node-input-addressSpaceScript'> </div> <div class='form-row node-text-editor-row' id='div-script-editor'> <div
style='height:350px;min-height:150px' class='node-text-editor' id='node-input-func-editor-addressSpaceScript'></div>
</div> </div> <div id='compact-server-tab-discovery' style='display:none'> <div class='form-row'>
<!-- SecurityPolicy enum via REST --> <label for='node-input-registerServerMethod' style='min-width:160px'><i
class='fa fa-discover'></i> <span data-i18n='opcua-compact-contrib.label.registerServerMethod'></span></label> <select
type='text' id='node-input-registerServerMethod'> <option value='1'>HIDDEN</option> <option value='2'>MDNS</option>
<option value='3'>LDS</option> </select> </div> <div class='form-row'> <span style='min-width:160px'> <ul> <li>
HIDDEN: the server doesn't expose itself to the external world </li><li>
MDNS: the server publish itself to the mDNS Multicast network directly </li><li>
LDS: the server registers itself to the LDS or LDS-ME (Local Discovery Server) </li></ul> </span> </div> <div
class='form-row'> <label for='node-input-serverDiscovery' style='min-width:160px'><i class='fa fa-cc-discover'></i>
<span data-i18n='opcua-compact-contrib.label.serverDiscovery'></span></label> <input type='checkbox'
id='node-input-serverDiscovery' style='max-width:35px'> </div> <div class='form-row'> <label
for='node-input-discoveryServerEndpointUrl' style='min-width:160px'><i class='icon-discover'></i> <span
data-i18n='opcua-compact-contrib.label.discoveryServerEndpointUrl'></span></label> <input type='text'
id='node-input-discoveryServerEndpointUrl' placeholder='opc.tcp://localhost:4840'> </div> <div class='form-row'> <label
for='node-input-capabilitiesForMDNS' style='min-width:160px'><i class='icon-discover'></i> <span
data-i18n='opcua-compact-contrib.label.capabilitiesForMDNS'></span></label> <input type='text'
id='node-input-capabilitiesForMDNS' placeholder='NA,DA,...'> </div> </div> </div> </script>