<commit_before>#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <set>
#include <mist/config.h>
#include <mist/defines.h>
#include <mist/timing.h>
#include <mist/http_parser.h>
#include <mist/tinythread.h>

Util::Config * cfg = 0;
std::string passphrase;

struct streamDetails{
  unsigned int total;
  unsigned int bandwidth;
  unsigned long long prevTotal;
};

class hostDetails{
  private:
    tthread::mutex * hostMutex;
    std::map<std::string, struct streamDetails> streams;
    unsigned int cpu;
    unsigned long long ramMax;
    unsigned long long ramCurr;
    unsigned int upSpeed;
    unsigned int downSpeed;
    unsigned int total;
    unsigned long long upPrev;
    unsigned long long downPrev;
    unsigned long long prevTime;
    unsigned long long addBandwidth;
  public:
    unsigned long long availBandwidth;
    hostDetails(){
      hostMutex = 0;
      cpu = 1000;
      ramMax = 0;
      ramCurr = 0;
      upSpeed = 0;
      downSpeed = 0;
      upPrev = 0;
      downPrev = 0;
      prevTime = 0;
      total = 0;
      addBandwidth = 0;
      availBandwidth = 128 * 1024 * 1024;//assume 1G connections
    }
    ~hostDetails(){
      if (hostMutex){
        delete hostMutex;
        hostMutex = 0;
      }
    }
    void badNess(){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      addBandwidth += 1 * 1024 * 1024;
      addBandwidth *= 1.2;
    }
    ///Returns the count of viewers for a given stream s.
    unsigned long long count(std::string & s){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      if (streams.count(s)){
        return streams[s].total;
      }else{
        return 0;
      }
    }
    ///Fills out a by reference given JSON::Value with current state.
    void fillState(JSON::Value & r){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      r["cpu"] = (long long)(cpu/10);
      if (ramMax){r["ram"] = (long long)((ramCurr*100) / ramMax);}
      r["up"] = (long long)upSpeed;
      r["down"] = (long long)downSpeed;
      r["streams"] = (long long)streams.size();
      r["viewers"] = (long long)total;
    }
    ///Scores a potential new connection to this server, on a scale from 0 to 3200.
    ///0 is horrible, 3200 is perfect.
    unsigned int rate(std::string & s){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      unsigned int score = 0;
      if (!ramMax){
        return 0;
      }
      //First, add current CPU/RAM left to the score, on a scale from 0 to 1000.
      score += (1000 - cpu) + (1000 - ((ramCurr * 1000) / ramMax));
      //Next, we add 200 points if the stream is already available.
      if (streams.count(s)){score += 200;}
      //Finally, account for bandwidth. We again scale from 0 to 1000 where 1000 is perfect.
      long long bwscore = (1000 - ((upSpeed * 1000) / availBandwidth));
      if (bwscore < 0){bwscore = 0;}
      long long bw_sub = ((addBandwidth * 1000) / availBandwidth);
      if (bwscore - bw_sub < 0){bw_sub = bwscore;}
      score += (bwscore - bw_sub);
      MEDIUM_MSG("CPU %u, RAM %u, Stream %u, BW %u (-%u) (max %llu MB/s)", 1000-cpu, 1000-((ramCurr * 1000) / ramMax), streams.count(s)?200:0, bwscore, bw_sub, availBandwidth / 1024 / 1024);
      return score;
    }
    void addViewer(std::string & s){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      unsigned long long toAdd = 0;
      if (streams.count(s)){
        toAdd = streams[s].bandwidth;
      }else{
        if (total){
          toAdd = (upSpeed + downSpeed) / total;
        }else{
          toAdd = (upSpeed + downSpeed) + 100000;
        }
      }
      //ensure reasonable limits of bandwidth guesses
      if (toAdd < 64*1024){toAdd = 64*1024;}//minimum of 0.5 mbps
      if (toAdd > 1024*1024){toAdd = 1024*1024;}//maximum of 8 mbps
      addBandwidth += toAdd;
    }
    void update(JSON::Value & d){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      cpu = d["cpu"].asInt();
      long long nRamMax = d["mem_total"].asInt();
      long long nRamCur = d["mem_used"].asInt();
      long long nShmMax = d["shm_total"].asInt();
      long long nShmCur = d["shm_used"].asInt();
      if (((nRamCur + nShmCur)*1000) / nRamMax > (nShmCur*1000) / nShmMax){
        ramMax = nRamMax;
        ramCurr = nRamCur + nShmCur;
      }else{
        ramMax = nShmMax;
        ramCurr = nShmCur;
      }
      total = d["curr"][0u].asInt();
      unsigned long long currUp = d["bw"][0u].asInt(), currDown = d["bw"][1u].asInt();
      unsigned int timeDiff = 0;
      if (prevTime){
        timeDiff = time(0) - prevTime;
        if (timeDiff){
          upSpeed = (currUp - upPrev) / timeDiff;
          downSpeed = (currDown - downPrev) / timeDiff;
        }
      }
      prevTime = time(0);
      upPrev = currUp;
      downPrev = currDown;

      if (d.isMember("streams") && d["streams"].size()){
        jsonForEach(d["streams"], it){
          unsigned int count = (*it)["curr"][0u].asInt() + (*it)["curr"][1u].asInt() + (*it)["curr"][2u].asInt();
          if (!count){
            if (streams.count(it.key())){
              streams.erase(it.key());
            }
            continue;
          }
          struct streamDetails & strm = streams[it.key()];
          strm.total = (*it)["curr"][0u].asInt();
          unsigned long long currTotal = (*it)["bw"][0u].asInt() + (*it)["bw"][1u].asInt();
          if (timeDiff && count){
            strm.bandwidth = ((currTotal - strm.prevTotal) / timeDiff) / count;
          }else{
            if (total){
              strm.bandwidth = (upSpeed + downSpeed) / total;
            }else{
              strm.bandwidth = (upSpeed + downSpeed) + 100000;
            }
          }
          strm.prevTotal = currTotal;
        }
        if (streams.size()){
          std::set<std::string> eraseList;
          for (std::map<std::string, struct streamDetails>::iterator it = streams.begin(); it != streams.end(); ++it){
            if (!d["streams"].isMember(it->first)){
              eraseList.insert(it->first);
            }
          }
          for (std::set<std::string>::iterator it = eraseList.begin(); it != eraseList.end(); ++it){
            streams.erase(*it);
          }
        }
      }else{
        streams.clear();
      }
      addBandwidth *= 0.9;
    }
};

std::map<std::string, hostDetails> hosts;

int handleRequest(Socket::Connection & conn){
  HTTP::Parser H;
  while (conn){
    if ((conn.spool() || conn.Received().size()) && H.Read(conn)){
      if (H.url.size() == 1){
        std::string host = H.GetVar("host");
        std::string stream = H.GetVar("stream");
        H.Clean();
        H.SetHeader("Content-Type", "text/plain");
        JSON::Value ret;
        if (!host.size() && !stream.size()){
            for (std::map<std::string, hostDetails>::iterator it = hosts.begin(); it != hosts.end(); ++it){
              it->second.fillState(ret[it->first]);
            }
        }else{
          if (stream.size()){
            unsigned long long strTot = 0;
            for (std::map<std::string, hostDetails>::iterator it = hosts.begin(); it != hosts.end(); ++it){
              strTot += it->second.count(stream);
            }
            ret = (long long)strTot;
          }else if (hosts.count(host)){
            hosts[host].fillState(ret);
          }
        }
        H.SetBody(ret.toPrettyString());
        H.SendResponse("200", "OK", conn);
        H.Clean();
        continue;
      }
      std::string stream = H.url.substr(1);
      INFO_MSG("Balancing stream %s", stream.c_str());
      H.Clean();
      H.SetHeader("Content-Type", "text/plain");
      std::string bestHost = "";
      unsigned int bestScore = 0;
      for (std::map<std::string, hostDetails>::iterator it = hosts.begin(); it != hosts.end(); ++it){
        unsigned int score = it->second.rate(stream);
        if (score > bestScore){
          bestHost = it->first;
          bestScore = score;
        }
        INFO_MSG("%s scores %u", it->first.c_str(), score);
      }
      INFO_MSG("Winner: %s scores %u", bestHost.c_str(), bestScore);
      hosts[bestHost].addViewer(stream);
      H.SetBody(bestHost);
      H.SendResponse("200", "OK", conn);
      H.Clean();
    }//if HTTP request received
  }
  conn.close();
  return 0;
}

void handleServer(void * servName){
  std::string & name = *(std::string*)servName;

  HTTP::Parser H;
  std::string host;
  int port = 4242;
  JSON::Value bandwidth = 128 * 1024 * 1024ll;//assume 1G connection

  size_t slash = name.find('/');
  if (slash != std::string::npos){
    bandwidth = name.substr(slash+1, std::string::npos);
    bandwidth = bandwidth.asInt() * 1024 * 1024;
    name = name.substr(0, slash);
  }

  size_t colon = name.find(':');
  if (colon != std::string::npos && colon != 0 && colon != name.size()) {
    host = name.substr(0, colon);
    port = atoi(name.substr(colon + 1, std::string::npos).c_str());
  }else{
    host = name;
  }

  hosts[host].availBandwidth = bandwidth.asInt();

  INFO_MSG("Monitoring %s on port %d.", host.c_str(), port, passphrase.c_str());

  Socket::Connection servConn(host, port, false);
  while (cfg->is_active){
    if (!servConn){
      INFO_MSG("Reconnecting to %s", host.c_str());
      servConn = Socket::Connection(host, port, false);
    }
    if (!servConn){
      INFO_MSG("Can't reach server %s", host.c_str());
      hosts[host].badNess();
      Util::wait(5000);
      continue;
    }

    //retrieve update information
    H.url = "/" + passphrase + ".json";
    H.method = "GET";
    H.SendRequest(servConn);
    H.Clean();
    unsigned int startTime = Util::epoch();
    while (cfg->is_active && servConn && !((servConn.spool() || servConn.Received().size()) && H.Read(servConn))){
      if (Util::epoch() - startTime > 2){
        servConn.close();
        H.Clean();
      }
      Util::sleep(250);
    }
    JSON::Value servData = JSON::fromString(H.body);
    if (!servData){
      INFO_MSG("Can't retrieve server %s load information", host.c_str());
      hosts[host].badNess();
      servConn.close();
    }else{
      hosts[host].update(servData);
    }
    H.Clean();
    Util::wait(5000);
  }
  servConn.close();
}

