<commit_before>uuid              = require 'node-uuid'
WebSocket         = require 'ws'
{env}             = process
{EventEmitter}    = require 'events'
{Scrubber, Store} = require 'koding-dnode-protocol'
Environment       = require './environment'
{Request, RequestFilter, RequestFilters, AuthenticateFilter} = require './request'
{decrypt} = require './utils'

noop = ->

module.exports = class Client extends EventEmitter
  constructor: (@options={})->
    @localStore = new Store
    @remoteStore = new Store

    @options.name        or= "application"
    @options.port        or= ""
    @options.environment or= new Environment
    @options.api         or= {}

    @environment    = @options.environment
    @kodingKey      = @environment.readKeyFile()
    @uuid           = @options.uuid or uuid.v4()
    @authentication = @options.authentication or type: "kodingKey", key: @kodingKey

    if @options.host? and @options.port?
      @remoteAddr = "ws://#{@options.host}:#{@options.port}/dnode"
    else
      @remoteAddr = @options.url or @environment.kontrolAddress()

    @api = {}

    @handleFunc "heartbeat", (request)->
      [interval, heartbeatCallback] = request.args
      setInterval ()->
        heartbeatCallback()
      , interval * 1000

    @handleFunc "log", (request)->
      console.log ">>> ", request.args

  handleFunc: (name, func)->
    @api[name] = func

  connect: (callback=noop)->
    @ws = new WebSocket @remoteAddr
    client = this
    @ws.on 'open', ()->
      client.emit 'connected'
      callback client

    @ws.on 'message', (data, flags)->
      # now we descrub message and call our callback function
      console.log "received: ", data
      scrubbed = JSON.parse data
      scrubber = new Scrubber client.localStore
      unscrubbed = scrubber.unscrub scrubbed, (callbackId)->
        unless client.remoteStore.has(callbackId)
          client.remoteStore.add callbackId, (args...)->
            client.callRemote callbackId, args

        client.remoteStore.get callbackId

      if client.api.propertyIsEnumerable(scrubbed.method) and 'function' is typeof client.api[scrubbed.method]
        callback = client.api[scrubbed.method]
      else
        callback = client.localStore.get(scrubbed.method)

      if callback
          args = if Array.isArray(unscrubbed) and unscrubbed[0]?.withArgs? then unscrubbed[0].withArgs else unscrubbed
          options =
            localKite: null,
            remoteKite: client,
            method: scrubbed.method,
            args: args,
            username: null, # <-- this will be added by authentication filter
            authentication: null # <-- this doesnt work right now, waiting for change on go side
          request = new Request options
          callback.apply client, [request]

  callRemote: (method, args, callback=noop)=>
    work = ()=>
      scrubber = new Scrubber @localStore
      # adding required stuff
      options = {}
      options.kite =
        id: @uuid
        name: @options.name
        username: @environment.userName()
        environment: @environment.environment()
        region: @environment.region()
        version: @environment.version()
        hostname: @environment.hostname()
        publicIP: "" # <-- we dont have a listening ip/port for a client
        port: @options.port.toString() # <-- port should be string, we dont need a listening ip and port for a client
      options.withArgs = args
      options.authentication = @authentication

      scrubber.scrub [options, callback], =>
        scrubbed = scrubber.toDnodeProtocol()
        scrubbed.method = method
        console.log "sending #{JSON.stringify scrubbed}"
        @ws.send JSON.stringify(scrubbed), (err)->
          if err
            console.log "error while sending data", err

    if @authentication.type is "token"
      # TODO: no need to revalidate in every request
      decryptedToken = JSON.parse decrypt(@authentication.key, @environment.kodingKey())
      validUntil = new Date(decryptedToken.validUntil)
      now = new Date
      if validUntil < now
        # TODO: there must be a getKontrol function
        kontrol = new Client environment: @environment
        kontrol.on 'connected', ()=>
          kontrol.getToken @options.remoteKiteData, (err, token)=>
            @authentication = type: 'token', key: token
            work()
        kontrol.connect()
      else
        work()
    work()

  getToken: (options, callback)->
    @callRemote "getToken", options, (request)->
      [err, token] = request.args
      callback err, token

  getKites: (query={}, callback=noop)->
    # these are query options for getKites, not to be confused with
    # environment options
    # we ask, getKites({name: "mathworker", version: "1"}) so it returns all
    # mathworkers in version 1
    query.environment or= @environment.environment()
    query.hostname    or= ""
    query.id          or= ""
    query.name        or= ""
    query.region      or= ""
    query.username    or= @environment.userName()
    query.version     or= ""

    @callRemote "getKites",
      [query, ()->],
      (request)->
        [err, kites] = request.args
        clients = []
        for kite in request.args[1]
          kiteOptions =
            remoteKiteData: kite.kite<commit_msg>kite: nodejs kite: revalidation of token should be a while before its expired<commit_after>uuid              = require 'node-uuid'
