         if DEBUG
             console.log("handle_json_data: #{data}")
         switch mesg.event
-            when "execute_javascript"
-                if mesg.session_uuid?
-                    @_sessions[mesg.session_uuid].emit("execute_javascript", mesg)
-                else
-                    @emit("execute_javascript", mesg)
-
-            when "output"
-                cb = @execute_callbacks[mesg.id]
-                if cb?
-                    cb(mesg)
-                    delete @execute_callbacks[mesg.id] if mesg.done
-                if mesg.session_uuid?  # executing in a persistent session
-                    @_sessions[mesg.session_uuid].emit("output", mesg)
-                else   # stateless exec
-                    @emit("output", mesg)
-
-            when "terminate_session"
-                session = @_sessions[mesg.session_uuid]
-                session?.emit("close")
-
-            when "session_reconnect"
-                if mesg.data_channel?
-                    @_sessions[mesg.data_channel]?.reconnect()
-                else if mesg.session_uuid?
-                    @_sessions[mesg.session_uuid]?.reconnect()
-
             when "cookies"
                 @_cookies?(mesg)
 

# if there is no response to an operation after this amount of time.
DEFAULT_TIMEOUT = 30  # in seconds


class Session extends EventEmitter
    # events:
    #    - 'open'   -- session is initialized, open and ready to be used
    #    - 'close'  -- session's connection is closed/terminated
    #    - 'execute_javascript' -- code that server wants client to run related to this session
    constructor: (opts) ->
        super()
        opts = defaults opts,
            conn         : required     # a Connection instance
            project_id   : required
            session_uuid : required
            params       : undefined
            data_channel : undefined    # optional extra channel that is used for raw data
            init_history : undefined    # used for console

        @start_time   = misc.walltime()
        @conn         = opts.conn
        @params       = opts.params
        if @type() == 'console'
            if not @params?.path? or not @params?.filename?
                throw Error("params must be specified with path and filename")
        @project_id   = opts.project_id
        @session_uuid = opts.session_uuid
        @data_channel = opts.data_channel
        @init_history = opts.init_history
        @emit("open")

        ## This is no longer necessary; or rather, it's better to only
        ## reset terminals, etc., when they are used, since it wastes
        ## less resources.
        # I'm going to leave this in for now -- it's only used for console sessions,
        # and they aren't properly reconnecting in all cases.
        if @reconnect?
            @conn.on("connected", @reconnect)

    close: () =>
        @removeAllListeners()
        if @reconnect?
            @conn.removeListener("connected", @reconnect)

    reconnect: (cb) =>
        # Called when the connection gets dropped, then reconnects
        if not @conn._signed_in
            setTimeout((()=>@reconnect(cb)), 500)
            return

        if @_reconnect_lock
            #console.warn('reconnect: lock')
            cb?("reconnect: hit lock")
            return

        @emit "reconnecting"
        @_reconnect_lock = true
        #console.log("reconnect: #{@type()} session with id #{@session_uuid}...")
        f = (cb) =>
            @conn.call
                allow_post : false
                message : message.connect_to_session
                    session_uuid : @session_uuid
                    type         : @type()
                    project_id   : @project_id
                    params       : @params
                timeout : 30
                cb      : (err, reply) =>
                    if err
                        cb(err); return
                    switch reply.event
                        when 'error'
                            cb(reply.error)
                        when 'session_connected'
                            #console.log("reconnect: #{@type()} session with id #{@session_uuid} -- SUCCESS", reply)
                            if @data_channel != reply.data_channel
                                @conn.change_data_channel
                                    prev_channel : @data_channel
                                    new_channel  : reply.data_channel
                                    session      : @
                            @data_channel = reply.data_channel
                            @init_history = reply.history
                            cb()
                        else
                            cb("bug in hub")
        misc.retry_until_success
            max_time : 15000
            factor   : 1.3
            f        : f
            cb       : (err) =>
                #console.log("reconnect('#{@session_uuid}'): finished #{err}")
                delete @_reconnect_lock
                if not err
                    @emit("reconnect")
                cb?(err)

    terminate_session: (cb) =>
        @conn.call
            message :
                message.terminate_session
                    project_id   : @project_id
                    session_uuid : @session_uuid
            timeout : 30
            cb      : cb

    walltime: () =>
        return misc.walltime() - @start_time

    handle_data: (data) =>
        @emit("data", data)

    write_data: (data) =>
        @conn.write_data(@data_channel, data)

    restart: (cb) =>
        @conn.call(message:message.restart_session(session_uuid:@session_uuid), timeout:10, cb:cb)


###
#
# A Console session, which connects the client to a pty on a remote machine.
#
#   Client <-- (primus) ---> Hub  <--- (tcp) ---> console_server
#
###

class ConsoleSession extends Session
    type: () => "console"




class exports.Connection extends EventEmitter
    # Connection events:
    #    - 'connecting' -- trying to establish a connection

        @_signed_in = false
        @_redux?.getActions('account')?.set_user_type('public')

    register_data_handler: (channel, h) ->
        @_data_handlers[channel] = h