int main(int argc, char ** argv){
  Util::Config conf(argv[0]);
  cfg = &conf;

  JSON::Value opt;
  opt["arg"] = "string";
  opt["short"] = "s";
  opt["long"] = "server";
  opt["help"] = "Address of a server to balance. Hostname or IP, optionally followed by API port.";
  conf.addOption("server", opt);

  opt["arg"] = "integer";
  opt["short"] = "p";
  opt["long"] = "port";
  opt["help"] = "TCP port to listen on";
  opt["value"].append((long long)8042);
  conf.addOption("port", opt);

  opt["arg"] = "string";
  opt["short"] = "P";
  opt["long"] = "passphrase";
  opt["help"] = "Passphrase (prometheus option value) to use for data retrieval.";
  opt["value"][0u] = "koekjes";
  conf.addOption("passphrase", opt);

  opt["arg"] = "string";
  opt["short"] = "i";
  opt["long"] = "interface";
  opt["help"] = "Network interface to listen on";
  opt["value"][0u] = "0.0.0.0";
  conf.addOption("interface", opt);

  opt["arg"] = "string";
  opt["short"] = "u";
  opt["long"] = "username";
  opt["help"] = "Username to drop privileges to";
  opt["value"][0u] = "root";
  conf.addOption("username", opt);

  conf.parseArgs(argc, argv);

  passphrase = conf.getOption("passphrase").asStringRef();

  JSON::Value & nodes = conf.getOption("server", true);
  INFO_MSG("Load balancer activating. Balancing between %llu nodes.", nodes.size());
  conf.activate();

  std::map<std::string, tthread::thread *> threads;
  jsonForEach(nodes, it){
    threads[it->asStringRef()] = new tthread::thread(handleServer, (void*)&(it->asStringRef()));
  }

  conf.serveThreadedSocket(handleRequest);
  if (!conf.is_active){
    INFO_MSG("Load balancer shutting down; received shutdown signal");
  }else{
    INFO_MSG("Load balancer shutting down; socket problem");
  }

  if (threads.size()){
    for (std::map<std::string, tthread::thread *>::iterator it = threads.begin(); it != threads.end(); ++it){
      it->second->join();
    }
  }

}

<commit_msg>Tweaked load balancer verbosity levels<commit_after>#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <set>
#include <mist/config.h>
#include <mist/defines.h>
#include <mist/timing.h>
#include <mist/http_parser.h>
#include <mist/tinythread.h>

Util::Config * cfg = 0;
std::string passphrase;

struct streamDetails{
  unsigned int total;
  unsigned int bandwidth;
  unsigned long long prevTotal;
};

class hostDetails{
  private:
    tthread::mutex * hostMutex;
    std::map<std::string, struct streamDetails> streams;
    unsigned int cpu;
    unsigned long long ramMax;
    unsigned long long ramCurr;
    unsigned int upSpeed;
    unsigned int downSpeed;
    unsigned int total;
    unsigned long long upPrev;
    unsigned long long downPrev;
    unsigned long long prevTime;
    unsigned long long addBandwidth;
  public:
    unsigned long long availBandwidth;
    hostDetails(){
      hostMutex = 0;
      cpu = 1000;
      ramMax = 0;
      ramCurr = 0;
      upSpeed = 0;
      downSpeed = 0;
      upPrev = 0;
      downPrev = 0;
      prevTime = 0;
      total = 0;
      addBandwidth = 0;
      availBandwidth = 128 * 1024 * 1024;//assume 1G connections
    }
    ~hostDetails(){
      if (hostMutex){
        delete hostMutex;
        hostMutex = 0;
      }
    }
    void badNess(){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      addBandwidth += 1 * 1024 * 1024;
      addBandwidth *= 1.2;
    }
    ///Returns the count of viewers for a given stream s.
    unsigned long long count(std::string & s){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      if (streams.count(s)){
        return streams[s].total;
      }else{
        return 0;
      }
    }
    ///Fills out a by reference given JSON::Value with current state.
    void fillState(JSON::Value & r){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      r["cpu"] = (long long)(cpu/10);
      if (ramMax){r["ram"] = (long long)((ramCurr*100) / ramMax);}
      r["up"] = (long long)upSpeed;
      r["down"] = (long long)downSpeed;
      r["streams"] = (long long)streams.size();
      r["viewers"] = (long long)total;
    }
    ///Scores a potential new connection to this server, on a scale from 0 to 3200.
    ///0 is horrible, 3200 is perfect.
    unsigned int rate(std::string & s){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      unsigned int score = 0;
      if (!ramMax){
        return 0;
      }
      //First, add current CPU/RAM left to the score, on a scale from 0 to 1000.
      score += (1000 - cpu) + (1000 - ((ramCurr * 1000) / ramMax));
      //Next, we add 200 points if the stream is already available.
      if (streams.count(s)){score += 200;}
      //Finally, account for bandwidth. We again scale from 0 to 1000 where 1000 is perfect.
      long long bwscore = (1000 - ((upSpeed * 1000) / availBandwidth));
      if (bwscore < 0){bwscore = 0;}
      long long bw_sub = ((addBandwidth * 1000) / availBandwidth);
      if (bwscore - bw_sub < 0){bw_sub = bwscore;}
      score += (bwscore - bw_sub);
      MEDIUM_MSG("CPU %u, RAM %u, Stream %u, BW %u (-%u) (max %llu MB/s)", 1000-cpu, 1000-((ramCurr * 1000) / ramMax), streams.count(s)?200:0, bwscore, bw_sub, availBandwidth / 1024 / 1024);
      return score;
    }
    void addViewer(std::string & s){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      unsigned long long toAdd = 0;
      if (streams.count(s)){
        toAdd = streams[s].bandwidth;
      }else{
        if (total){
          toAdd = (upSpeed + downSpeed) / total;
        }else{
          toAdd = (upSpeed + downSpeed) + 100000;
        }
      }
      //ensure reasonable limits of bandwidth guesses
      if (toAdd < 64*1024){toAdd = 64*1024;}//minimum of 0.5 mbps
      if (toAdd > 1024*1024){toAdd = 1024*1024;}//maximum of 8 mbps
      addBandwidth += toAdd;
    }
    void update(JSON::Value & d){
      if (!hostMutex){hostMutex = new tthread::mutex();}
      tthread::lock_guard<tthread::mutex> guard(*hostMutex);
      cpu = d["cpu"].asInt();
      long long nRamMax = d["mem_total"].asInt();
      long long nRamCur = d["mem_used"].asInt();
      long long nShmMax = d["shm_total"].asInt();
      long long nShmCur = d["shm_used"].asInt();
      if (((nRamCur + nShmCur)*1000) / nRamMax > (nShmCur*1000) / nShmMax){
        ramMax = nRamMax;
        ramCurr = nRamCur + nShmCur;
      }else{
        ramMax = nShmMax;
        ramCurr = nShmCur;
      }
      total = d["curr"][0u].asInt();
      unsigned long long currUp = d["bw"][0u].asInt(), currDown = d["bw"][1u].asInt();
      unsigned int timeDiff = 0;
      if (prevTime){
        timeDiff = time(0) - prevTime;
        if (timeDiff){
          upSpeed = (currUp - upPrev) / timeDiff;
          downSpeed = (currDown - downPrev) / timeDiff;
        }
      }
      prevTime = time(0);
      upPrev = currUp;
      downPrev = currDown;

      if (d.isMember("streams") && d["streams"].size()){
        jsonForEach(d["streams"], it){
          unsigned int count = (*it)["curr"][0u].asInt() + (*it)["curr"][1u].asInt() + (*it)["curr"][2u].asInt();
          if (!count){
            if (streams.count(it.key())){
              streams.erase(it.key());
            }
            continue;
          }
          struct streamDetails & strm = streams[it.key()];
          strm.total = (*it)["curr"][0u].asInt();
          unsigned long long currTotal = (*it)["bw"][0u].asInt() + (*it)["bw"][1u].asInt();
          if (timeDiff && count){
            strm.bandwidth = ((currTotal - strm.prevTotal) / timeDiff) / count;
          }else{
            if (total){
              strm.bandwidth = (upSpeed + downSpeed) / total;
            }else{
              strm.bandwidth = (upSpeed + downSpeed) + 100000;
            }
          }
          strm.prevTotal = currTotal;
        }
        if (streams.size()){
          std::set<std::string> eraseList;
          for (std::map<std::string, struct streamDetails>::iterator it = streams.begin(); it != streams.end(); ++it){
            if (!d["streams"].isMember(it->first)){
              eraseList.insert(it->first);
            }
          }
          for (std::set<std::string>::iterator it = eraseList.begin(); it != eraseList.end(); ++it){
            streams.erase(*it);
          }
        }
      }else{
        streams.clear();
      }
      addBandwidth *= 0.9;
    }
};

std::map<std::string, hostDetails> hosts;

int handleRequest(Socket::Connection & conn){
  HTTP::Parser H;
  while (conn){
    if ((conn.spool() || conn.Received().size()) && H.Read(conn)){
      if (H.url.size() == 1){
        std::string host = H.GetVar("host");
        std::string stream = H.GetVar("stream");
        H.Clean();
        H.SetHeader("Content-Type", "text/plain");
        JSON::Value ret;
        if (!host.size() && !stream.size()){
            for (std::map<std::string, hostDetails>::iterator it = hosts.begin(); it != hosts.end(); ++it){
              it->second.fillState(ret[it->first]);
            }
        }else{
          if (stream.size()){
            unsigned long long strTot = 0;
            for (std::map<std::string, hostDetails>::iterator it = hosts.begin(); it != hosts.end(); ++it){
              strTot += it->second.count(stream);
            }
            ret = (long long)strTot;
          }else if (hosts.count(host)){
            hosts[host].fillState(ret);
          }
        }
        H.SetBody(ret.toPrettyString());
        H.SendResponse("200", "OK", conn);
        H.Clean();
        continue;
      }
      std::string stream = H.url.substr(1);
      INFO_MSG("Balancing stream %s", stream.c_str());
      H.Clean();
      H.SetHeader("Content-Type", "text/plain");
      std::string bestHost = "";
      unsigned int bestScore = 0;
      for (std::map<std::string, hostDetails>::iterator it = hosts.begin(); it != hosts.end(); ++it){
        unsigned int score = it->second.rate(stream);
        if (score > bestScore){
          bestHost = it->first;
          bestScore = score;
        }
        INFO_MSG("%s scores %u", it->first.c_str(), score);
      }
      INFO_MSG("Winner: %s scores %u", bestHost.c_str(), bestScore);
      hosts[bestHost].addViewer(stream);
      H.SetBody(bestHost);
      H.SendResponse("200", "OK", conn);
      H.Clean();
    }//if HTTP request received
  }
  conn.close();
  return 0;
}

void handleServer(void * servName){
  std::string & name = *(std::string*)servName;

  HTTP::Parser H;
  std::string host;
  int port = 4242;
  JSON::Value bandwidth = 128 * 1024 * 1024ll;//assume 1G connection

  size_t slash = name.find('/');
  if (slash != std::string::npos){
    bandwidth = name.substr(slash+1, std::string::npos);
    bandwidth = bandwidth.asInt() * 1024 * 1024;
    name = name.substr(0, slash);
  }

  size_t colon = name.find(':');
  if (colon != std::string::npos && colon != 0 && colon != name.size()) {
    host = name.substr(0, colon);
    port = atoi(name.substr(colon + 1, std::string::npos).c_str());
  }else{
    host = name;
  }

  hosts[host].availBandwidth = bandwidth.asInt();

  INFO_MSG("Monitoring %s on port %d.", host.c_str(), port, passphrase.c_str());
  down = true;

  Socket::Connection servConn(host, port, false);
  while (cfg->is_active){
    if (!servConn){
      WARN_MSG("Reconnecting to %s", host.c_str());
      servConn = Socket::Connection(host, port, false);
    }
    if (!servConn){
      FAIL_MSG("Can't reach server %s", host.c_str());
      hosts[host].badNess();
      Util::wait(5000);
      down = true;
      continue;
    }

    //retrieve update information
    H.url = "/" + passphrase + ".json";
    H.method = "GET";
    H.SendRequest(servConn);
    H.Clean();
    unsigned int startTime = Util::epoch();
    while (cfg->is_active && servConn && !((servConn.spool() || servConn.Received().size()) && H.Read(servConn))){
      if (Util::epoch() - startTime > 2){
        servConn.close();
        H.Clean();
      }
      Util::sleep(250);
    }
    JSON::Value servData = JSON::fromString(H.body);
    if (!servData){
      FAIL_MSG("Can't retrieve server %s load information", host.c_str());
      down = true;
      hosts[host].badNess();
      servConn.close();
    }else{
      if (down){
        WARN_MSG("Connection established with %s", host.c_str());
        down = false;
      }
      hosts[host].update(servData);
    }
    H.Clean();
    Util::wait(5000);
  }
  servConn.close();
}

