uchcode
8/30/2017 - 11:24 PM

nodejs eventemitter example

nodejs eventemitter example

class StdioEmitter {
    constructor(encoding='utf8') {
        this.EVENT = {
          DEFAULT : Symbol(),
          ALL     : Symbol(),
        }
        this.encoding = encoding
        this.emitter = new (require('events').EventEmitter)()
        this._event_all_listener = undefined
        this._regexp_listener_dictionary = {}
        this._base_listener = (data) => {
            if (Object.prototype.toString.call(data).slice(8,-1).toLowerCase() != 'string') {
                return
            }
            try {
                let d = JSON.parse(data.trim())
                if (!this.emitter.emit(d.eventName, d.data)) {
                    this.emitter.emit(this.EVENT.DEFAULT, d.data)
                }
            } catch(e) {
                let d = data.replace(/\n$/,'')
                if (!this.emitter.emit(d, data)) {
                    this.emitter.emit(this.EVENT.DEFAULT, data)
                }
            }
        }
        process.stdin.on('data', this._base_listener)
    }
    on(eventName, listener) {
        switch(eventName) {
        case this.EVENT.ALL:
            if (this._event_all_listener) {
                throw new Error(`on(): already regist. EVENT.ALL.`)
            }
            process.stdin.on('data', listener)
            this._event_all_listener = listener
            break
        default:
            let type = Object.prototype.toString.call(eventName).slice(8,-1).toLowerCase()
            if (type == 'regexp') {
                if (this._regexp_listener_dictionary[eventName]) {
                    throw new Error(`on(): already regist. RegExp: ${eventName}`)
                }
                process.stdin.on('data', listener)
                this._regexp_listener_dictionary[eventName] = listener
            } else {
                this.emitter.on(eventName, listener)
            }
            break
        }
    }
    off(eventName, listener) {
        switch(eventName) {
        case this.EVENT.ALL:
            if (this._event_all_listener) {
                process.stdin.removeListener('data', this._event_all_listener)
                this._event_all_listener = undefined
            }
            break
        default:
            let type = Object.prototype.toString.call(eventName).slice(8,-1).toLowerCase()
            if (type == 'regexp') {
                process.stdin.removeListener('data', listener)
                if (this._regexp_listener_dictionary[eventName] == listener) {
                    delete this._regexp_listener_dictionary[eventName]
                }
            } else {
                this.emitter.removeListener(eventName, listener)
            }
            break
        }
    }
    offAll(eventName) {
        switch(eventName) {
        case this.EVENT.ALL:
            if (this._event_all_listener) {
                process.stdin.removeListener('data', this._event_all_listener)
                this._event_all_listener = undefined
            }
            break
        default:
            let type = Object.prototype.toString.call(eventName).slice(8,-1).toLowerCase()
            if (type == 'regexp') {
                let listener = this._regexp_listener_dictionary[eventName]
                if (listener) {
                    process.stdin.removeListener('data', listener)
                    delete this._regexp_listener_dictionary[eventName]
                }
            } else {
                this.emitter.removeAllListeners(eventName)
            }
            break
        }
    }
    removeListener(eventName, listener) {
        this.off(eventName, listener)
    }
    removeAllListeners(eventName) {
        this.offAll(eventName)
    }
    once(eventName, listener) {
        this.emitter.once(eventName, listener)
    }
    emit(data, argument='') {
        switch(data) {
        case this.EVENT.DEFAULT:
            this.emitter.emit(this.EVENT.DEFAULT, argument)
            break
        default:
            process.stdin.emit('data', data)
            break
        }
    }
    regexp(eventName, listener) {
        return [eventName, (data) => {
            try {
                let d = data.replace(/\n$/,'')
                if ( eventName.test(d) ) {
                    listener(data)
                }
            } catch(e) {
                //console.log(e)
            }
        }]
    }
    set encoding(e) {
        process.stdin.setEncoding(e)
        process.stdout.setEncoding(e)
        process.stderr.setEncoding(e)
    }
    get encoding() {
        return process.stdin._readableState.encoding
    }
}

///////////////////////////////////////////

function output(data, terminator='\n') {
    process.stdout.write(data + terminator)
}
function error(data, terminator='\n') {
    process.stderr.write(data + terminator)
}

answer = Math.floor( Math.random() * (100) )

rule = new StdioEmitter()

EVENT = rule.EVENT

rule.on(answer.toString(), () => {
    output(`正解!! ${answer}`)
    process.exit(0)
})

rule.on('', () => {
    error('ゲームを中止しました。')
    error(`答えは ${answer} でした。`)
    process.exit(1)
})

rule.once('hint', () => {
    if (answer > 50) {
        output('答えは50より大きいです')
    } else {
        output('答えは50以下です')
    }
})

rule.on(...rule.regexp( /[^0-9]+/, (data) => {
    if (data.trim() == 'hint') {
        output('hintは一回だけ!')
    } else {
        error('半角数字の正数でお願いします')
    }
}))

rule.on(EVENT.DEFAULT, (data) => {
    let d = data.trim()
    if (d > 100 || d <= 0) {
        output(`答えは 1 〜 100 の間で!`)
    } else if (d > answer) {
        output(`${d}は大きい`)
    } else if (d < answer) {
        output(`${d}は小さい`)
    }
})

rule.on(EVENT.ALL, (data) => {
    output('答え:', '')
})

output('数当てゲーム!!')
output('1 〜 100 の間の整数を当ててください')
rule.emit(EVENT.ALL)