WebSocket         = require 'ws'
{env}             = process
{EventEmitter}    = require 'events'
{Scrubber, Store} = require 'koding-dnode-protocol'
Environment       = require './environment'
{Request, RequestFilter, RequestFilters, AuthenticateFilter} = require './request'
{decrypt} = require './utils'

noop = ->

module.exports = class Client extends EventEmitter
  constructor: (@options={})->
    @localStore = new Store
    @remoteStore = new Store

    @options.name        or= "application"
    @options.port        or= ""
    @options.environment or= new Environment
    @options.api         or= {}

    @environment    = @options.environment
    @kodingKey      = @environment.readKeyFile()
    @uuid           = @options.uuid or uuid.v4()
    @authentication = @options.authentication or type: "kodingKey", key: @kodingKey

    if @options.host? and @options.port?
      @remoteAddr = "ws://#{@options.host}:#{@options.port}/dnode"
    else
      @remoteAddr = @options.url or @environment.kontrolAddress()

    @api = {}

    @handleFunc "heartbeat", (request)->
      [interval, heartbeatCallback] = request.args
      setInterval ()->
        heartbeatCallback()
      , interval * 1000

    @handleFunc "log", (request)->
      console.log ">>> ", request.args

  handleFunc: (name, func)->
    @api[name] = func

  connect: (callback=noop)->
    @ws = new WebSocket @remoteAddr
    client = this
    @ws.on 'open', ()->
      client.emit 'connected'
      callback client

    @ws.on 'message', (data, flags)->
      # now we descrub message and call our callback function
      console.log "received: ", data
      scrubbed = JSON.parse data
      scrubber = new Scrubber client.localStore
      unscrubbed = scrubber.unscrub scrubbed, (callbackId)->
        unless client.remoteStore.has(callbackId)
          client.remoteStore.add callbackId, (args...)->
            client.callRemote callbackId, args

        client.remoteStore.get callbackId

      if client.api.propertyIsEnumerable(scrubbed.method) and 'function' is typeof client.api[scrubbed.method]
        callback = client.api[scrubbed.method]
      else
        callback = client.localStore.get(scrubbed.method)

      if callback
          args = if Array.isArray(unscrubbed) and unscrubbed[0]?.withArgs? then unscrubbed[0].withArgs else unscrubbed
          options =
            localKite: null,
            remoteKite: client,
            method: scrubbed.method,
            args: args,
            username: null, # <-- this will be added by authentication filter
            authentication: null # <-- this doesnt work right now, waiting for change on go side
          request = new Request options
          callback.apply client, [request]

  callRemote: (method, args, callback=noop)=>
    work = ()=>
      scrubber = new Scrubber @localStore
      # adding required stuff
      options = {}
      options.kite =
        id: @uuid
        name: @options.name
        username: @environment.userName()
        environment: @environment.environment()
        region: @environment.region()
        version: @environment.version()
        hostname: @environment.hostname()
        publicIP: "" # <-- we dont have a listening ip/port for a client
        port: @options.port.toString() # <-- port should be string, we dont need a listening ip and port for a client
      options.withArgs = args
      options.authentication = @authentication

      scrubber.scrub [options, callback], =>
        scrubbed = scrubber.toDnodeProtocol()
        scrubbed.method = method
        console.log "sending #{JSON.stringify scrubbed}"
        @ws.send JSON.stringify(scrubbed), (err)->
          if err
            console.log "error while sending data", err

    if @authentication.type is "token"
      # TODO: no need to revalidate in every request
      decryptedToken = JSON.parse decrypt(@authentication.key, @environment.kodingKey())
      validUntil = new Date(decryptedToken.validUntil)
      now = new Date
      tokenTtl = (validUntil - new Date(now)) - 2000
      if tokenTtl < 0
        # TODO: there must be a getKontrol function
        kontrol = new Client environment: @environment
        kontrol.on 'connected', ()=>
          kontrol.getToken @options.remoteKiteData, (err, token)=>
            @authentication = type: 'token', key: token
            work()
        kontrol.connect()
      else
        work()
    else
      work()

  getToken: (options, callback)->
    @callRemote "getToken", options, (request)->
      [err, token] = request.args
      callback err, token

  getKites: (query={}, callback=noop)->
    # these are query options for getKites, not to be confused with
    # environment options
    # we ask, getKites({name: "mathworker", version: "1"}) so it returns all
    # mathworkers in version 1
    query.environment or= @environment.environment()
    query.hostname    or= ""
    query.id          or= ""
    query.name        or= ""
    query.region      or= ""
    query.username    or= @environment.userName()
    query.version     or= ""

    @callRemote "getKites",
      [query, ()->],
      (request)->
        [err, kites] = request.args
        clients = []
        for kite in request.args[1]
          kiteOptions =
            remoteKiteData: kite.kite
{'fraction_non_alphanumeric': 0.11338185890257559, 'fraction_numerical': 0.0023329600597237774, 'mean_word_length': 2.4327354260089686, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5386604', 'n_tokens_mistral': 3022, 'n_tokens_neox': 2987, 'n_words': 855}