int main(int argc, char ** argv){
  Util::Config conf(argv[0]);
  cfg = &conf;

  JSON::Value opt;
  opt["arg"] = "string";
  opt["short"] = "s";
  opt["long"] = "server";
  opt["help"] = "Address of a server to balance. Hostname or IP, optionally followed by API port.";
  conf.addOption("server", opt);

  opt["arg"] = "integer";
  opt["short"] = "p";
  opt["long"] = "port";
  opt["help"] = "TCP port to listen on";
  opt["value"].append((long long)8042);
  conf.addOption("port", opt);

  opt["arg"] = "string";
  opt["short"] = "P";
  opt["long"] = "passphrase";
  opt["help"] = "Passphrase (prometheus option value) to use for data retrieval.";
  opt["value"][0u] = "koekjes";
  conf.addOption("passphrase", opt);

  opt["arg"] = "string";
  opt["short"] = "i";
  opt["long"] = "interface";
  opt["help"] = "Network interface to listen on";
  opt["value"][0u] = "0.0.0.0";
  conf.addOption("interface", opt);

  opt["arg"] = "string";
  opt["short"] = "u";
  opt["long"] = "username";
  opt["help"] = "Username to drop privileges to";
  opt["value"][0u] = "root";
  conf.addOption("username", opt);

  conf.parseArgs(argc, argv);

  passphrase = conf.getOption("passphrase").asStringRef();

  JSON::Value & nodes = conf.getOption("server", true);
  WARN_MSG("Load balancer activating. Balancing between %llu nodes.", nodes.size());
  conf.activate();

  std::map<std::string, tthread::thread *> threads;
  jsonForEach(nodes, it){
    threads[it->asStringRef()] = new tthread::thread(handleServer, (void*)&(it->asStringRef()));
  }

  conf.serveThreadedSocket(handleRequest);
  if (!conf.is_active){
    WARN_MSG("Load balancer shutting down; received shutdown signal");
  }else{
    WARN_MSG("Load balancer shutting down; socket problem");
  }

  if (threads.size()){
    for (std::map<std::string, tthread::thread *>::iterator it = threads.begin(); it != threads.end(); ++it){
      it->second->join();
    }
  }

}

<|endoftext|>


<commit_before>/*
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2013 Aldebaran Robotics
*/

#include <qic/value.h>
#include "value_p.h"
#include "object_p.h"

qi_value_t* qi_value_create(const char *signature)
{
  qi::GenericValue* v;

  if (!signature || !strcmp(signature, ""))
    v = new qi::GenericValue();
  else {
    //TODO: check signature correctness
    qi::Type *type = qi::Type::fromSignature(signature);
    v = new qi::GenericValue(type);
  }
  return (qi_value_t*)v;
}

void qi_value_destroy(qi_value_t* val)
{
  qi::GenericValue *v = &qi_value_cpp(val);
  delete v;
}

int         qi_value_reset(qi_value_t* value, const char *signature)
{
  qi::GenericValue *v = &qi_value_cpp(value);
  if (!signature || !strcmp(signature, ""))
    v->reset();
  else {
    //TODO: check signature correctness
    qi::Type *type = qi::Type::fromSignature(signature);
    v->reset(type);
  }
  return 1;
}

void        qi_value_swap(qi_value_t* dest, qi_value_t* src)
{
  qi::GenericValue *s = &qi_value_cpp(src);
  qi::GenericValue *d = &qi_value_cpp(dest);
  s->swap(*d);
}

qi_value_t* qi_value_copy(qi_value_t* src)
{
  qi::GenericValue *s = &qi_value_cpp(src);
  qi::GenericValue *d = new qi::GenericValue;
  *d = s;
  return (qi_value_t*)d;
}

qi_value_kind_t qi_value_get_kind(qi_value_t* value) {
  if (!value)
    return QI_VALUE_KIND_UNKNOWN;
  qi::GenericValue &val = qi_value_cpp(value);
  return (qi_value_kind_t)(val.kind());
}

const char*     qi_value_get_signature(qi_value_t* value, int resolveDynamics)
{
  qi::GenericValue &val = qi_value_cpp(value);
  return qi::os::strdup(val.signature(!!resolveDynamics).c_str());
}

//# GENERIC POD IMPL
template<typename T>
int       qi_value_set_pod(qi_value_t  *msg, T val) {
  qi::GenericValue &gv = qi_value_cpp(msg);
  try {
    gv.set<T>(val);
    return 1;
  } catch (std::runtime_error &) {}
  return 0;
}

template<typename T>
int qi_value_get_pod(qi_value_t *msg, T *result) {
  qi::GenericValue &gv = qi_value_cpp(msg);
  try {
    *result = gv.to<T>();
    return 1;
  } catch (std::runtime_error &) {
  }
  return 0;
}

template<typename T>
T qi_value_get_pod_default(qi_value_t *msg, T defvalue) {
  qi::GenericValue &gv = qi_value_cpp(msg);
  try {
    return gv.to<T>();
  } catch (std::runtime_error &) {
  }
  return defvalue;
}

//# UINT64
int qi_value_set_uint64(qi_value_t* container, unsigned long long value)
{ return qi_value_set_pod<unsigned long long>(container, value); }

int qi_value_get_uint64(qi_value_t* container, unsigned long long *result)
{ return qi_value_get_pod<unsigned long long>(container, result); }

unsigned long long qi_value_get_uint64_default(qi_value_t *container, unsigned long long defvalue)
{ return qi_value_get_pod_default<unsigned long long>(container, defvalue); }

//# INT64
int qi_value_set_int64(qi_value_t* container, long long value)
{ return qi_value_set_pod<long long>(container, value); }

int qi_value_get_int64(qi_value_t* container, long long *result)
{ return qi_value_get_pod<long long>(container, result); }

long long qi_value_get_int64_default(qi_value_t *container, long long defvalue)
{ return qi_value_get_pod_default<long long>(container, defvalue); }

//# FLOAT
int qi_value_set_float(qi_value_t* container, float value)
{ return qi_value_set_pod<float>(container, value); }

int qi_value_get_float(qi_value_t* container, float *result)
{ return qi_value_get_pod<float>(container, result); }

float qi_value_get_float_default(qi_value_t *container, float defvalue)
{ return qi_value_get_pod_default<float>(container, defvalue); }

//# DOUBLE
int qi_value_set_double(qi_value_t* container, double value)
{ return qi_value_set_pod<double>(container, value); }

int qi_value_get_double(qi_value_t* container, double *result)
{ return qi_value_get_pod<double>(container, result); }

double qi_value_get_double_default(qi_value_t *container, double defvalue)
{ return qi_value_get_pod_default<double>(container, defvalue); }

//# STRING
int        qi_value_set_string(qi_value_t *container, const char *s)
{
  qi::GenericValue &gv = qi_value_cpp(container);
  try {
    gv.setString(s);
    return 1;
  } catch (std::runtime_error &) {
  }
  return 0;
}

const char* qi_value_get_string(qi_value_t *msg)
{
  qi::GenericValue &gv = qi_value_cpp(msg);
  try {
    return qi::os::strdup(gv.toString().c_str());
  } catch (std::runtime_error &) {
  }
  return 0;
}

//# TUPLE
int        qi_value_tuple_set(qi_value_t *msg, unsigned int idx, qi_value_t *value)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  qi::GenericValue &val = qi_value_cpp(value);

  try {
    if (container.kind() != QI_VALUE_KIND_TUPLE || idx >= container.size()) {
      return 0;
    }
    container[idx].set(val);
    return 1;
  } catch (std::runtime_error &) {}
  return 0;
}

qi_value_t*  qi_value_tuple_get(qi_value_t *msg, unsigned int idx) {
  qi::GenericValue &container = qi_value_cpp(msg);
  if (container.kind() != QI_VALUE_KIND_TUPLE || idx >= container.size()) {
    return 0;
  }
  qi_value_t* ret = qi_value_create("");
  qi::GenericValue &gv = qi_value_cpp(ret);
  gv = container[idx];
  return ret;
}

int          qi_value_tuple_size(qi_value_t *msg)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  if (container.kind() != QI_VALUE_KIND_TUPLE) {
    return -1;
  }
  return container.size();
}

//# LIST
int          qi_value_list_set(qi_value_t *msg, unsigned int idx, qi_value_t *value)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  qi::GenericValue &val = qi_value_cpp(value);

  if (container.kind() != QI_VALUE_KIND_LIST || idx >= container.size()) {
    return 0;
  }
  try {
    container[idx].set(val);
    return 1;
  } catch (std::runtime_error &) {}
  return 0;
}

qi_value_t*  qi_value_list_get(qi_value_t *msg, unsigned int idx)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  if (container.kind() != QI_VALUE_KIND_LIST || idx >= container.size()) {
    return 0;
  }
  qi_value_t* ret = qi_value_create("");
  qi::GenericValue &gv = qi_value_cpp(ret);
  gv = container[idx];
  return ret;
}

int          qi_value_list_size(qi_value_t *msg)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  if (container.kind() != QI_VALUE_KIND_LIST) {
    return -1;
  }
  return container.size();
}

//# OBJECT
qi_object_t* qi_value_get_object(qi_value_t* val)
{
  qi::GenericValuePtr &gv = qi_value_cpp(val);
  qi::ObjectPtr obj = gv.as<qi::ObjectPtr>();
  return qi_object_create_from(obj);
}

int          qi_value_set_object(qi_value_t* value, qi_object_t *o)
{
  qi::GenericValuePtr &gv = qi_value_cpp(value);
  qi::ObjectPtr &obj = qi_object_cpp(o);
  try {
    gv.set<qi::ObjectPtr>(obj);
    return 1;
  } catch (std::runtime_error&) {}
  return 0;
}

//# DYNAMIC
int          qi_value_dynamic_set(qi_value_t *container, qi_value_t* value)
{
  return 0;
}

qi_value_t*  qi_value_dynamic_get(qi_value_t *container)
{
  return 0;
}

//# MAP
unsigned int qi_value_map_size(qi_value_t *msg)
{
  return 0;
}

int         qi_value_map_set(qi_value_t *msg, qi_value_t *key, qi_value_t *value)
{
  return 0;
}

qi_value_t*  qi_value_map_get(qi_value_t *msg, qi_value_t *key)
{
  return 0;
}

//# RAW
int          qi_value_raw_set(qi_value_t* value, const char* data, int size){
  return 0;
}

int          qi_value_raw_get(qi_value_t* value, const char**data, int *size) {
  return 0;
}
<commit_msg>c: value: fix qi_value_copy<commit_after>/*
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2013 Aldebaran Robotics
*/

#include <qic/value.h>
#include "value_p.h"
#include "object_p.h"

qi_value_t* qi_value_create(const char *signature)
{
  qi::GenericValue* v;

  if (!signature || !strcmp(signature, ""))
    v = new qi::GenericValue();
  else {
    //TODO: check signature correctness
    qi::Type *type = qi::Type::fromSignature(signature);
    v = new qi::GenericValue(type);
  }
  return (qi_value_t*)v;
}

