@@ -12,6 +12,65 @@ Installation
1212
1313 $ npm install cdp-client
1414
15+ Example
16+ -------
17+
18+ .. code :: javascript
19+
20+ const studio = require (" cdp-client" );
21+
22+ const client = new studio.api.Client (" 127.0.0.1:7690" , {
23+ credentialsRequested: async (request ) => {
24+ return { Username: " cdpuser" , Password: " cdpuser" };
25+ }
26+ });
27+
28+ // Track subscribed apps to avoid duplicates
29+ const subscribedApps = new Set ();
30+
31+ function subscribeToApp (app ) {
32+ const appName = app .name ();
33+ if (subscribedApps .has (appName)) return ;
34+ subscribedApps .add (appName);
35+
36+ // subscribeWithResume automatically restores subscriptions after reconnection
37+ client .subscribeWithResume (appName + ' .CPULoad' , value => {
38+ console .log (` [${ appName} ] CPULoad: ${ value} ` );
39+ });
40+ }
41+
42+ client .root ().then (root => {
43+ // Subscribe to apps already visible
44+ root .forEachChild (app => subscribeToApp (app));
45+
46+ // Subscribe to structure changes to catch sibling apps as they're discovered
47+ root .subscribeToStructure ((name , change ) => {
48+ if (change === 1 ) { // ADD
49+ root .child (name).then (app => subscribeToApp (app));
50+ }
51+ });
52+ }).catch (err => console .error (" Connection failed:" , err));
53+
54+ Proxy Support (CDP 5.1+)
55+ ------------------------
56+
57+ CDP 5.1 introduced proxy support which allows a single WebSocket connection to access
58+ multiple backend CDP applications through multiplexing. In older CDP versions, the client
59+ connected directly to each CDP application, meaning a dedicated port had to be opened for
60+ each application.
61+
62+ When connecting to a CDP 5.1+ application configured as a proxy, the client automatically
63+ discovers and connects to all backend applications. All discovered applications appear as
64+ children of the root system node, enabling transparent access to their structure and values
65+ through the standard API. The example above works the same whether the server has proxy
66+ support or not.
67+
68+ Benefits
69+ ~~~~~~~~
70+
71+ - Simplified firewall configuration - only one port needs to be opened
72+ - SSH port forwarding - forward a single port to access entire CDP system
73+
1574API
1675---
1776
@@ -303,6 +362,64 @@ client.find(path)
303362 // use the load object referring to CPULoad in MyApp
304363 });
305364
365+ client.subscribeWithResume(nodePath, valueConsumer, fs, sampleRate)
366+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
367+
368+ - Arguments
369+
370+ nodePath - Full dot-separated path to the node (e.g. "MyApp.CPULoad")
371+
372+ Function(value, timestamp) valueConsumer - Called on each value change
373+
374+ fs - maximum frequency that value updates are expected. Defaults to 5 hz.
375+
376+ sampleRate - maximum amount of value updates sent per second. Defaults to 0 (all samples).
377+
378+ - Returns
379+
380+ Promise that resolves when the subscription is registered.
381+
382+ - Usage
383+
384+ Subscribe to value changes with automatic re-subscription after reconnection. When a
385+ backend application restarts or the connection is re-established, the subscription is
386+ automatically restored. This is the recommended way to subscribe when using proxy connections.
387+
388+ - Example
389+
390+ .. code :: javascript
391+
392+ client .subscribeWithResume (' MyApp.CPULoad' , function (value , timestamp ) {
393+ console .log (" CPULoad: " + value);
394+ });
395+
396+ client.unsubscribeWithResume(nodePath, valueConsumer)
397+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
398+
399+ - Arguments
400+
401+ nodePath - Full dot-separated path to the node
402+
403+ Function(value, timestamp) valueConsumer - The callback to unsubscribe
404+
405+ - Usage
406+
407+ Unsubscribe a callback registered with subscribeWithResume.
408+
409+ client.close()
410+ ^^^^^^^^^^^^^^
411+
412+ - Usage
413+
414+ Close all connections managed by this client. This stops reconnection attempts
415+ and cleans up all resources. Call this when you are done using the client.
416+
417+ - Example
418+
419+ .. code :: javascript
420+
421+ client .close ();
422+
306423 Instance Methods / INode
307424~~~~~~~~~~~~~~~~~~~~~~~~
308425
@@ -334,11 +451,11 @@ node.info()
334451 +------------------+------------------------------+---------------------------------------------------------------+
335452 | Property | Type | Description |
336453 +==================+==============================+===============================================================+
337- | Info.node_id | number | Application wide unique ID for each instance in CDP structure |
454+ | Info.nodeId | number | Application wide unique ID for each instance in CDP structure |
338455 +------------------+------------------------------+---------------------------------------------------------------+
339456 | Info.name | string | Nodes short name |
340457 +------------------+------------------------------+---------------------------------------------------------------+
341- | Info.node_type | studio.protocol.CDPNodeType | | Direct CDP base type of the class. One of the following: |
458+ | Info.nodeType | studio.protocol.CDPNodeType | | Direct CDP base type of the class. One of the following: |
342459 | | | - CDP_UNDEFINED |
343460 | | | - CDP_APPLICATION |
344461 | | | - CDP_COMPONENT |
@@ -351,7 +468,7 @@ node.info()
351468 | | | - CDP_OPERATOR |
352469 | | | - CDP_NODE |
353470 +------------------+------------------------------+---------------------------------------------------------------+
354- | Info.value_type | studio.protocol.CDPValueType | | Optional: Value primitive type the node holds |
471+ | Info.valueType | studio.protocol.CDPValueType | | Optional: Value primitive type the node holds |
355472 | | | | if node may hold a value. One of the following: |
356473 | | | - eUNDEFINED |
357474 | | | - eDOUBLE |
@@ -367,15 +484,15 @@ node.info()
367484 | | | - eBOOL |
368485 | | | - eSTRING |
369486 +------------------+------------------------------+---------------------------------------------------------------+
370- | Info.type_name | string | Optional: Class name of the reflected node |
487+ | Info.typeName | string | Optional: Class name of the reflected node |
371488 +------------------+------------------------------+---------------------------------------------------------------+
372- | Info.server_addr | string | Optional: StudioAPI IP present on application nodes that |
373- | | | have **Info.is_local == false ** |
489+ | Info.serverAddr | string | Optional: StudioAPI IP present on application nodes that |
490+ | | | have **Info.isLocal == false ** |
374491 +------------------+------------------------------+---------------------------------------------------------------+
375- | Info.server_port | number | Optional: StudioAPI Port present on application nodes that |
376- | | | have **Info.is_local == false ** |
492+ | Info.serverPort | number | Optional: StudioAPI Port present on application nodes that |
493+ | | | have **Info.isLocal == false ** |
377494 +------------------+------------------------------+---------------------------------------------------------------+
378- | Info.is_local | boolean | Optional: When multiple applications are present in root node |
495+ | Info.isLocal | boolean | Optional: When multiple applications are present in root node |
379496 | | | this flag is set to true for the application that the client |
380497 | | | is connected to |
381498 +------------------+------------------------------+---------------------------------------------------------------+
@@ -435,7 +552,7 @@ node.forEachChild(iteratorCallback)
435552 .. code :: javascript
436553
437554 cdpapp .forEachChild (function (child ) {
438- if (child .info ().node_type == studio .protocol .CDPNodeType .CDP_COMPONENT ) {
555+ if (child .info ().nodeType == studio .protocol .CDPNodeType .CDP_COMPONENT ) {
439556 // Use child object of type {INode} that is a CDP component.
440557 }
441558 });
@@ -477,7 +594,7 @@ node.subscribeToValues(valueConsumer, fs, sampleRate)
477594- Usage
478595
479596 Subscribe to value changes on this node. On each value change valueConsumer function is called
480- with value of the nodes value_type and UTC Unix timestamp in nanoseconds (nanoseconds from 01.01.1970).
597+ with value of the nodes valueType and UTC Unix timestamp in nanoseconds (nanoseconds from 01.01.1970).
481598 Timestamp refers to the time of value change in connected application on target controller.
482599
483600- Example
@@ -579,7 +696,7 @@ node.subscribeToEvents(eventConsumer, timestampFrom)
579696 +-------------------+-----------------------------+---------------------------------------------------------------------------------------------------------------------------+
580697 | Event.code | studio.protocol.EventCode | Optional: Event code flags. Any of: |
581698 | | +-----------------------------+---------------------------------------------------------------------------------------------+
582- | | | - eAlarmSet | The alarm's Set flag/state was set. The alarm changed state to "Unack-Set" |
699+ | | | - aAlarmSet | The alarm's Set flag/state was set. The alarm changed state to "Unack-Set" |
583700 | | +-----------------------------+---------------------------------------------------------------------------------------------+
584701 | | | - eAlarmClr | The alarm's Set flag was cleared. The Unack state is unchanged. |
585702 | | +-----------------------------+---------------------------------------------------------------------------------------------+
@@ -591,7 +708,7 @@ node.subscribeToEvents(eventConsumer, timestampFrom)
591708 | | +-----------------------------+---------------------------------------------------------------------------------------------+
592709 | | | - eNodeBoot | The provider reports that the CDPEventNode just have booted. |
593710 +-------------------+-----------------------------+-----------------------------+---------------------------------------------------------------------------------------------+
594- | Event.status | studio.protocol.EventStatus | Optional: Value primitive type the node holds if node may hold a value. Any of : |
711+ | Event.status | studio.protocol.EventStatus | Optional: Status flags as a numeric bitfield. Possible flag values : |
595712 | | +-----------------------------+---------------------------------------------------------------------------------------------+
596713 | | | - eStatusOK | No alarm set |
597714 | | +-----------------------------+---------------------------------------------------------------------------------------------+
0 commit comments