<commit_before>{ argv } = require 'optimist'

koding = require './bongo'

opsview = require 'koding-opsview-wrapper'

parseServiceKey = require 'koding-service-key-parser'

allServices = {}

incService = (serviceKey, amount) ->
  serviceInfo = parseServiceKey serviceKey

  { serviceGenericName, serviceUniqueName } = serviceInfo

  fetchHostname serviceGenericName, serviceUniqueName, (err, hostname) ->

    allServices[serviceGenericName] ?= { seq: 0, services: {} }

    genericServices = allServices[serviceGenericName].services

    if genericServices[serviceUniqueName]?
    then genericServices[serviceUniqueName].amount += amount
    else genericServices[serviceUniqueName] = { amount, hostname }

    if genericServices[serviceUniqueName].amount is 0
      delete genericServices[serviceUniqueName]
    else if genericServices[serviceUniqueName].amount < 0
      console.error 'Negative service count!'

koding.connect ->
  opsview.send 'Services presence', 0, 'Service started'
  koding.monitorPresence
    join: (serviceKey) ->
      incService serviceKey, 1
    leave: (serviceKey) ->
      incService serviceKey, -1

fetchHostname = (serviceGenericName, serviceUniqueName, callback) ->
  if 'broker' is serviceGenericName and not KONFIG.runKontrol
    process.nextTick -> callback null,
      if KONFIG.broker.webPort?
      then "#{ KONFIG.broker.webHostname }:#{ KONFIG.broker.webPort }"
      else KONFIG.broker.webHostname
  else
    (koding.getClient().collection 'jKontrolWorkers')
      .findOne {
        serviceUniqueName
        hostname  : ///^#{ serviceGenericName }///
        status    : 0
      }, { hostname: 1 }, (err, worker) ->
          return callback err  if err?
          callback null, worker?.hostname ? null

module.exports = do (failing = no) -> (req, res) ->
  { params:{ service }, query } = req

  protocol = KONFIG.broker.webProtocol ? 'https:'

  genericServices = allServices[service]

  { services: s } = genericServices

  services =
    Object.keys(s).map( (k) ->
      { hostname } = s[k]
      unless hostname?
        console.warn """
          Could not find that hostname:
          #{k}
          #{require('util').inspect genericServices.services[k]}
          """
      return hostname
    ).filter Boolean

  res.set "Content-Type", "text/json"

  if query.all?
    res.send services.map (hostname) -> "#{ protocol }//#{ hostname }"

  else if services.length is 0
    # FAILURE! send an alert to opsview.
    unless failing
      failing = yes
      opsview.send 'Services presence', 2, 'Service loadbalancing failure detected!'
    # Fail-over to the value hard-coded into the config.
    { webHostname, webPort } = KONFIG.broker
    res.send "\"#{ protocol }//#{ webHostname }#{ if webHostname.port then ":#{webHostname.port}" else "" }\""

  else
    failing = no
    i = genericServices.seq++ % services.length
    res.send "\"#{ protocol }//#{ services[i] }\""<commit_msg>webserver: reimplement "services-presence" in terms of kontrol<commit_after>request = require 'request'

supportedServices = ['broker']

getFailoverUrl = ->
  { webProtocol: protocol, webHostname: hostname, webPort: port } =
    KONFIG.broker

  # piece the url together from the config:
  url = "#{ protocol }//#{ hostname }#{ if port then ":#{port}" else "" }"

failover = (req, res, multi) ->  
  if req.params.service is 'broker'
    url = getFailoverUrl()
    res.set 'Content-Type', 'application/json'
    res.send if multi then [url] else JSON.stringify url
    yes
  else
    no

module.exports = (req, res, next) ->
  { params, query } = req

  { service } = params

  if service not in supportedServices
    next()
    return

  multi = query.all?

  if KONFIG.runKontrol # let kontrol provide the url

    url = "#{ KONFIG.kontrold.api.url }/workers/url/#{ service }#{
      if multi
      then '?all'
      else ''
    }"

    request(url)
      .on('error', (err) -> next()  unless failover req, res, multi)
      .pipe(res)

  else # handle fail over
    next()  unless failover req, res, multi
{'fraction_non_alphanumeric': 0.12357884330202669, 'fraction_numerical': 0.002471576866040534, 'mean_word_length': 3.055110220440882, 'pattern_counts': {'":': 2, '<': 4, '<?xml version=': 0, '>': 19, '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': '7475819', 'n_tokens_mistral': 1248, 'n_tokens_neox': 1229, 'n_words': 329}