void qi_value_destroy(qi_value_t* val)
{
  qi::GenericValue *v = &qi_value_cpp(val);
  delete v;
}

int         qi_value_reset(qi_value_t* value, const char *signature)
{
  qi::GenericValue *v = &qi_value_cpp(value);
  if (!signature || !strcmp(signature, ""))
    v->reset();
  else {
    //TODO: check signature correctness
    qi::Type *type = qi::Type::fromSignature(signature);
    v->reset(type);
  }
  return 1;
}

void        qi_value_swap(qi_value_t* dest, qi_value_t* src)
{
  qi::GenericValue *s = &qi_value_cpp(src);
  qi::GenericValue *d = &qi_value_cpp(dest);
  s->swap(*d);
}

qi_value_t* qi_value_copy(qi_value_t* src)
{
  qi::GenericValue *s = &qi_value_cpp(src);
  qi::GenericValue *d = new qi::GenericValue;
  *d = *s;
  return (qi_value_t*)d;
}

qi_value_kind_t qi_value_get_kind(qi_value_t* value) {
  if (!value)
    return QI_VALUE_KIND_UNKNOWN;
  qi::GenericValue &val = qi_value_cpp(value);
  return (qi_value_kind_t)(val.kind());
}

const char*     qi_value_get_signature(qi_value_t* value, int resolveDynamics)
{
  qi::GenericValue &val = qi_value_cpp(value);
  return qi::os::strdup(val.signature(!!resolveDynamics).c_str());
}

//# GENERIC POD IMPL
template<typename T>
int       qi_value_set_pod(qi_value_t  *msg, T val) {
  qi::GenericValue &gv = qi_value_cpp(msg);
  try {
    gv.set<T>(val);
    return 1;
  } catch (std::runtime_error &) {}
  return 0;
}

template<typename T>
int qi_value_get_pod(qi_value_t *msg, T *result) {
  qi::GenericValue &gv = qi_value_cpp(msg);
  try {
    *result = gv.to<T>();
    return 1;
  } catch (std::runtime_error &) {
  }
  return 0;
}

template<typename T>
T qi_value_get_pod_default(qi_value_t *msg, T defvalue) {
  qi::GenericValue &gv = qi_value_cpp(msg);
  try {
    return gv.to<T>();
  } catch (std::runtime_error &) {
  }
  return defvalue;
}

//# UINT64
int qi_value_set_uint64(qi_value_t* container, unsigned long long value)
{ return qi_value_set_pod<unsigned long long>(container, value); }

int qi_value_get_uint64(qi_value_t* container, unsigned long long *result)
{ return qi_value_get_pod<unsigned long long>(container, result); }

unsigned long long qi_value_get_uint64_default(qi_value_t *container, unsigned long long defvalue)
{ return qi_value_get_pod_default<unsigned long long>(container, defvalue); }

//# INT64
int qi_value_set_int64(qi_value_t* container, long long value)
{ return qi_value_set_pod<long long>(container, value); }

int qi_value_get_int64(qi_value_t* container, long long *result)
{ return qi_value_get_pod<long long>(container, result); }

long long qi_value_get_int64_default(qi_value_t *container, long long defvalue)
{ return qi_value_get_pod_default<long long>(container, defvalue); }

//# FLOAT
int qi_value_set_float(qi_value_t* container, float value)
{ return qi_value_set_pod<float>(container, value); }

int qi_value_get_float(qi_value_t* container, float *result)
{ return qi_value_get_pod<float>(container, result); }

float qi_value_get_float_default(qi_value_t *container, float defvalue)
{ return qi_value_get_pod_default<float>(container, defvalue); }

//# DOUBLE
int qi_value_set_double(qi_value_t* container, double value)
{ return qi_value_set_pod<double>(container, value); }

int qi_value_get_double(qi_value_t* container, double *result)
{ return qi_value_get_pod<double>(container, result); }

double qi_value_get_double_default(qi_value_t *container, double defvalue)
{ return qi_value_get_pod_default<double>(container, defvalue); }

//# STRING
int        qi_value_set_string(qi_value_t *container, const char *s)
{
  qi::GenericValue &gv = qi_value_cpp(container);
  try {
    gv.setString(s);
    return 1;
  } catch (std::runtime_error &) {
  }
  return 0;
}

const char* qi_value_get_string(qi_value_t *msg)
{
  qi::GenericValue &gv = qi_value_cpp(msg);
  try {
    return qi::os::strdup(gv.toString().c_str());
  } catch (std::runtime_error &) {
  }
  return 0;
}

//# TUPLE
int        qi_value_tuple_set(qi_value_t *msg, unsigned int idx, qi_value_t *value)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  qi::GenericValue &val = qi_value_cpp(value);

  try {
    if (container.kind() != QI_VALUE_KIND_TUPLE || idx >= container.size()) {
      return 0;
    }
    container[idx].set(val);
    return 1;
  } catch (std::runtime_error &) {}
  return 0;
}

qi_value_t*  qi_value_tuple_get(qi_value_t *msg, unsigned int idx) {
  qi::GenericValue &container = qi_value_cpp(msg);
  if (container.kind() != QI_VALUE_KIND_TUPLE || idx >= container.size()) {
    return 0;
  }
  qi_value_t* ret = qi_value_create("");
  qi::GenericValue &gv = qi_value_cpp(ret);
  gv = container[idx];
  return ret;
}

int          qi_value_tuple_size(qi_value_t *msg)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  if (container.kind() != QI_VALUE_KIND_TUPLE) {
    return -1;
  }
  return container.size();
}

//# LIST
int          qi_value_list_set(qi_value_t *msg, unsigned int idx, qi_value_t *value)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  qi::GenericValue &val = qi_value_cpp(value);

  if (container.kind() != QI_VALUE_KIND_LIST || idx >= container.size()) {
    return 0;
  }
  try {
    container[idx].set(val);
    return 1;
  } catch (std::runtime_error &) {}
  return 0;
}

qi_value_t*  qi_value_list_get(qi_value_t *msg, unsigned int idx)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  if (container.kind() != QI_VALUE_KIND_LIST || idx >= container.size()) {
    return 0;
  }
  qi_value_t* ret = qi_value_create("");
  qi::GenericValue &gv = qi_value_cpp(ret);
  gv = container[idx];
  return ret;
}

int          qi_value_list_size(qi_value_t *msg)
{
  qi::GenericValue &container = qi_value_cpp(msg);
  if (container.kind() != QI_VALUE_KIND_LIST) {
    return -1;
  }
  return container.size();
}

//# OBJECT
qi_object_t* qi_value_get_object(qi_value_t* val)
{
  qi::GenericValuePtr &gv = qi_value_cpp(val);
  qi::ObjectPtr obj = gv.as<qi::ObjectPtr>();
  return qi_object_create_from(obj);
}

int          qi_value_set_object(qi_value_t* value, qi_object_t *o)
{
  qi::GenericValuePtr &gv = qi_value_cpp(value);
  qi::ObjectPtr &obj = qi_object_cpp(o);
  try {
    gv.set<qi::ObjectPtr>(obj);
    return 1;
  } catch (std::runtime_error&) {}
  return 0;
}

//# DYNAMIC
int          qi_value_dynamic_set(qi_value_t *container, qi_value_t* value)
{
  return 0;
}

qi_value_t*  qi_value_dynamic_get(qi_value_t *container)
{
  return 0;
}

//# MAP
unsigned int qi_value_map_size(qi_value_t *msg)
{
  return 0;
}

int         qi_value_map_set(qi_value_t *msg, qi_value_t *key, qi_value_t *value)
{
  return 0;
}

qi_value_t*  qi_value_map_get(qi_value_t *msg, qi_value_t *key)
{
  return 0;
}

//# RAW
int          qi_value_raw_set(qi_value_t* value, const char* data, int size){
  return 0;
}

int          qi_value_raw_get(qi_value_t* value, const char**data, int *size) {
  return 0;
}
<|endoftext|>


<commit_before>#include "xmlui/SessionXmlHandler.h"

using namespace std;
using namespace Poco;
using namespace Poco::Net;
using namespace Poco::XML;
using namespace BeeeOn;
using namespace BeeeOn::XmlUI;

SessionXmlHandler::SessionXmlHandler(
		const string &ns,
		const StreamSocket &socket,
		const AutoPtr<Document> input,
		Session::Ptr session):
	AbstractXmlHandler(ns, socket, input),
	m_session(session)
{
}

bool SessionXmlHandler::requireSession()
{
	if (!hasSession()) {
		resultNotAuthenticated();
		return false;
	}

	return true;
}

bool SessionXmlHandler::hasSession() const
{
	return !m_session.isNull();
}

const Session::Ptr SessionXmlHandler::session() const
{
	return m_session;
}

SessionXmlHandlerResolver::SessionXmlHandlerResolver(const string &ns):
	AbstractXmlHandlerResolver(ns)
{
}

Session::Ptr SessionXmlHandlerResolver::lookupSession(
		SessionManager &sessionManager,
		const AutoPtr<Document> input)
{
	const Element *root = input->documentElement();
	const string &sessionId = root->getAttribute("sessionid");
	ExpirableSession::Ptr session;

	if (!sessionManager.lookup(sessionId, session))
		return NULL;

	return session;
}
<commit_msg>SessionXmlHandlerResolver: sanitize sessionID<commit_after>#include "util/Sanitize.h"
#include "xmlui/SessionXmlHandler.h"

using namespace std;
using namespace Poco;
using namespace Poco::Net;
using namespace Poco::XML;
using namespace BeeeOn;
using namespace BeeeOn::XmlUI;

SessionXmlHandler::SessionXmlHandler(
		const string &ns,
		const StreamSocket &socket,
		const AutoPtr<Document> input,
		Session::Ptr session):
	AbstractXmlHandler(ns, socket, input),
	m_session(session)
{
}

bool SessionXmlHandler::requireSession()
{
	if (!hasSession()) {
		resultNotAuthenticated();
		return false;
	}

	return true;
}

bool SessionXmlHandler::hasSession() const
{
	return !m_session.isNull();
}

const Session::Ptr SessionXmlHandler::session() const
{
	return m_session;
}

SessionXmlHandlerResolver::SessionXmlHandlerResolver(const string &ns):
	AbstractXmlHandlerResolver(ns)
{
}

Session::Ptr SessionXmlHandlerResolver::lookupSession(
		SessionManager &sessionManager,
		const AutoPtr<Document> input)
{
	const Element *root = input->documentElement();
	const string &sessionId = Sanitize::base64(root->getAttribute("sessionid"));
	ExpirableSession::Ptr session;

	if (!sessionManager.lookup(sessionId, session))
		return NULL;

	return session;
}
<|endoftext|>


<commit_before>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <fstream>

#include "app.h"
#include "progressbar.h"
#include "dwi/tractography/file.h"
#include "dwi/tractography/properties.h"

MRTRIX_APPLICATION

using namespace MR;
using namespace MR::DWI;
using namespace App;

void usage ()
{
  DESCRIPTION
  + "print out information about track file";

  ARGUMENTS
  + Argument ("tracks", "the input track file.")
  .allow_multiple()
  .type_file ();

  OPTIONS
  + Option ("ascii",
            "save positions of each track in individual ascii files, with the "
            "specified prefix.")
  + Argument ("prefix");
}

