Source: src/server.js

/**
 * NanoMemoTools.server module
 * @module NanoMemoTools/server
 */

const network = require('./network.js');
const Memo = require('./memo.js');
let SERVER = 'https://nanomemo.cc';
let WSS = 'wss://nanomemo.cc';

/**
* This function gathers user data from the server
* @public
* @param {string} [api_key=undefined] user public api key; if undefined uses IP rate limiting
* @param {string} [api_secret=undefined] user private secret key; if undefined uses IP rate limiting
* @param {string} [endpoint=/api/user/] endpoint of POST request
* @returns {Promise} Promise object represents the user data as an object
*/
const getUserData = async function(api_key=undefined, api_secret=undefined, endpoint='/api/user') {
    
    const data = {
        api_key: api_key,
        api_secret: api_secret
    }
    return network.post(SERVER + endpoint, data);
}

/**
* This function gathers a memo's data from the server
* @public
* @param {array} hashes array of 64-hex hash that represents a Nano Block
* @param {string} [server=SERVER] server to POST
* @param {string} [endpoint=/api/memo/blocks/] endpoint of POST request
* @returns {Promise} Promise object represents array of Memo objectsthe memo object 
*/
const getMemos = async function(hashes, server=SERVER, endpoint='/api/memo/blocks/') {

    let response = await network.post(server + endpoint, {
        hashes: hashes
    });
    if (response === undefined || response === null) {
        return {
            success: false,
            dtg: new Date(),
            error: 'No response returned'
        }
    }
    if (response.error !== undefined) return response;

    // Create Memo objects
    let memos = [];
    for (let memo_data of response.data) {
        let memo = undefined;
        if (memo_data.version_encrypt !== undefined) {
            // Yes, encrypted
            memo = new Memo.EncryptedMemo(
                memo_data.hash,
                memo_data.message,
                memo_data.signing_address,
                memo_data.decrypting_address,
                memo_data.signature,
                memo_data.version_sign,
                memo_data.version_encrypt
            );
        } else {
            // No, not encrypted
            memo = new Memo.Memo(
                memo_data.hash,
                memo_data.message,
                memo_data.signing_address,
                memo_data.signature,
                memo_data.version_sign
            );
        }

        // Validate signature locally
        if (!memo.valid_signature) {
            console.error('In NanoMemoTools.server.getMemos, memo signature validation failed for hash '+ memo.hash);
            continue;
        }

        memos.push(memo);
    }

    return memos;
}

/**
* This function saves a memo to the server
* @public
* @param {Memo.Memo} memo memo data to be saved to the server
* @param {string} api_key public api key
* @param {string} api_secret private api key
* @param {string} [server=SERVER] server to POST
* @param {string} [endpoint=/api/memo/new/] endpoint of POST request
* @returns {Promise} Promise object represents the memo object 
*/
const saveMemo = async function(memo, api_key, api_secret, server=SERVER, endpoint='/api/memo/new') {

    if (!memo.valid_signature) {
        console.error('Memo has an invalid signature');
        return {
            success: false,
            dtg: new Date(),
            error: 'Memo has an invalid signature'
        }
    }

    console.log(server + endpoint);

    const response = await network.post(server + endpoint, {
        api_key: api_key,
        api_secret: api_secret,
        message: memo.message,
        hash: memo.hash,
        signing_address: memo.signing_address,
        decrypting_address: memo.decrypting_address,
        signature: memo.signature,
        version_sign: memo.version_sign,
        version_encrypt: memo.version_encrypt
    });

    return response;
}

/**
 * This function subscribes to a NanoMemo websocket that will send a message for each new memo that is saved
 * @public
 * @param {function} onmessage function to call with newly received memo data
 * @returns {websocket} websocket object 
 */
const websocketSubscribe = async function(onmessage) {
    const websocket = network.websocket(
        WSS,
        function(ws) {
            // onopen
            console.log('Connected to websocket server: '+ WSS);
            const data = {
                "action": "subscribe"
            }
            ws.send(JSON.stringify(data));
        },
        function(ws, message) {
            // onmessage
            console.log('Websocket message received from: '+ WSS);
            let data = undefined;
            try {
                data = JSON.parse(message.data);
            } catch(e) {
                console.error('Error parsing data into Object: '+ message.data);
            }
            onmessage(data);
        },
        function(ws) {
            // onclose
            console.log('Closed connection to websocket server: '+ WSS);
        },
        function(ws, e) {
            // onerror
            console.error(e);
        }
    );

    return websocket;
}

/**
 * This function unsubscribes to a NanoMemo websocket that was receiving new memos
 * @public
 * @returns undefined
 */
const websocketUnsubscribe = async function() {
    if (websocket === undefined) return;
    const data = {
        "action": "unsubscribe"
    }
    websocket.send(JSON.stringify(data));
}

module.exports = {
    getUserData,
    getMemos,
    saveMemo,
    websocketSubscribe,
    websocketUnsubscribe,
}