Jump To …

clients.coffee

protocol = require './protocol'
utils    = require './utils'
crypto   = require 'crypto'

class ClientBase extends utils.PubSub
    constructor: (@options = {}) ->
        super
        do @handleOptions
        @debug 'ClientBase::constructor'
        do @setupConnect
        do @setupClient

    debug: (args...) =>
        @options.logFn   "#{@constructor.name}> ", args... if @options.debug

    verbose: (args...) =>
        @options.logFn   "#{@constructor.name}> ", args... if @options.verbose

    handleOptions: =>
        @options.logFn    ?= console.log
        @options.verbose  ?= false
        @options.debug    ?= false
        @options.login    ?= process.env.USER
        @options.location ?= require('os').hostname() || '-'
        @options.agent    ?= 'node-netsoul'
        if not @options.password?
            throw new Error 'password is not specified'
        if not @options.nsconnect?
            throw new Error 'nsconnect is not specified'
        @ns = @options.nsconnect
        @debug 'ClientBase::handleOptions', @options

    setupClient: =>
        @debug 'ClientBase::setupClient'

    setupConnect: =>
        @debug 'ClientBase::setup'
        @ns.on 'connect',    @onConnect
        @ns.on 'message',    @onMessage
        @ns.on 'error',      @onError
        @ns.on 'disconnect', @onDisconnect

nsconnect wrappers

    connect: =>
        @debug 'ClientBase::connect'
        do @ns.connect

    send: (data) =>
        @verbose 'ClientBase::send', data.join(' ')
        @ns.send data

nsconnect handlers

    onDisconnect: =>
        @debug 'ClientBase::onDisconnect'

    onMessage: (message) =>
        @verbose 'ClientBase::onMessage', message.line
        if message.type?
            handlerName = "message_#{message.type}"
            @debug "ClientBase::onMessage, type=#{handlerName}"
            @emit handlerName, message
            if @[handlerName]?
                @[handlerName] message

    onError: (error) =>
        @debug 'ClientBase::onError', error

    onConnect: =>
        @debug 'ClientBase::onConnect'

client handlers

class ClientAuth extends ClientBase
    setupClient: =>
        super
        @debug "ClientAuth::setupClient"
        @authenticated = false
        @auth_step = 0

    message_salut: (message) =>
        @debug "ClientAuth::message_salut", message.line
        @handshake = message.split
        @send ['auth_ag', 'ext_user', 'none', 'none']

    message_rep: (message) =>
        code = message.split[1]
        if not @authenticated
            if @auth_step is 0
                do @readyForHandshake
            if @auth_step is 1
                do @handshakeAccepted
            @auth_step++

    readyForHandshake: =>
        concat    = "#{@handshake[2]}-#{@handshake[3]}/#{@handshake[4]}#{@options.password}"
        login     = @options.login
        hash      = crypto.createHash('md5').update(concat).digest("hex")
        agent     = encodeURIComponent @options.agent
        location  = encodeURIComponent @options.location
        @debug "ClientAuth::message_salut", "login=#{login}, concat=#{concat}, hash=#{hash}, location=#{location}, agent=#{agent}"
        @send ['ext_user_log', login, hash, agent, location]

    handshakeAccepted: =>
        @debug "ClientAuth::handshakeAccepted"
        @authenticated = true
        @emit 'authenticate'

    message_ping: (message) =>
        @debug "ClientAuth::message_pong", message
        @send message.split

class ClientDaemon extends ClientAuth
    setupClient: ->
        super
        @debug "ClientDaemon::setupClient"
        @on 'authenticate', =>
            @send ['user_cmd', 'state', 'actif']

module.exports =
    base:       ClientBase
    auth:       ClientAuth
    daemon:     ClientDaemon