void run ()
{

  Options opt = get_options ("ascii");
  size_t count = 0;

  for (size_t i = 0; i < argument.size(); ++i) {
    Tractography::Properties properties;
    Tractography::Reader<float> file;
    file.open (argument[i], properties);

    std::cout << "***********************************\n";
    std::cout << "  Tracks file: \"" << argument[i] << "\"\n";
    for (Tractography::Properties::iterator i = properties.begin(); i != properties.end(); ++i) {
      std::string S (i->first + ':');
      S.resize (22, ' ');
      std::cout << "    " << S << i->second << "\n";
    }

    if (properties.comments.size()) {
      std::cout << "    Comments:             ";
      for (std::vector<std::string>::iterator i = properties.comments.begin(); i != properties.comments.end(); ++i)
        std::cout << (i == properties.comments.begin() ? "" : "                       ") << *i << "\n";
    }

    for (std::multimap<std::string,std::string>::const_iterator i = properties.roi.begin(); i != properties.roi.end(); ++i)
      std::cout << "    ROI:                  " << i->first << " " << i->second << "\n";

    if (opt.size()) {
      ProgressBar progress ("writing track data to ascii files");
      std::vector<Point<float> > tck;
      while (file.next (tck)) {
        std::string filename (opt[0][0]);
        filename += "-000000.txt";
        std::string num (str (count));
        filename.replace (filename.size()-4-num.size(), num.size(), num);

        std::ofstream out (filename.c_str());
        if (!out) throw Exception ("error opening ascii file \"" + filename + "\": " + strerror (errno));

        for (std::vector<Point<float> >::iterator i = tck.begin(); i != tck.end(); ++i)
          out << (*i) [0] << " " << (*i) [1] << " " << (*i) [2] << "\n";

        out.close();

        count++;
        ++progress;
      }
    }
  }
}
<commit_msg>added option -count to tckinfo to verify actual number of tracks in file<commit_after>/*
    Copyright 2008 Brain Research Institute, Melbourne, Australia

    Written by J-Donald Tournier, 27/06/08.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <fstream>

#include "app.h"
#include "progressbar.h"
#include "dwi/tractography/file.h"
#include "dwi/tractography/properties.h"

MRTRIX_APPLICATION

using namespace MR;
using namespace MR::DWI;
using namespace App;

void usage ()
{
  DESCRIPTION
  + "print out information about track file";

  ARGUMENTS
  + Argument ("tracks", "the input track file.")
  .allow_multiple()
  .type_file ();

  OPTIONS
  + Option ("count",
            "count number of tracks in file explicitly, ignoring the header")

  + Option ("ascii",
            "save positions of each track in individual ascii files, with the "
            "specified prefix.")
  + Argument ("prefix");
}

void run ()
{

  Options opt = get_options ("ascii");
  bool actual_count = get_options ("count").size();

  for (size_t i = 0; i < argument.size(); ++i) {
    Tractography::Properties properties;
    Tractography::Reader<float> file;
    file.open (argument[i], properties);

    std::cout << "***********************************\n";
    std::cout << "  Tracks file: \"" << argument[i] << "\"\n";

    for (Tractography::Properties::iterator i = properties.begin(); i != properties.end(); ++i) {
      std::string S (i->first + ':');
      S.resize (22, ' ');
      std::cout << "    " << S << i->second << "\n";
    }

    if (properties.comments.size()) {
      std::cout << "    Comments:             ";
      for (std::vector<std::string>::iterator i = properties.comments.begin(); i != properties.comments.end(); ++i)
        std::cout << (i == properties.comments.begin() ? "" : "                       ") << *i << "\n";
    }

    for (std::multimap<std::string,std::string>::const_iterator i = properties.roi.begin(); i != properties.roi.end(); ++i)
      std::cout << "    ROI:                  " << i->first << " " << i->second << "\n";

    if (actual_count) {
      std::vector<Point<float> > tck;
      size_t count = 0;
      {
        ProgressBar progress ("counting tracks in file... ");
        while (file.next (tck)) {
          ++count;
          ++progress;
        }
      }
      std::cout << "actual count in file: " << count << "\n";
    }

    if (opt.size()) {
      ProgressBar progress ("writing track data to ascii files");
      std::vector<Point<float> > tck;
      size_t count = 0;
      while (file.next (tck)) {
        std::string filename (opt[0][0]);
        filename += "-000000.txt";
        std::string num (str (count));
        filename.replace (filename.size()-4-num.size(), num.size(), num);

        std::ofstream out (filename.c_str());
        if (!out) throw Exception ("error opening ascii file \"" + filename + "\": " + strerror (errno));

        for (std::vector<Point<float> >::iterator i = tck.begin(); i != tck.end(); ++i)
          out << (*i) [0] << " " << (*i) [1] << " " << (*i) [2] << "\n";

        out.close();

        count++;
        ++progress;
      }
    }
  }
}
<|endoftext|>


<commit_before>#include "Common.hpp"
#include "Config.hpp"

#include "raycaster/Raycaster.hpp"

#include "input/Input.hpp"
#include "input/InputCallbacks.hpp"
#include "input/ControllableCamera.hpp"

#include "scene/Scene.hpp"
#include "resources/ResourcesManager.hpp"
#include "graphics/ScreenQuad.hpp"

#include "helpers/Random.hpp"
#include "helpers/System.hpp"

#include <thread>

/**
 \defgroup RaytracerDemo Raytracer demo
 \brief A basic ray tracing demo.
 \ingroup Applications
 */

class RaytracerConfig : public Config {
public:

	RaytracerConfig(const std::vector<std::string> & argv) : Config(argv) {

		// Process arguments.
		for(const auto & arg : _rawArguments){
			const std::string key = arg.key;
			const std::vector<std::string> & values = arg.values;

			if(key == "samples" && values.size() >= 1){
				samples = size_t(std::stoi(values[0]));
			} else if(key == "depth" && values.size() >= 1){
				depth = size_t(std::stoi(values[0]));
			} else if(key == "scene" && values.size() >= 1){
				scene = values[0];
			} else if(key == "output" && values.size() >= 1){
				outputPath = values[0];
			}  else if(key == "wxh" && values.size() >= 2){
				size[0] = std::stoi(values[0]);
				size[1] = std::stoi(values[1]);
			}
		}
		// If no path passed, setup a default one.
		if(outputPath.empty()){
			outputPath 	= "./test_" + scene + "_" + std::to_string(samples) + "_" + std::to_string(depth)
						+ "_" + std::to_string(size.x) + "x" + std::to_string(size.y) + ".png";
		}

		// Detail help.
		_infos.emplace_back("", "", "Raytracer");
		_infos.emplace_back("wxh", "", "Dimensions of the image.", std::vector<std::string>{"width", "height"});
		_infos.emplace_back("samples", "", "Number of samples per pixel.", "int");
		_infos.emplace_back("depth", "", "Maximum path depth.", "int");
		_infos.emplace_back("scene", "", "Name of the scene to load.", "string");
		_infos.emplace_back("output", "", "Path for the output image.", "path");

	}

	glm::ivec2 size = glm::ivec2(1024);
	size_t samples = 8; ///< Number of samples per pixel.
	size_t depth = 5; ///< Max depth of a path.
	std::string outputPath = ""; ///< Output image path.
	std::string scene = ""; ///< Scene name.

};

/**
 The main function of the demo.
 \param argc the number of input arguments.
 \param argv a pointer to the raw input arguments.
 \return a general error code.
 \ingroup RaytracerDemo
 */
