<commit_before>/* jshint unused:false */
"use strict";

var http = require('http');
var https = require('https');
var path = require('path');
var url = require('url');
var app = require("./server").app;
var httpServer = require("./server").server;
var config = require('./config').config;
var logger = require('./logger');
var UserList = require('./users').UserList;
var User = require('./users').User;

var users = new UserList();
var anons = new UserList();
var api;

users.onadduser = function(user) {
  users.forEach(function(peer) {
    if (peer !== user)
      peer.send("userJoined", user.nick);
  });
};

users.onremoveuser = function(user) {
  users.forEach(function(peer) {
    if (peer !== user)
      peer.send("userLeft", user.nick);
  });
};

api = {
  _verifyAssertion: function(assertion, callback) {
    // When we're in the test environment, we bypass the assertion verifiction.
    // In this case, the email of the user IS the assertion.
    if (process.env.NODE_ENV === "test")
      return callback(null, assertion);

    var data = "audience=" + encodeURIComponent(config.ROOTURL);
    data += "&assertion=" + encodeURIComponent(assertion);

    var options = {
      host: "verifier.login.persona.org",
      path: "/verify",
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "Content-Length": data.length
      }
    };

    var req = https.request(options, function(res) {
      var ret = "";
      res.setEncoding('utf8');

      res.on("data", function (chunk) {
        ret += chunk;
      });
      res.on("end", function () {
        var val = JSON.parse(ret);
        if (val.status === "okay")
          callback(null, val.email);
        else
          callback(val.reason);
      });
    });
    req.write(data);
    req.end();
  },

  signin: function(req, res) {
    var assertion = req.body.assertion;
    api._verifyAssertion(assertion, function(err, nick) {
      if (err)
        return res.send(400, JSON.stringify({error: err}));

      logger.info({type: "signin"});

      req.session.email = nick;
      res.send(200, JSON.stringify({nick: nick}));
    });
  },

  signout: function(req, res) {
    if (!req.session.email)
      return res.send(400);

    var nick = req.session.email;

    // Remove the user's session
    req.session.reset();

    var user = users.get(nick);
    if (user) {
      // notify the client
      user.send("disconnect", null);

      // Disconnecting the user will remove them from the users
      // list.
      user.disconnect();
    }

    logger.info({type: "signout"});

    // XXX why do we return true?  this may want to be removed
    res.send(200, JSON.stringify(true));
  },

  /*
   * Long Polling API
   *
   * This API provides a stream of event via a long polling mechanism.
   * The connection hangs for n seconds as long as there is no events.
   * If in the meantime there are incoming events, then the API returns
   * immediately with these events as a response.
   *
   * Events received between reconnections are not lost.
   */
  stream: function(req, res) {
    var firstRequest = req.body && req.body.firstRequest;
    var isAnon = !req.session.email;
    var user;

    if (isAnon)
      user = api._setupUser(anons, api._genId());
    else
      user = api._setupUser(users, req.session.email);

    user.touch();

    if (firstRequest)
      res.send(200, JSON.stringify([]));
    else
      user.waitForEvents(function(events) {
        logger.trace({to: nick, events: events}, "long polling send");
        res.send(200, JSON.stringify(events));
      });
  },

  _setupUser: function(userList, id, firstRequest) {
    var user = userList.get(id);

    if (user && firstRequest) {
      user.clearPending();
      logger.info({type: "reconnection"});
    }

    if (!user) {
      user = userList.add(id).get(id);
      user.ondisconnect = function() {
        userList.remove(id);
        logger.info({type: "disconnection"});
      };

      logger.info({type: "connection"});
    }

    return user;
  },

  _genId: function() {
    // XXX needs to be implemented<commit_msg>Fix merge conflict caught by jshint<commit_after>/* jshint unused:false */
"use strict";

var http = require('http');
var https = require('https');
var path = require('path');
var url = require('url');
var app = require("./server").app;
var httpServer = require("./server").server;
var config = require('./config').config;
var logger = require('./logger');
var UserList = require('./users').UserList;
var User = require('./users').User;

var users = new UserList();
var anons = new UserList();
var api;

users.onadduser = function(user) {
  users.forEach(function(peer) {
    if (peer !== user)
      peer.send("userJoined", user.nick);
  });
};

users.onremoveuser = function(user) {
  users.forEach(function(peer) {
    if (peer !== user)
      peer.send("userLeft", user.nick);
  });
};

api = {
  _verifyAssertion: function(assertion, callback) {
    // When we're in the test environment, we bypass the assertion verifiction.
    // In this case, the email of the user IS the assertion.
    if (process.env.NODE_ENV === "test")
      return callback(null, assertion);

    var data = "audience=" + encodeURIComponent(config.ROOTURL);
    data += "&assertion=" + encodeURIComponent(assertion);

    var options = {
      host: "verifier.login.persona.org",
      path: "/verify",
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "Content-Length": data.length
      }
    };

    var req = https.request(options, function(res) {
      var ret = "";
      res.setEncoding('utf8');

      res.on("data", function (chunk) {
        ret += chunk;
      });
      res.on("end", function () {
        var val = JSON.parse(ret);
        if (val.status === "okay")
          callback(null, val.email);
        else
          callback(val.reason);
      });
    });
    req.write(data);
    req.end();
  },

  signin: function(req, res) {
    var assertion = req.body.assertion;
    api._verifyAssertion(assertion, function(err, nick) {
      if (err)
        return res.send(400, JSON.stringify({error: err}));

      logger.info({type: "signin"});

      req.session.email = nick;
      res.send(200, JSON.stringify({nick: nick}));
    });
  },

  signout: function(req, res) {
    if (!req.session.email)
      return res.send(400);

    var nick = req.session.email;

    // Remove the user's session
    req.session.reset();

    var user = users.get(nick);
    if (user) {
      // notify the client
      user.send("disconnect", null);

      // Disconnecting the user will remove them from the users
      // list.
      user.disconnect();
    }

    logger.info({type: "signout"});

    // XXX why do we return true?  this may want to be removed
    res.send(200, JSON.stringify(true));
  },

  /*
   * Long Polling API
   *
   * This API provides a stream of event via a long polling mechanism.
   * The connection hangs for n seconds as long as there is no events.
   * If in the meantime there are incoming events, then the API returns
   * immediately with these events as a response.
   *
   * Events received between reconnections are not lost.
   */
  stream: function(req, res) {
    var firstRequest = req.body && req.body.firstRequest;
    var isAnon = !req.session.email;
    var user;

    if (isAnon)
      user = api._setupUser(anons, api._genId());
    else
      user = api._setupUser(users, req.session.email);

    user.touch();

    if (firstRequest)
      res.send(200, JSON.stringify([]));
    else
      user.waitForEvents(function(events) {
        logger.trace({to: user.nick, events: events}, "long polling send");
        res.send(200, JSON.stringify(events));
      });
  },

  _setupUser: function(userList, id, firstRequest) {
    var user = userList.get(id);

    if (user && firstRequest) {
      user.clearPending();
      logger.info({type: "reconnection"});
    }

    if (!user) {
      user = userList.add(id).get(id);
      user.ondisconnect = function() {
        userList.remove(id);
        logger.info({type: "disconnection"});
      };

      logger.info({type: "connection"});
    }

    return user;
  },

  _genId: function() {
    // XXX needs to be implemented
{'fraction_non_alphanumeric': 0.1519672722897365, 'fraction_numerical': 0.004572253639754542, 'mean_word_length': 2.6472136902150067, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '5587228', 'n_tokens_mistral': 2638, 'n_tokens_neox': 2543, 'n_words': 678}