WComorSocketioClient.mjs

import SocketIOClient from 'socket.io-client'
import get from 'lodash-es/get.js'
import set from 'lodash-es/set.js'
import genPm from 'wsemi/src/genPm.mjs'
import genID from 'wsemi/src/genID.mjs'
import Evem from 'wsemi/src/evem.mjs'
import j2o from 'wsemi/src/j2o.mjs'
import isfun from 'wsemi/src/isfun.mjs'


/**
 * 建立SocketIO使用者(Node.js與Browser)端物件
 *
 * @param {Object} opt 輸入設定參數物件
 * @param {String} [opt.url='http://localhost:8080'] 輸入SocketIO伺服器網址,預設為'http://localhost:8080'
 * @param {String} [opt.token='*'] 輸入使用者認證用token,預設為'*'
 * @param {Object} [opt.ioSettings={}] 輸入SocketIO初始化設定物件,預設為{}
 * @param {Function} opt.open 輸入監聽open函數
 * @param {Function} opt.close 輸入監聽close函數
 * @param {Function} opt.error 輸入監聽error函數
 * @param {Function} opt.reconn 輸入監聽reconn函數
 * @returns {Promise} 回傳Promise,resolve為映射伺服器端可用函數之物件,各函數輸入皆為單一物件,各函數回傳皆為Promise,用resolve與reject處理回傳結果
 * @example
 *
 * import WComorSocketioClient from 'w-comor-socketio/dist/w-comor-socketio-client.umd.js'
 *
 * //opt
 * let opt = {
 *     url: 'http://localhost:8080',
 *     token: '*',
 *     open: function() {
 *         console.log('client nodejs: open')
 *     },
 *     close: function() {
 *         console.log('client nodejs: close')
 *     },
 *     error: function(err) {
 *         console.log('client nodejs: error:', err)
 *     },
 *     reconn: function() {
 *         console.log('client nodejs: reconn')
 *     },
 * }
 *
 * //WComorSocketioClient
 * new WComorSocketioClient(opt)
 *     .then(function(wo) {
 *         console.log('client: funcs: ', wo)
 *
 *         function core(ps) {
 *             wo.group.plus(ps)
 *                 .then(function(r) {
 *                     console.log('client: plus(' + JSON.stringify(ps) + ')=' + r)
 *                 })
 *                 .catch(function(err) {
 *                     console.log('client: plus: catch: ', err)
 *                 })
 *             wo.group.div(ps)
 *                 .then(function(r) {
 *                     console.log('client: div(' + JSON.stringify(ps) + ')=' + r)
 *                 })
 *                 .catch(function(err) {
 *                     console.log('client: div: catch: ', err)
 *                 })
 *             wo.add(ps)
 *                 .then(function(r) {
 *                     console.log(`client: add(${JSON.stringify(ps)})=${r}`)
 *                 })
 *                 .catch(function(err) {
 *                     console.log('client: add: catch: ', err)
 *                 })
 *             wo.minu(ps)
 *                 .then(function(r) {
 *                     console.log(`client: minu(${JSON.stringify(ps)})=${r}`)
 *                 })
 *                 .catch(function(err) {
 *                     console.log('client: minu: catch: ', err)
 *                 })
 *         }
 *
 *         let i = 100
 *         setInterval(function() {
 *             i += 1
 *             core({
 *                 p1: i,
 *                 p2: 10,
 *             })
 *         }, 1000)
 *
 *     })
 *     .catch(function(err) {
 *         console.log('client: catch', err)
 *     })
 *
 */
function WComorSocketioClient(opt) {
    let pm = genPm()
    let ioc = null //socket.io
    let wo = {} //回傳操作物件


    //ev
    let ev = new Evem()


    function core() {


        //default
        if (!opt.url) {
            opt.url = 'http://localhost:8080'
        }
        if (!opt.token) {
            opt.token = '*'
        }
        if (!opt.ioSettings) {
            opt.ioSettings = {} //若伺服器有反向代理, 得設定{ path: '反向代理子路徑' }, 例如'/HLW/SSO/'
        }


        //socket.io-client
        try {
            ioc = new SocketIOClient(opt.url, opt.ioSettings)
        }
        catch (err) {
            console.log('create SocketIOClient error', err)
            return null
        }


        //execFunction
        function execFunction(func, input = null) {
            let pmm = genPm()

            //_id
            let _id = genID()

            //msg
            let msg = {
                token: opt.token,
                _id,
                func,
                input,
            }

            //send
            try {
                ioc.send(JSON.stringify(msg), function(err) {
                    if (err) {
                        if (isfun(opt.error)) {
                            opt.error(err)
                        }
                    }
                })
            }
            catch (err) {
                if (isfun(opt.error)) {
                    opt.error(err)
                }
            }

            //等待結果回傳
            ev.on(_id, function (output) {

                //resolve
                pmm.resolve(output)

                //removeAllListeners
                ev.removeAllListeners(_id)

            })

            return pmm
        }


        //connect
        function fConnect() {
            if (isfun(opt.open)) {
                opt.open()
            }
            execFunction('getFuncs', null)
        }
        ioc.on('connect', fConnect)


        //fMessage
        function fMessage(message) {

            //data
            let data = j2o(message)

            //get sys funcs
            if (get(data, 'output.sys') === 'sys' && get(data, 'output.funcs')) {

                //funcs
                let funcs = data['output']['funcs']

                //clear wo
                wo = {}

                //bind funcs
                for (let i = 0; i < funcs.length; i++) {

                    //func
                    let func = funcs[i]

                    //add func
                    let f = function(input) {
                        return execFunction(func, input)
                    }
                    set(wo, func, f)

                }

                //resolve
                pm.resolve(wo)

            }

            //get result
            if (get(data, '_id') && get(data, 'output')) {

                //_id
                let _id = get(data, '_id')

                //output
                let output = get(data, 'output')

                //emit
                ev.emit(_id, output)

            }

        }
        ioc.on('message', fMessage)


        //fClose
        function fClose() {
            if (isfun(opt.close)) {
                opt.close()
            }
        }
        ioc.on('disconnect', fClose)


        //fReconnect
        function fReconnect() {
            if (isfun(opt.reconn)) {
                opt.reconn()
            }
        }
        ioc.on('reconnect', fReconnect)


        //fError
        function fError(err) {
            if (isfun(opt.error)) {
                opt.error(err)
            }
        }
        ioc.on('error', fError)


    }


    //core
    core()


    return pm
}


export default WComorSocketioClient