int main(int argc, char** argv) {

	RaytracerConfig config(std::vector<std::string>(argv, argv+argc));
	if(config.showHelp()){
		return 0;
	}

	if(config.scene.empty()){
		Log::Error() << "Missing scene name." << std::endl;
		return 1;
	}

	// Initialize random generator;
	Random::seed();
	Resources::manager().addResources("../../../resources/pbrdemo");
	Resources::manager().addResources("../../../resources/additional");

	// Load geometry and create raycaster.
	Scene scene(config.scene);
	scene.init(Storage::CPU);

	Raycaster raycaster;
	for(const auto & obj : scene.objects){
		raycaster.addMesh(obj.mesh()->geometry, obj.model());
	}
	raycaster.updateHierarchy();

	// Result image.
	Image render(config.size.x, config.size.y, 3);
	const size_t samples = config.samples;
	const size_t depth = config.depth;
	const float ratio = float(config.size.x)/float(config.size.y);

	// Setup camera.
	Camera camera;
	camera.pose(glm::vec3(0.0f, 1.0f, 2.5f), glm::vec3(0.0f, 1.0f, 1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
	camera.projection(ratio, 1.3f, 0.01f, 100.0f);
	// Compute incremental pixel shifts.
	glm::vec3 corner, dx, dy;
	camera.pixelShifts(corner, dx, dy);

	// Start chrono.
	auto start = std::chrono::steady_clock::now();

	// Parallelize on each row of the image.
	System::forParallel(0, render.height, [&](size_t y){
		for(size_t x = 0; x < render.width; ++x){

			for(size_t sid = 0; sid < samples; ++sid){
				// Draw random shift in [0.0,1.0f) for jittering.
				const float jx = Random::Float();
				const float jy = Random::Float();
				// Derive a position on the image plane from the pixel.
				const glm::vec2 ndcPos = glm::vec2(x + jx, y + jy) / glm::vec2(render.width, render.height);
				// Place the point on the near plane in clip space.
				const glm::vec3 worldPos = corner + ndcPos.x * dx + ndcPos.y * dy;

				glm::vec3 rayPos = camera.position();
				glm::vec3 rayDir = glm::normalize(worldPos - camera.position());

				glm::vec3 sampleColor(0.0f);
				glm::vec3 attenColor(1.0f);

				for(size_t did = 0; did < depth; ++did){
					// Query closest intersection.
					const Raycaster::RayHit hit = raycaster.intersects(rayPos, rayDir);

					// If no hit, background.
					if(!hit.hit){
						// For now the background is not emissive, it is only sampled for direct paths.
						/// \todo Support environment map fetch.
						if(depth == 0){
							const Scene::Background mode = scene.backgroundMode;
							if (mode == Scene::Background::IMAGE){
								const Image & image = scene.background.textures()[0]->images[0];
								sampleColor = image.rgbl(ndcPos.x, ndcPos.y);
							} else {
								sampleColor = scene.backgroundColor;
							}
						}
						break;
					}

					// Fetch geometry infos...
					const Mesh & mesh = scene.objects[hit.meshId].mesh()->geometry;
					const glm::vec3 p = rayPos + hit.dist * rayDir;
					const glm::vec3 n = Raycaster::interpolateNormal(hit, mesh);
					const glm::vec2 uv = Raycaster::interpolateUV(hit, mesh);

					// Compute lighting.
					// Check light visibility.
					glm::vec3 illumination(0.0f);
					for(const auto light : scene.lights){
						glm::vec3 direction;
						float attenuation;
						if(light->visible(p, raycaster, direction, attenuation)){
							const float diffuse = glm::max(glm::dot(n, direction), 0.0f);
							illumination += attenuation * diffuse * light->intensity();
						}
					}

					// Fetch base color from texture.
					const Image & image = scene.objects[hit.meshId].textures()[0]->images[0];
					const glm::vec3 baseColor = glm::pow(image.rgbl(uv.x, uv.y), glm::vec3(2.2f));

					// Bounce decay.
					attenColor *= baseColor;
					sampleColor += attenColor * illumination;

					// Update position and ray direction.
					if(did < depth-1){
						rayPos = p;
						// For the direction, we want to sample the hemisphere, weighted by the cosine weight to better use our samples.
						// We use the trick described by Peter Shirley in 'Raytracing in One Week-End':
						// Uniformly sample a sphere tangent to the surface, add this to the normal.
						rayDir = glm::normalize(n + Random::sampleSphere());
					}
				}
				// Modulate and store.
				render.rgb(x,y) += sampleColor;
			}
		}
	});

	// Normalize and gamma correction.
	System::forParallel(0, render.height, [&render, &samples](size_t y){
		for(size_t x = 0; x < render.width; ++x){
			const glm::vec3 color = render.rgb(x,y) / float(samples);
			render.rgb(x,y) = glm::pow(color, glm::vec3(1.0f/2.2f));
		}
	});

	// Display duration.
	auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
	Log::Info() << "Generation took " << duration.count() << " ms at " << render.width << "x" << render.height << "." << std::endl;

	// Save image.
	ImageUtilities::saveLDRImage(config.outputPath, render, false);
	return 0;
}

<commit_msg>Raytracer: first stab at cubemap sampling.<commit_after>#include "Common.hpp"
#include "Config.hpp"

#include "raycaster/Raycaster.hpp"

#include "input/Input.hpp"
#include "input/InputCallbacks.hpp"
#include "input/ControllableCamera.hpp"

#include "scene/Scene.hpp"
#include "resources/ResourcesManager.hpp"
#include "graphics/ScreenQuad.hpp"

#include "helpers/Random.hpp"
#include "helpers/System.hpp"

#include <thread>

/**
 \defgroup RaytracerDemo Raytracer demo
 \brief A basic ray tracing demo.
 \ingroup Applications
 */

class RaytracerConfig : public Config {
public:

	RaytracerConfig(const std::vector<std::string> & argv) : Config(argv) {

		// Process arguments.
		for(const auto & arg : _rawArguments){
			const std::string key = arg.key;
			const std::vector<std::string> & values = arg.values;

			if(key == "samples" && values.size() >= 1){
				samples = size_t(std::stoi(values[0]));
			} else if(key == "depth" && values.size() >= 1){
				depth = size_t(std::stoi(values[0]));
			} else if(key == "scene" && values.size() >= 1){
				scene = values[0];
			} else if(key == "output" && values.size() >= 1){
				outputPath = values[0];
			}  else if(key == "wxh" && values.size() >= 2){
				size[0] = std::stoi(values[0]);
				size[1] = std::stoi(values[1]);
			}
		}
		// If no path passed, setup a default one.
		if(outputPath.empty()){
			outputPath 	= "./test_" + scene + "_" + std::to_string(samples) + "_" + std::to_string(depth)
						+ "_" + std::to_string(size.x) + "x" + std::to_string(size.y) + ".png";
		}

		// Detail help.
		_infos.emplace_back("", "", "Raytracer");
		_infos.emplace_back("wxh", "", "Dimensions of the image.", std::vector<std::string>{"width", "height"});
		_infos.emplace_back("samples", "", "Number of samples per pixel.", "int");
		_infos.emplace_back("depth", "", "Maximum path depth.", "int");
		_infos.emplace_back("scene", "", "Name of the scene to load.", "string");
		_infos.emplace_back("output", "", "Path for the output image.", "path");

	}

	glm::ivec2 size = glm::ivec2(1024);
	size_t samples = 8; ///< Number of samples per pixel.
	size_t depth = 5; ///< Max depth of a path.
	std::string outputPath = ""; ///< Output image path.
	std::string scene = ""; ///< Scene name.

};

glm::vec3 sampleCubemap(const std::vector<Image> & images, const glm::vec3 & dir){
	// Images are stored in the following order:
	// px, nx, py, ny, pz, nz
	const glm::vec3 abs = glm::abs(dir);
	int side = 0;
	float x = 0.0f, y = 0.0f;
	if(abs.x >= abs.y && abs.x >= abs.y){
		y = abs.y / abs.x;
		// X faces.
		if(dir.x >= 0.0f){
			side = 0;
			x = -abs.z / abs.x;
		} else {
			side = 1;
			x = abs.z / abs.x;
		}

	} else if(abs.y >= abs.x && abs.y >= abs.z){
		x = abs.x / abs.y;
		// Y faces.
		if(dir.y >= 0.0f){
			side = 2;
			y = -abs.z / abs.y;
		} else {
			side = 3;
			y = abs.z / abs.y;
		}
	} else if(abs.z >= abs.x && abs.z >= abs.y){
		y = abs.y / abs.z;
		// Z faces.
		if(dir.z >= 0.0f){
			side = 4;
			x = abs.x / abs.z;
		} else {
			side = 5;
			x = -abs.x / abs.z;
		}
	}
	x = 0.5f * x + 0.5f;
	y = 0.5f * y + 0.5f;
	return images[side].rgbl(x, y);
}

/**
 The main function of the demo.
 \param argc the number of input arguments.
 \param argv a pointer to the raw input arguments.
 \return a general error code.
 \ingroup RaytracerDemo
 */
int main(int argc, char** argv) {

	RaytracerConfig config(std::vector<std::string>(argv, argv+argc));
	if(config.showHelp()){
		return 0;
	}

	if(config.scene.empty()){
		Log::Error() << "Missing scene name." << std::endl;
		return 1;
	}

	// Initialize random generator;
	Random::seed();
	Resources::manager().addResources("../../../resources/pbrdemo");
	Resources::manager().addResources("../../../resources/additional");

	// Load geometry and create raycaster.
	Scene scene(config.scene);
	scene.init(Storage::CPU);

	Raycaster raycaster;
	for(const auto & obj : scene.objects){
		raycaster.addMesh(obj.mesh()->geometry, obj.model());
	}
	raycaster.updateHierarchy();

	// Result image.
	Image render(config.size.x, config.size.y, 3);
	const size_t samples = config.samples;
	const size_t depth = config.depth;
	const float ratio = float(config.size.x)/float(config.size.y);

	// Setup camera.
	Camera camera;
	//camera.pose(glm::vec3(0.0f, 1.0f, 2.5f), glm::vec3(0.0f, 1.0f, 1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
	camera.pose(glm::vec3(0.0f, 0.0f, 2.5f), glm::vec3(0.0f, 0.0f, 1.5f), glm::vec3(0.0f, 1.0f, 0.0f));
	camera.projection(ratio, 1.3f, 0.01f, 100.0f);
	// Compute incremental pixel shifts.
	glm::vec3 corner, dx, dy;
	camera.pixelShifts(corner, dx, dy);

	// Start chrono.
	auto start = std::chrono::steady_clock::now();

	// Parallelize on each row of the image.
	System::forParallel(0, render.height, [&](size_t y){
		for(size_t x = 0; x < render.width; ++x){

			for(size_t sid = 0; sid < samples; ++sid){
				// Draw random shift in [0.0,1.0f) for jittering.
				const float jx = Random::Float();
				const float jy = Random::Float();
				// Derive a position on the image plane from the pixel.
				const glm::vec2 ndcPos = glm::vec2(x + jx, y + jy) / glm::vec2(render.width, render.height);
				// Place the point on the near plane in clip space.
				const glm::vec3 worldPos = corner + ndcPos.x * dx + ndcPos.y * dy;

				glm::vec3 rayPos = camera.position();
				glm::vec3 rayDir = glm::normalize(worldPos - camera.position());

				glm::vec3 sampleColor(0.0f);
				glm::vec3 attenColor(1.0f);

				for(size_t did = 0; did < depth; ++did){
					// Query closest intersection.
					const Raycaster::RayHit hit = raycaster.intersects(rayPos, rayDir);

					// If no hit, background.
					if(!hit.hit){
						// For now the background is not emissive, it is only sampled for direct paths.
						/// \todo Support environment map fetch.
						if(did == 0){
							const Scene::Background mode = scene.backgroundMode;
							if (mode == Scene::Background::IMAGE){
								const Image & image = scene.background.textures()[0]->images[0];
								sampleColor = image.rgbl(ndcPos.x, ndcPos.y);
							} else if (mode == Scene::Background::SKYBOX){
								const auto & images = scene.background.textures()[0]->images;
								sampleColor = sampleCubemap(images, glm::normalize(rayDir));
							} else {
								sampleColor = scene.backgroundColor;
							}
						}
						break;
					}

					// Fetch geometry infos...
					const Mesh & mesh = scene.objects[hit.meshId].mesh()->geometry;
					const glm::vec3 p = rayPos + hit.dist * rayDir;
					const glm::vec3 n = Raycaster::interpolateNormal(hit, mesh);
					const glm::vec2 uv = Raycaster::interpolateUV(hit, mesh);

					// Compute lighting.
					// Check light visibility.
					glm::vec3 illumination(0.0f);
					for(const auto light : scene.lights){
						glm::vec3 direction;
						float attenuation;
						if(light->visible(p, raycaster, direction, attenuation)){
							const float diffuse = glm::max(glm::dot(n, direction), 0.0f);
							illumination += attenuation * diffuse * light->intensity();
						}
					}

					// Fetch base color from texture.
					const Image & image = scene.objects[hit.meshId].textures()[0]->images[0];
					const glm::vec3 baseColor = glm::pow(image.rgbl(uv.x, uv.y), glm::vec3(2.2f));

					// Bounce decay.
					attenColor *= baseColor;
					sampleColor += attenColor * illumination;

					// Update position and ray direction.
					if(did < depth-1){
						rayPos = p;
						// For the direction, we want to sample the hemisphere, weighted by the cosine weight to better use our samples.
						// We use the trick described by Peter Shirley in 'Raytracing in One Week-End':
						// Uniformly sample a sphere tangent to the surface, add this to the normal.
						rayDir = glm::normalize(n + Random::sampleSphere());
					}
				}
				// Modulate and store.
				render.rgb(x,y) += sampleColor;
			}
		}
	});

	// Normalize and gamma correction.
	System::forParallel(0, render.height, [&render, &samples](size_t y){
		for(size_t x = 0; x < render.width; ++x){
			const glm::vec3 color = render.rgb(x,y) / float(samples);
			render.rgb(x,y) = glm::pow(color, glm::vec3(1.0f/2.2f));
		}
	});

	// Display duration.
	auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
	Log::Info() << "Generation took " << duration.count() << " ms at " << render.width << "x" << render.height << "." << std::endl;

	// Save image.
	ImageUtilities::saveLDRImage(config.outputPath, render, false);
	return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/glue/plugins/webplugin_delegate_impl.h"

#include <string>
#include <vector>

#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_instance.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "webkit/glue/plugins/plugin_stream_url.h"
#include "webkit/glue/webkit_glue.h"

using webkit_glue::WebPlugin;
using webkit_glue::WebPluginDelegate;
using webkit_glue::WebPluginResourceClient;
using WebKit::WebCursorInfo;
using WebKit::WebKeyboardEvent;
using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;

WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
    const FilePath& filename,
    const std::string& mime_type,
    gfx::PluginWindowHandle containing_view) {
  scoped_refptr<NPAPI::PluginLib> plugin_lib =
      NPAPI::PluginLib::CreatePluginLib(filename);
  if (plugin_lib.get() == NULL)
    return NULL;

  NPError err = plugin_lib->NP_Initialize();
  if (err != NPERR_NO_ERROR)
    return NULL;

  scoped_refptr<NPAPI::PluginInstance> instance =
      plugin_lib->CreateInstance(mime_type);
  return new WebPluginDelegateImpl(containing_view, instance.get());
}

void WebPluginDelegateImpl::PluginDestroyed() {
  if (handle_event_depth_) {
    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
  } else {
    delete this;
  }
}

bool WebPluginDelegateImpl::Initialize(
    const GURL& url,
    const std::vector<std::string>& arg_names,
    const std::vector<std::string>& arg_values,
    WebPlugin* plugin,
    bool load_manually) {
  plugin_ = plugin;

  instance_->set_web_plugin(plugin_);
  if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) {
    NPAPI::PluginLib* plugin_lib = instance()->plugin_lib();
    if (plugin_lib->instance_count() > 1) {
      return false;
    }
  }

  if (quirks_ & PLUGIN_QUIRK_DIE_AFTER_UNLOAD)
    webkit_glue::SetForcefullyTerminatePluginProcess(true);

  int argc = 0;
  scoped_array<char*> argn(new char*[arg_names.size()]);
  scoped_array<char*> argv(new char*[arg_names.size()]);
  for (size_t i = 0; i < arg_names.size(); ++i) {
    if (quirks_ & PLUGIN_QUIRK_NO_WINDOWLESS &&
        LowerCaseEqualsASCII(arg_names[i], "windowlessvideo")) {
      continue;
    }
    argn[argc] = const_cast<char*>(arg_names[i].c_str());
    argv[argc] = const_cast<char*>(arg_values[i].c_str());
    argc++;
  }

  bool start_result = instance_->Start(
      url, argn.get(), argv.get(), argc, load_manually);
  if (!start_result)
    return false;

  windowless_ = instance_->windowless();
  if (!windowless_) {
    if (!WindowedCreatePlugin())
      return false;
  } else {
    // For windowless plugins we should set the containing window handle
    // as the instance window handle. This is what Safari does. Not having
    // a valid window handle causes subtle bugs with plugins which retrieve
    // the window handle and validate the same. The window handle can be
    // retrieved via NPN_GetValue of NPNVnetscapeWindow.
    instance_->set_window_handle(parent_);
  }

  bool should_load = PlatformInitialize();

  plugin_url_ = url.spec();

  return should_load;
}

void WebPluginDelegateImpl::DestroyInstance() {
  if (instance_ && (instance_->npp()->ndata != NULL)) {
    // Shutdown all streams before destroying so that
    // no streams are left "in progress".  Need to do
    // this before calling set_web_plugin(NULL) because the
    // instance uses the helper to do the download.
    instance_->CloseStreams();

    window_.window = NULL;
    if (!(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
      instance_->NPP_SetWindow(&window_);
    }

    instance_->NPP_Destroy();

    instance_->set_web_plugin(NULL);

    PlatformDestroyInstance();

    instance_ = 0;
  }
}

void WebPluginDelegateImpl::UpdateGeometry(
    const gfx::Rect& window_rect,
    const gfx::Rect& clip_rect) {

  if (first_set_window_call_) {
    first_set_window_call_ = false;
    // Plugins like media player on Windows have a bug where in they handle the
    // first geometry update and ignore the rest resulting in painting issues.
    // This quirk basically ignores the first set window call sequence for
    // these plugins and has been tested for Windows plugins only.
    if (quirks_ & PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL)
      return;
  }

  if (windowless_) {
    WindowlessUpdateGeometry(window_rect, clip_rect);
  } else {
    WindowedUpdateGeometry(window_rect, clip_rect);
  }
}

void WebPluginDelegateImpl::SetFocus(bool focused) {
  DCHECK(windowless_);
  // This is called when internal WebKit focus (the focused element on the page)
  // changes, but plugins need to know about OS-level focus, so we have an extra
  // layer of focus tracking.
  has_webkit_focus_ = focused;
  if (containing_view_has_focus_)
    SetPluginHasFocus(focused);
}

void WebPluginDelegateImpl::SetPluginHasFocus(bool focused) {
  if (focused == plugin_has_focus_)
    return;
  if (PlatformSetPluginHasFocus(focused))
    plugin_has_focus_ = focused;
}

void WebPluginDelegateImpl::SetContentAreaHasFocus(bool has_focus) {
  containing_view_has_focus_ = has_focus;
  if (!windowless_)
    return;
  SetPluginHasFocus(containing_view_has_focus_ && has_webkit_focus_);
}

NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
  return instance_->GetPluginScriptableObject();
}

void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL& url,
                                                    NPReason reason,
                                                    int notify_id) {
  if (quirks_ & PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS &&
      reason == NPRES_NETWORK_ERR) {
    // Flash needs this or otherwise it unloads the launching swf object.
    reason = NPRES_DONE;
  }

  instance()->DidFinishLoadWithReason(url, reason, notify_id);
}

