Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website

node-mango-client to update datasource properties on Mango 2.8


  • Hi,
    I want try to use node-mango-client to update some Mango 2.8 datasource properties from outside Mango user interface. Mango instance is running on a RPI3B+.

    To achieve this I've done the following:

    sudo apt install -y nodejs
    node -v
    v8.11.1
    
    sudo apt install npm
    npm -v
    1.4.21
    (node:4528) [DEP0022] DeprecationWarning: os.tmpDir() is deprecated. Use os.tmpdir() instead.
    
    
    cd /home/solergy/MANGO/NODE-JS/
    npm install mango-client --save
    (node:2363) [DEP0022] DeprecationWarning: os.tmpDir() is deprecated. Use os.tmpdir() instead.
    mango-client@0.4.0 node_modules/mango-client
    ├── uuid@3.1.0
    ├── moment-timezone@0.5.27
    └── moment@2.24.0
    

    after this I've tried this little sample:

    const MangoClient = require('mango-client');
    
    const client = new MangoClient({
        protocol: 'http',
        host: 'localhost',
        port: 8810,
        rejectUnauthorized: false
    });
    
    const DataPoint = client.DataPoint;
    const User = client.User;
    
    
    User.login('myUsername', 'myPassword').then(data => {
        console.log(`Logged in as '${data.username}'.`);
        return DataPoint.getValue('internal_mango_num_data_points');
    }).then(data => {
        console.log(`There are ${data.value} data points.`);
    
        // you can perform any arbitrary rest request like this
        return client.restRequest({
            path: '/rest/v1/data-points/internal_mango_num_data_points',
            method: 'GET',
            //data: {object}
        });
    }).then(response => {
        console.log(`The data point's name is '${response.data.name}'`);
    });
    

    it is the same descripted here:
    https://github.com/infiniteautomation/node-mango-client

    but I've the following error:

    solergy@Tracker_0-1:~/MANGO/NODE-JS/node_modules/mango-client $ node example.js
    (node:4926) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected token < in JSON at position 3
        at JSON.parse (<anonymous>)
        at IncomingMessage.response.on (/home/solergy/MANGO/NODE-JS/node_modules/mango-client/src/mangoClient.js:183:62)
        at emitNone (events.js:111:20)
        at IncomingMessage.emit (events.js:208:7)
        at endReadableNT (_stream_readable.js:1064:12)
        at _combinedTickCallback (internal/process/next_tick.js:138:11)
        at process._tickCallback (internal/process/next_tick.js:180:9)
    (node:4926) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
    (node:4926) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    

    any idea about where's the problem?


  • I took at look at it is because the node client uses the REST V2 APIs to log in and they are not available on Mango 2.8. The actual error is because Mango 2.8 incorrectly returns the HTML error page instead of a JSON error response.

    I had a play with manually using client.restRequest() to login but that will not work either due to the CSRF protection changing.

    Otherwise this would work I would think...

    const MangoClient = require('@infinite-automation/mango-client');
    
    const client = new MangoClient({
        protocol: 'http',
        host: 'localhost',
        port: 8080,
        rejectUnauthorized: false
    });
    
    const DataPoint = client.DataPoint;
    const User = client.User;
    
    const username = 'admin';
    const password = 'admin';
    
    client.restRequest({
        path: `/rest/v1/login/${username}`,
        method: 'POST',
        params: {password}
    }).then(response => {
        const data = response.data;
        console.log(`Logged in as '${data.username}'.`);
        return DataPoint.getValue('internal_mango_num_data_points');
    }).then(data => {
        console.log(`There are ${data.value} data points.`);
    
        // you can perform any arbitrary rest request like this
        return client.restRequest({
            path: '/rest/v1/data-points/internal_mango_num_data_points',
            method: 'GET',
            //data: {object}
        });
    }).then(response => {
        console.log(`The data point's name is '${response.data.name}'`);
    });
    

  • It seems there's still some problem:

    solergy@Tracker_0-1:~/MANGO/NODE-JS/node_modules/mango-client $ node example.js
    (node:3790) UnhandledPromiseRejectionWarning: Error: Mango HTTP error - 403 Forbidden
        at IncomingMessage.response.on (/home/solergy/MANGO/NODE-JS/node_modules/mango-client/src/mangoClient.js:194:35)
        at emitNone (events.js:111:20)
        at IncomingMessage.emit (events.js:208:7)
        at endReadableNT (_stream_readable.js:1064:12)
        at _combinedTickCallback (internal/process/next_tick.js:138:11)
        at process._tickCallback (internal/process/next_tick.js:180:9)
    (node:3790) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
    (node:3790) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    

  • @jared-wiltshire said in node-mango-client to update datasource properties on Mango 2.8:

    I had a play with manually using client.restRequest() to login but that will not work either due to the CSRF protection changing.
    Otherwise this would work I would think...

    ^ as I said CSRF has changed since 2.8.


  • OK, thanks anyway, I will search for a different approach to change datasource properties from outside Mango 2.8. I've tried to read the blob with the following python script:

    #!/usr/bin/python3
    
    import pymysql
    import json
    
    def write_file(data, filename):
        with open(filename, 'wb') as f:
            f.write(data)
    
    
    def read_blob(filename):
        # select photo column of a specific author
        query = "SELECT data FROM mangoTerlizzi.dataSources where xid='FML01-main'"
    
        try:
            # Open database connection
            db = pymysql.connect("localhost","user","pwd","mangoTerlizzi" )
    
            # prepare a cursor object using cursor() method
            cursor = db.cursor()
    
            # execute SQL query using execute() method.
            cursor.execute(query)
            
            # Fetch a single row using fetchone() method.
            data = cursor.fetchone()[0]
      
            # write blob data into a file
            write_file(data, filename)
            
            with open(filename) as json_file:
              data = json.load(json_file)
       
        except Error as e:
            print(e)
     
        finally:
            cursor.close()
            db.close()
            
                    
    
    read_blob("datasourceDescription.json")
    

    but maybe it is not all the stuff, in fact I've the following error:

    solergy@Tracker_0-1:~ $ python3 dbConnection.py
    Traceback (most recent call last):
      File "dbConnection.py", line 34, in read_blob
        data = json.load(json_file)
      File "/usr/lib/python3.5/json/__init__.py", line 265, in load
        return loads(fp.read(),
      File "/usr/lib/python3.5/codecs.py", line 321, in decode
        (result, consumed) = self._buffer_decode(data, self.errors, final)
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xac in position 0: invalid start byte
    

  • At the end I choose to use a scripting datasource to update datasource properties:

    var dsvoMain = com.serotonin.m2m2.db.dao.DataSourceDao.instance.getByXid("FML01-main");
        dsvoMain.host = "172.16.0.12";
        com.serotonin.m2m2.db.dao.DataSourceDao.instance.saveDataSource(dsvoMain);
    

    and the same for the publisher:

    var voPublisher = com.serotonin.m2m2.db.dao.PublisherDao.instance.getByXid("Pub_TRK-0.1")
        voPublisher.port              = "8811";
        com.serotonin.m2m2.db.dao.PublisherDao.instance.savePublisher(voPublisher);
    

    but I can't update instead systemSettings,
    I've tried with the following:

    com.serotonin.m2m2.db.dao.SystemSettingsDao.setValue("emailFromName", "Etantonio");
    

    but the result is:

    0_1572511885915_c97ce613-c790-42db-ab07-72ec0ef03a57-immagine.png

    but the method seems to be there in

    https://github.com/infiniteautomation/ma-core-public/blob/2.8.x/Core/src/com/serotonin/m2m2/db/dao/SystemSettingsDao.java

    0_1572511990311_1ce1aedf-d313-4853-bcbe-f25636247fd2-immagine.png

    do you have an idea about where's the problem?

    And also, there's a similar way to update excelReport properties on table excelReportTemplates?

    Thanks, Antonio


  • @etantonio it looks like you have a syntax error. The other dao classes have a static instance member to access the methods but this dao is different in Mango 2.8,

    The method you are using is not static so you need to first get a reference to the created dao. I believe there is a DaoRegistry class you may be able to use. Just be careful and make sure you understand why some methods are static and others are not.


  • yes, you're right, the following code it's ok. thanks,

    var ssdao = new com.serotonin.m2m2.db.dao.SystemSettingsDao();
       ssdao.setValue("emailFromName", "Etantonio");
    

    instead for excelReport:

    var voExcelReport = com.infiniteautomation.mango.excelreports.dao.ExcelReportTemplateDao.instance.getByXid("My_DailyReport")
    voExcelReport.setName("Etantonio")
    com.infiniteautomation.mango.excelreports.dao.ExcelReportTemplateDao.instance.save(voExcelReport);  
    

    Antonio