int WebPluginDelegateImpl::GetProcessId() {
  // We are in process, so the plugin pid is this current process pid.
  return base::GetCurrentProcId();
}

void WebPluginDelegateImpl::SendJavaScriptStream(const GURL& url,
                                                 const std::string& result,
                                                 bool success,
                                                 int notify_id) {
  instance()->SendJavaScriptStream(url, result, success, notify_id);
}

void WebPluginDelegateImpl::DidReceiveManualResponse(
    const GURL& url, const std::string& mime_type,
    const std::string& headers, uint32 expected_length, uint32 last_modified) {
  if (!windowless_) {
    // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in
    // Flash.  See http://b/issue?id=892174.
    DCHECK(windowed_did_set_window_);
  }

  instance()->DidReceiveManualResponse(url, mime_type, headers,
                                       expected_length, last_modified);
}

void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
                                                 int length) {
  instance()->DidReceiveManualData(buffer, length);
}

void WebPluginDelegateImpl::DidFinishManualLoading() {
  instance()->DidFinishManualLoading();
}

void WebPluginDelegateImpl::DidManualLoadFail() {
  instance()->DidManualLoadFail();
}

FilePath WebPluginDelegateImpl::GetPluginPath() {
  return instance()->plugin_lib()->plugin_info().path;
}

void WebPluginDelegateImpl::WindowedUpdateGeometry(
    const gfx::Rect& window_rect,
    const gfx::Rect& clip_rect) {
  if (WindowedReposition(window_rect, clip_rect) ||
      !windowed_did_set_window_) {
    // Let the plugin know that it has been moved
    WindowedSetWindow();
  }
}

bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event,
                                             WebCursorInfo* cursor_info) {
  DCHECK(windowless_) << "events should only be received in windowless mode";

  bool pop_user_gesture = false;
  if (IsUserGesture(event)) {
    pop_user_gesture = true;
    instance()->PushPopupsEnabledState(true);
  }

  bool handled = PlatformHandleInputEvent(event, cursor_info);

  if (pop_user_gesture) {
    instance()->PopPopupsEnabledState();
  }

  return handled;
}

bool WebPluginDelegateImpl::IsUserGesture(const WebInputEvent& event) {
  switch (event.type) {
    case WebInputEvent::MouseDown:
    case WebInputEvent::MouseUp:
    case WebInputEvent::KeyDown:
    case WebInputEvent::KeyUp:
      return true;
    default:
      return false;
  }
  return false;
}

WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
    unsigned long resource_id, const GURL& url, int notify_id) {
  return instance()->CreateStream(
      resource_id, url, std::string(), notify_id);
}

WebPluginResourceClient* WebPluginDelegateImpl::CreateSeekableResourceClient(
    unsigned long resource_id, int range_request_id) {
  return instance()->GetRangeRequest(range_request_id);
}
<commit_msg>Fix full screen mode for windowless flash plugins. Flash doesn't expect a "kill focus" message to be sent when the window is deactivated.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/glue/plugins/webplugin_delegate_impl.h"

#include <string>
#include <vector>

#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/scoped_ptr.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_instance.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "webkit/glue/plugins/plugin_stream_url.h"
#include "webkit/glue/webkit_glue.h"

using webkit_glue::WebPlugin;
using webkit_glue::WebPluginDelegate;
using webkit_glue::WebPluginResourceClient;
using WebKit::WebCursorInfo;
using WebKit::WebKeyboardEvent;
using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;

WebPluginDelegateImpl* WebPluginDelegateImpl::Create(
    const FilePath& filename,
    const std::string& mime_type,
    gfx::PluginWindowHandle containing_view) {
  scoped_refptr<NPAPI::PluginLib> plugin_lib =
      NPAPI::PluginLib::CreatePluginLib(filename);
  if (plugin_lib.get() == NULL)
    return NULL;

  NPError err = plugin_lib->NP_Initialize();
  if (err != NPERR_NO_ERROR)
    return NULL;

  scoped_refptr<NPAPI::PluginInstance> instance =
      plugin_lib->CreateInstance(mime_type);
  return new WebPluginDelegateImpl(containing_view, instance.get());
}

void WebPluginDelegateImpl::PluginDestroyed() {
  if (handle_event_depth_) {
    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
  } else {
    delete this;
  }
}

bool WebPluginDelegateImpl::Initialize(
    const GURL& url,
    const std::vector<std::string>& arg_names,
    const std::vector<std::string>& arg_values,
    WebPlugin* plugin,
    bool load_manually) {
  plugin_ = plugin;

  instance_->set_web_plugin(plugin_);
  if (quirks_ & PLUGIN_QUIRK_DONT_ALLOW_MULTIPLE_INSTANCES) {
    NPAPI::PluginLib* plugin_lib = instance()->plugin_lib();
    if (plugin_lib->instance_count() > 1) {
      return false;
    }
  }

  if (quirks_ & PLUGIN_QUIRK_DIE_AFTER_UNLOAD)
    webkit_glue::SetForcefullyTerminatePluginProcess(true);

  int argc = 0;
  scoped_array<char*> argn(new char*[arg_names.size()]);
  scoped_array<char*> argv(new char*[arg_names.size()]);
  for (size_t i = 0; i < arg_names.size(); ++i) {
    if (quirks_ & PLUGIN_QUIRK_NO_WINDOWLESS &&
        LowerCaseEqualsASCII(arg_names[i], "windowlessvideo")) {
      continue;
    }
    argn[argc] = const_cast<char*>(arg_names[i].c_str());
    argv[argc] = const_cast<char*>(arg_values[i].c_str());
    argc++;
  }

  bool start_result = instance_->Start(
      url, argn.get(), argv.get(), argc, load_manually);
  if (!start_result)
    return false;

  windowless_ = instance_->windowless();
  if (!windowless_) {
    if (!WindowedCreatePlugin())
      return false;
  } else {
    // For windowless plugins we should set the containing window handle
    // as the instance window handle. This is what Safari does. Not having
    // a valid window handle causes subtle bugs with plugins which retrieve
    // the window handle and validate the same. The window handle can be
    // retrieved via NPN_GetValue of NPNVnetscapeWindow.
    instance_->set_window_handle(parent_);
  }

  bool should_load = PlatformInitialize();

  plugin_url_ = url.spec();

  return should_load;
}

void WebPluginDelegateImpl::DestroyInstance() {
  if (instance_ && (instance_->npp()->ndata != NULL)) {
    // Shutdown all streams before destroying so that
    // no streams are left "in progress".  Need to do
    // this before calling set_web_plugin(NULL) because the
    // instance uses the helper to do the download.
    instance_->CloseStreams();

    window_.window = NULL;
    if (!(quirks_ & PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY)) {
      instance_->NPP_SetWindow(&window_);
    }

    instance_->NPP_Destroy();

    instance_->set_web_plugin(NULL);

    PlatformDestroyInstance();

    instance_ = 0;
  }
}

void WebPluginDelegateImpl::UpdateGeometry(
    const gfx::Rect& window_rect,
    const gfx::Rect& clip_rect) {

  if (first_set_window_call_) {
    first_set_window_call_ = false;
    // Plugins like media player on Windows have a bug where in they handle the
    // first geometry update and ignore the rest resulting in painting issues.
    // This quirk basically ignores the first set window call sequence for
    // these plugins and has been tested for Windows plugins only.
    if (quirks_ & PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL)
      return;
  }

  if (windowless_) {
    WindowlessUpdateGeometry(window_rect, clip_rect);
  } else {
    WindowedUpdateGeometry(window_rect, clip_rect);
  }
}

void WebPluginDelegateImpl::SetFocus(bool focused) {
  DCHECK(windowless_);
  // This is called when internal WebKit focus (the focused element on the page)
  // changes, but plugins need to know about OS-level focus, so we have an extra
  // layer of focus tracking.
  //
  // On Windows, historically browsers did not set focus events to windowless
  // plugins when the toplevel window focus changes. Sending such focus events
  // breaks full screen mode in Flash because it will come out of full screen
  // mode when it loses focus, and its full screen window causes the browser to
  // lose focus.
  has_webkit_focus_ = focused;
#ifndef OS_WIN
  if (containing_view_has_focus_)
    SetPluginHasFocus(focused);
#else
  SetPluginHasFocus(focused);
#endif
}

void WebPluginDelegateImpl::SetPluginHasFocus(bool focused) {
  if (focused == plugin_has_focus_)
    return;
  if (PlatformSetPluginHasFocus(focused))
    plugin_has_focus_ = focused;
}

void WebPluginDelegateImpl::SetContentAreaHasFocus(bool has_focus) {
  containing_view_has_focus_ = has_focus;
  if (!windowless_)
    return;
#ifndef OS_WIN  // See SetFocus above.
  SetPluginHasFocus(containing_view_has_focus_ && has_webkit_focus_);
#endif
}

NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
  return instance_->GetPluginScriptableObject();
}

void WebPluginDelegateImpl::DidFinishLoadWithReason(const GURL& url,
                                                    NPReason reason,
                                                    int notify_id) {
  if (quirks_ & PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS &&
      reason == NPRES_NETWORK_ERR) {
    // Flash needs this or otherwise it unloads the launching swf object.
    reason = NPRES_DONE;
  }

  instance()->DidFinishLoadWithReason(url, reason, notify_id);
}

int WebPluginDelegateImpl::GetProcessId() {
  // We are in process, so the plugin pid is this current process pid.
  return base::GetCurrentProcId();
}

void WebPluginDelegateImpl::SendJavaScriptStream(const GURL& url,
                                                 const std::string& result,
                                                 bool success,
                                                 int notify_id) {
  instance()->SendJavaScriptStream(url, result, success, notify_id);
}

void WebPluginDelegateImpl::DidReceiveManualResponse(
    const GURL& url, const std::string& mime_type,
    const std::string& headers, uint32 expected_length, uint32 last_modified) {
  if (!windowless_) {
    // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in
    // Flash.  See http://b/issue?id=892174.
    DCHECK(windowed_did_set_window_);
  }

  instance()->DidReceiveManualResponse(url, mime_type, headers,
                                       expected_length, last_modified);
}

void WebPluginDelegateImpl::DidReceiveManualData(const char* buffer,
                                                 int length) {
  instance()->DidReceiveManualData(buffer, length);
}

void WebPluginDelegateImpl::DidFinishManualLoading() {
  instance()->DidFinishManualLoading();
}

void WebPluginDelegateImpl::DidManualLoadFail() {
  instance()->DidManualLoadFail();
}

FilePath WebPluginDelegateImpl::GetPluginPath() {
  return instance()->plugin_lib()->plugin_info().path;
}

void WebPluginDelegateImpl::WindowedUpdateGeometry(
    const gfx::Rect& window_rect,
    const gfx::Rect& clip_rect) {
  if (WindowedReposition(window_rect, clip_rect) ||
      !windowed_did_set_window_) {
    // Let the plugin know that it has been moved
    WindowedSetWindow();
  }
}

bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event,
                                             WebCursorInfo* cursor_info) {
  DCHECK(windowless_) << "events should only be received in windowless mode";

  bool pop_user_gesture = false;
  if (IsUserGesture(event)) {
    pop_user_gesture = true;
    instance()->PushPopupsEnabledState(true);
  }

  bool handled = PlatformHandleInputEvent(event, cursor_info);

  if (pop_user_gesture) {
    instance()->PopPopupsEnabledState();
  }

  return handled;
}

bool WebPluginDelegateImpl::IsUserGesture(const WebInputEvent& event) {
  switch (event.type) {
    case WebInputEvent::MouseDown:
    case WebInputEvent::MouseUp:
    case WebInputEvent::KeyDown:
    case WebInputEvent::KeyUp:
      return true;
    default:
      return false;
  }
  return false;
}

WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
    unsigned long resource_id, const GURL& url, int notify_id) {
  return instance()->CreateStream(
      resource_id, url, std::string(), notify_id);
}

WebPluginResourceClient* WebPluginDelegateImpl::CreateSeekableResourceClient(
    unsigned long resource_id, int range_request_id) {
  return instance()->GetRangeRequest(range_request_id);
}
<|endoftext|>


<commit_before>//
// @file util.cc
// @brief Test project for folder dialogue.
// @author Mamoru Kaminaga
// @date 2019-07-02 18:56:28
// Copyright 2019 Mamoru Kaminaga
//
#include "./util.h"
#include <assert.h>
#include <shlobj.h>
#include <wchar.h>
#include <windows.h>

static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam,
                                       LPARAM lpData) {
  (void)hWnd;
  (void)lpData;

  wchar_t dir[MAX_PATH] = {0};
  ITEMIDLIST *pidl = NULL;

  switch (uMsg) {
    case BFFM_INITIALIZED:
      // The dialog box has finished initializing.
      break;
    case BFFM_IUNKNOWN:
      // An IUnknown interface is available to the dialog box.
      break;
    case BFFM_VALIDATEFAILED:
      // The user typed an invalid name into the dialog's edit box.
      // A nonexistent folder is considered an invalid name.
      MessageBox(hWnd, L"Invalid folder name!", L"Error", MB_OK);
      return 1;
    case BFFM_SELCHANGED:
      // The selection has changed in the dialog box.
      pidl = (ITEMIDLIST *)lParam;
      SHGetPathFromIDList(pidl, dir);
#ifdef DEBUG
      fwprintf(stderr, L"Select changed:%ls\n", dir);
      fwprintf(stderr, L"\n");
#endif
      break;
  }
  return 0;
}

bool GetDirectoryName(HWND hwnd, const wchar_t *title, const wchar_t *root_dir,
                      wchar_t *selected_dir) {
  assert(title);
  assert(selected_dir);

  PIDLIST_ABSOLUTE pidlRoot = NULL;

  // When root directory path is specified, the input path is converted to the
  // id list.
  if (root_dir != NULL) {
    // Root directory to item ID list.
    HRESULT hr = SHParseDisplayName((PCWSTR)root_dir, NULL, &pidlRoot, 0, NULL);
    if ((hr != S_OK) || (pidlRoot == NULL)) {
#ifdef DEBUG
      fwprintf(stderr, L"Invalid root directory\n");
#endif
      return false;
    }
  }

  // Set information about the folder dialog.
  BROWSEINFO bi;
  memset(&bi, 0, sizeof(BROWSEINFO));
  bi.hwndOwner = hwnd;
  bi.pidlRoot = pidlRoot;
  bi.pszDisplayName = (LPWSTR)selected_dir;
  bi.lpszTitle = title;
  bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_USENEWUI;
  bi.lpfn = BrowseCallbackProc;
  bi.lParam = (LPARAM)root_dir;

  // Displays a dialog box that enables you to select a shell folder.
  LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);
  if (pIDList == NULL) {
    selected_dir[0] = L'\0';
    return false;
  }

  //  Converts acquired item ID list to a file system path.
  if (!SHGetPathFromIDList(pIDList, selected_dir)) {
    CoTaskMemFree(pIDList);
    return false;
  }

  // Free the ID list allocated by SHBrowseForFolder.
  CoTaskMemFree(pIDList);
  return true;
}
<commit_msg>The behavior is OK<commit_after>//
// @file util.cc
// @brief Test project for folder dialogue.
// @author Mamoru Kaminaga
// @date 2019-07-02 18:56:28
// Copyright 2019 Mamoru Kaminaga
//
#include "./util.h"
#include <assert.h>
#include <shlobj.h>
#include <wchar.h>
#include <windows.h>

static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam,
                                       LPARAM lpData) {
  (void)hWnd;
  (void)lpData;

  wchar_t dir[MAX_PATH] = {0};
  ITEMIDLIST *pidl = NULL;

  switch (uMsg) {
    case BFFM_INITIALIZED:
      // The dialog box has finished initializing.
      break;
    case BFFM_IUNKNOWN:
      // An IUnknown interface is available to the dialog box.
      break;
    case BFFM_VALIDATEFAILED:
      // The user typed an invalid name into the dialog's edit box.
      // A nonexistent folder is considered an invalid name.
      MessageBox(hWnd, L"Invalid folder name!", L"Error", MB_OK);
      return 1;
    case BFFM_SELCHANGED:
      // The selection has changed in the dialog box.
#ifdef DEBUG
      pidl = (ITEMIDLIST *)lParam;
      SHGetPathFromIDList(pidl, dir);
      fwprintf(stderr, L"Select changed:%ls\n", dir);
      fwprintf(stderr, L"\n");
#endif
      break;
  }
  return 0;
}

bool GetDirectoryName(HWND hwnd, const wchar_t *title, const wchar_t *root_dir,
                      wchar_t *selected_dir) {
  assert(title);
  assert(selected_dir);

  PIDLIST_ABSOLUTE pidlRoot = NULL;

  // When root directory path is specified, the input path is converted to the
  // id list.
  if (root_dir != NULL) {
    // Root directory to item ID list.
    HRESULT hr = SHParseDisplayName((PCWSTR)root_dir, NULL, &pidlRoot, 0, NULL);
    if ((hr != S_OK) || (pidlRoot == NULL)) {
#ifdef DEBUG
      fwprintf(stderr, L"Invalid root directory\n");
#endif
      return false;
    }
  }

  // Set information about the folder dialog.
  BROWSEINFO bi;
  memset(&bi, 0, sizeof(BROWSEINFO));
  bi.hwndOwner = hwnd;
  bi.pidlRoot = pidlRoot;
  bi.pszDisplayName = (LPWSTR)selected_dir;
  bi.lpszTitle = title;
  bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_USENEWUI;
  bi.lpfn = BrowseCallbackProc;
  bi.lParam = (LPARAM)root_dir;

  // Displays a dialog box that enables you to select a shell folder.
  LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);
  if (pIDList == NULL) {
    selected_dir[0] = L'\0';
    return false;
  }

  //  Converts acquired item ID list to a file system path.
  if (!SHGetPathFromIDList(pIDList, selected_dir)) {
    CoTaskMemFree(pIDList);
    return false;
  }

  // Free the ID list allocated by SHBrowseForFolder.
  CoTaskMemFree(pIDList);
  return true;
}
<|endoftext|>