<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <iostream>
#include <fstream>

#include "Timer.h"

#define USAGE printf("Usage: cp src dst [flag]\n")

int main(int argc, char** argv) {
  Timer t1;
  Timer t2;
  Timer t3;

  int meth = 3;

  // proper # of args
  if (argc < 3 || argc > 4) {
    USAGE;
    exit(1);
  }
  bool test = (argc == 4) ? strcmp(argv[3], "--test") == 0 : false;
  for(int i = 3; i < argc; ++i) {
    if (strlen(argv[i]) >= 2 && argv[i][0] == '-') {
      argv[i][2] = 0;
      meth = atoi(argv[i] + 1);
    } else {
      USAGE;
      exit(1);
    }
  }

  struct stat a1;
  struct stat a2;

  if (stat(argv[1], &a1) == -1) {
    perror(argv[1]);
    exit(1);
  }

  if (stat(argv[2], &a2) != -1) {
    USAGE;
    printf("Usage: dst cannot exist or be a directory\n");
    exit(1);
  }

  errno = 0;

  if (S_ISDIR(a1.st_mode)) {
    USAGE;
    printf("Usage: src cannot be a directory\n");
    exit(1);
  }

  if (test) {
    goto tst;
ret:
    exit(0);
  }

  switch (meth) {
    case 1:    // istream/ostream
    {
tst:
      if (test) {
        t1.start();
      }
      std::ifstream fin(argv[1], std::ios::binary);
      if (!fin.good()) {
        printf("Error opening %s\n", argv[1]);
        exit(1);
      }

      std::ofstream fout(argv[2], std::ios::out);
      if (!fout.is_open()) {
        printf("Fatal error: can't open %s\n", argv[2]);
        exit(1);
      }

      char c = fin.get();
      while (fin.good()) {
        fout.put(c);
        c = fin.get();
      }
    }

    if (test) {
      double etime;
      printf("C++ istream:\n");
      t1.elapsedWallclockTime(etime);
      printf("Wall clock: %f\n", etime);
      t1.elapsedUserTime(etime);
      printf("User clock: %f\n", etime);
      t1.elapsedSystemTime(etime);
      printf("System clock: %f\n", etime);
    } else {
      break;
    }

    case 2:    // read/write 1 char at a time
    {
      if (test) {
        t2.start();
      }
      int fd1 = open(argv[1], O_RDONLY);
      if(fd1 == -1) {
        perror(argv[1]);
        exit(1);
      }
      int fd2 = creat(argv[2], a1.st_mode);
      if(fd2 == -1) {
        perror(argv[2]);
        exit(1);
      }

      char c;
      int rret = read(fd1, &c, 1);

      while (rret) {
        if (write(fd2, &c, rret) == -1) {
          perror("write");
          exit(1);
        }
        rret = read(fd1, &c, 1);
      }
      if (close(fd1) == -1) {
        perror("close fd1");
        exit(1);
      }
      if (close(fd2) == -1) {
        perror("close fd2");
        exit(1);
      }
    }

    if (test) {
      double etime;
      printf("\nread/write 1 char at a time:\n");
      t2.elapsedWallclockTime(etime);
      printf("Wall clock: %f\n", etime);
      t2.elapsedUserTime(etime);
      printf("User clock: %f\n", etime);
      t2.elapsedSystemTime(etime);
      printf("System clock: %f\n", etime);
    } else {
      break;
    }

    case 3:    // read/write BUFSIZ at a time
    {
      if (test) {
        t3.start();
      }
      int fd1 = open(argv[1], O_RDONLY);
      if(fd1 == -1) {
        perror(argv[1]);
        exit(1);
      }
      int fd2 = creat(argv[2], a1.st_mode);
      if(fd2 == -1) {
        perror(argv[2]);
        exit(1);
      }

      char c[BUFSIZ];
      int rret = read(fd1, &c, BUFSIZ);

      while (rret) {
        if (write(fd2, &c, rret) == -1) {
          perror("write");
          exit(1);
        }
        rret = read(fd1, &c, BUFSIZ);
      }
      if (close(fd1) == -1) {
        perror("close fd1");
        exit(1);
      }
      if (close(fd2) == -1) {
        perror("close fd2");
        exit(1);
      }
    }
    if (test) {
      double etime;
      printf("\nread/write BUFSIZ chars at a time:\n");
      t3.elapsedWallclockTime(etime);
      printf("Wall clock: %f\n", etime);
      t3.elapsedUserTime(etime);
      printf("User clock: %f\n", etime);
      t3.elapsedSystemTime(etime);
      printf("System clock: %f\n", etime);
      goto ret;
    } else {
      break;
    }

    default:
      printf("No.\n");
      exit(1);
  }

  return 0;
}

<commit_msg>error checking<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <iostream>
#include <fstream>

#include "Timer.h"

#define USAGE printf("Usage: cp src dst [flag]\n")

int main(int argc, char** argv) {
  Timer t1;
  Timer t2;
  Timer t3;

  int meth = 3;

  // proper # of args
  if (argc < 3 || argc > 4) {
    USAGE;
    exit(1);
  }
  bool test = (argc == 4) ? strcmp(argv[3], "--test") == 0 : false;
  for(int i = 3; i < argc; ++i) {
    if (strlen(argv[i]) >= 2 && argv[i][0] == '-') {
      argv[i][2] = 0;
      meth = atoi(argv[i] + 1);
    } else {
      USAGE;
      exit(1);
    }
  }

  struct stat a1;
  struct stat a2;

  if (stat(argv[1], &a1) == -1) {
    perror(argv[1]);
    exit(1);
  }

  if (stat(argv[2], &a2) != -1) {
    USAGE;
    printf("Usage: dst cannot exist or be a directory\n");
    exit(1);
  }

  errno = 0;

  if (S_ISDIR(a1.st_mode)) {
    USAGE;
    printf("Usage: src cannot be a directory\n");
    exit(1);
  }

  if (test) {
    goto tst;
ret:
    exit(0);
  }

  switch (meth) {
    case 1:    // istream/ostream
    {
tst:
      if (test) {
        t1.start();
      }
      std::ifstream fin(argv[1], std::ios::binary);
      if (!fin.good()) {
        printf("Error opening %s\n", argv[1]);
        exit(1);
      }

      std::ofstream fout(argv[2], std::ios::out);
      if (!fout.is_open()) {
        printf("Fatal error: can't open %s\n", argv[2]);
        exit(1);
      }

      char c = fin.get();
      while (fin.good()) {
        fout.put(c);
        c = fin.get();
      }
    }

    if (test) {
      double etime;
      printf("C++ istream:\n");
      t1.elapsedWallclockTime(etime);
      printf("Wall clock: %f\n", etime);
      t1.elapsedUserTime(etime);
      printf("User clock: %f\n", etime);
      t1.elapsedSystemTime(etime);
      printf("System clock: %f\n", etime);
    } else {
      break;
    }

    case 2:    // read/write 1 char at a time
    {
      if (test) {
        t2.start();
      }
      int fd1 = open(argv[1], O_RDONLY);
      if(fd1 == -1) {
        perror(argv[1]);
        exit(1);
      }
      int fd2 = creat(argv[2], a1.st_mode);
      if(fd2 == -1) {
        perror(argv[2]);
        exit(1);
      }

      char c;
      int rret = read(fd1, &c, 1);

      while (rret) {
        if (write(fd2, &c, rret) == -1) {
          perror("write");
          exit(1);
        }
        rret = read(fd1, &c, 1);
      }
      if (close(fd1) == -1) {
        perror("close fd1");
        exit(1);
      }
      if (close(fd2) == -1) {
        perror("close fd2");
        exit(1);
      }
    }

    if (test) {
      double etime;
      printf("\nread/write 1 char at a time:\n");
      t2.elapsedWallclockTime(etime);
      printf("Wall clock: %f\n", etime);
      t2.elapsedUserTime(etime);
      printf("User clock: %f\n", etime);
      t2.elapsedSystemTime(etime);
      printf("System clock: %f\n", etime);
    } else {
      break;
    }

    case 3:    // read/write BUFSIZ at a time
    {
      if (test) {
        t3.start();
      }
      int fd1 = open(argv[1], O_RDONLY);
      if(fd1 == -1) {
        perror(argv[1]);
        exit(1);
      }
      int fd2 = creat(argv[2], a1.st_mode);
      if(fd2 == -1) {
        perror(argv[2]);
        exit(1);
      }

      char c[BUFSIZ];
      int rret = read(fd1, &c, BUFSIZ);

      while (rret) {
        if (write(fd2, &c, rret) == -1) {
          perror("write");
          exit(1);
        }
        rret = read(fd1, &c, BUFSIZ);
      }
      if (close(fd1) == -1) {
        perror("close fd1");
        exit(1);
      }
      if (close(fd2) == -1) {
        perror("close fd2");
        exit(1);
      }
    }
    if (test) {
      double etime;
      printf("\nread/write BUFSIZ chars at a time:\n");
      t3.elapsedWallclockTime(etime);
      printf("Wall clock: %f\n", etime);
      t3.elapsedUserTime(etime);
      printf("User clock: %f\n", etime);
      t3.elapsedSystemTime(etime);
      printf("System clock: %f\n", etime);
      goto ret;
    } else {
      break;
    }

    default:
      printf("No.\n");
      exit(1);
  }

  return 0;
  perror("fixed");
  perror("fixed");
  perror("fixed");
  perror("fixed");
  perror("fixed");
}

<|endoftext|>


<commit_before>#include "Diagnostics.h"

#include <string>
#include <usb.h>
#include <sys/stat.h> // To check if a file exists
#include <std_msgs/String.h> // For creating ROS string messages
#include <ctime> // For time()

using namespace std;
using namespace gazebo;

Diagnostics::Diagnostics(std::string name) {

  this->publishedName = name;
  diagLogPublisher = nodeHandle.advertise<std_msgs::String>("/diagsLog", 1, true);
  diagnosticDataPublisher  = nodeHandle.advertise<std_msgs::Float32MultiArray>("/"+publishedName+"/diagnostics", 10);
  fingerAngleSubscribe = nodeHandle.subscribe(publishedName + "/fingerAngle/prev_cmd", 10, &Diagnostics::fingerTimestampUpdate, this);
  wristAngleSubscribe = nodeHandle.subscribe(publishedName + "/fingerAngle/prev_cmd", 10, &Diagnostics::wristTimestampUpdate, this);
  imuSubscribe = nodeHandle.subscribe(publishedName + "/imu", 10, &Diagnostics::imuTimestampUpdate, this);
  odometrySubscribe = nodeHandle.subscribe(publishedName + "/odom", 10, &Diagnostics::odometryTimestampUpdate, this);
  sonarLeftSubscribe = nodeHandle.subscribe(publishedName + "/sonarLeft", 10, &Diagnostics::sonarLeftTimestampUpdate, this);
  sonarCenterSubscribe = nodeHandle.subscribe(publishedName + "/sonarCenter", 10, &Diagnostics::sonarCenterTimestampUpdate, this);
  sonarRightSubscribe = nodeHandle.subscribe(publishedName + "/sonarRight", 10, &Diagnostics::sonarRightTimestampUpdate, this);

  // Initialize the variables we use to track the simulation update rate
  prevRealTime = common::Time(0.0);
  prevSimTime = common::Time(0.0);
  simRate = 0.0f;

  // Setup sensor check timers
  sensorCheckTimer = nodeHandle.createTimer(ros::Duration(sensorCheckInterval), &Diagnostics::sensorCheckTimerEventHandler, this);

 simCheckTimer = nodeHandle.createTimer(ros::Duration(sensorCheckInterval), &Diagnostics::simCheckTimerEventHandler, this);

  if ( checkIfSimulatedRover() ) {
    // For processing gazebo messages from the world stats topic.
    // Used to gather information for simulated rovers

    // Create fake argv and argc for the gazebo setup
    char  arg0[] = "diagnostics";
    char* argv[] = { &arg0[0], NULL };
    int   argc   = (int)(sizeof(argv) / sizeof(argv[0])) - 1;
    gazebo::setupClient(argc, argv);

    // Create Gazebo node and init
    gazebo::transport::NodePtr newNode(new gazebo::transport::Node());
    gazeboNode = newNode;
    gazeboNode->Init();
    string worldStatsTopic = "/gazebo/default/world_stats";
    worldStatsSubscriber = gazeboNode->Subscribe(worldStatsTopic, &Diagnostics::simWorldStatsEventHandler, this);

    simulated = true;
    publishInfoLogMessage("Diagnostic Package Started. Simulated Rover.");
  } else {
    simulated = false;
    publishInfoLogMessage("Diagnostic Package Started. Physical Rover. ");

    try {
      string name = wirelessDiags.setInterface();
      publishInfoLogMessage("Monitoring wireless interface " + name);
    } catch( exception &e ) {
      publishErrorLogMessage("Error setting interface name for wireless diagnostics: " + string(e.what()));
    }
  }
}

void Diagnostics::publishDiagnosticData() {
  if (!simulated) {
  WirelessInfo info;

  // Get info about the wireless interface
  // Catch and display an error if there was an exception
  try {
    info = wirelessDiags.getInfo();
  } catch( exception &e ){
    publishErrorLogMessage(e.what());
  return;
}

  std_msgs::Float32MultiArray rosMsg;
  rosMsg.data.clear();
  rosMsg.data.push_back(info.quality);
  rosMsg.data.push_back(info.bandwidthUsed);
  rosMsg.data.push_back(-1); // Sim update rate
  diagnosticDataPublisher.publish(rosMsg);
  }
}

void Diagnostics::publishErrorLogMessage(std::string msg) {

  std_msgs::String ros_msg;
  ros_msg.data = "" + publishedName+" ("+getHumanFriendlyTime()+"): " + msg + "";
  diagLogPublisher.publish(ros_msg);

}

void Diagnostics::publishWarningLogMessage(std::string msg) {
  std_msgs::String ros_msg;
  ros_msg.data = "" + publishedName+" ("+getHumanFriendlyTime()+"): " + msg + "";
  diagLogPublisher.publish(ros_msg);
}

void Diagnostics::publishInfoLogMessage(std::string msg) {
  std_msgs::String ros_msg;
  ros_msg.data = "" + publishedName + " ("+getHumanFriendlyTime()+"): " + msg + "";
  diagLogPublisher.publish(ros_msg);
}

void Diagnostics::fingerTimestampUpdate(const geometry_msgs::QuaternionStamped::ConstPtr& message) {
	fingersTimestamp = message->header.stamp;
}

void Diagnostics::wristTimestampUpdate(const geometry_msgs::QuaternionStamped::ConstPtr& message) {
	wristTimestamp = message->header.stamp;
}

void Diagnostics::imuTimestampUpdate(const sensor_msgs::Imu::ConstPtr& message) {
	imuTimestamp = message->header.stamp;
}

void Diagnostics::odometryTimestampUpdate(const nav_msgs::Odometry::ConstPtr& message) {
	odometryTimestamp = message->header.stamp;
}

void Diagnostics::sonarLeftTimestampUpdate(const sensor_msgs::Range::ConstPtr& message) {
	sonarLeftTimestamp = message->header.stamp;
}

void Diagnostics::sonarCenterTimestampUpdate(const sensor_msgs::Range::ConstPtr& message) {
	sonarCenterTimestamp = message->header.stamp;
}

void Diagnostics::sonarRightTimestampUpdate(const sensor_msgs::Range::ConstPtr& message) {
	sonarRightTimestamp = message->header.stamp;
}

// Return the current time in this timezone in "WeekDay Month Day hr:mni:sec year" format.
// We use this instead of asctime or ctime because it is thread safe
string Diagnostics::getHumanFriendlyTime() {
   time_t t = std::time(NULL);
   char humanReadableStr[100];

   if (strftime(humanReadableStr, sizeof(humanReadableStr), "%A %c", localtime(&t)))
     return humanReadableStr;
   else
     return ""; // There was a problem getting the time. Return the empty string.

}

// sensor check timeout handler. This function is triggered periodically and calls the
// sensor check functions.
void Diagnostics::sensorCheckTimerEventHandler(const ros::TimerEvent& event) {

  if (!simulated) {
  checkIMU();
  checkGPS();
  checkSonar();
  checkCamera();
  checkGripper();
  checkOdometry();

  publishDiagnosticData();
  }

}

void Diagnostics::simCheckTimerEventHandler(const ros::TimerEvent& event) {

  if (simulated) {
    std_msgs::Float32MultiArray rosMsg;
    rosMsg.data.clear();
    rosMsg.data.push_back(0.0f);
 rosMsg.data.push_back(0.0f);
    rosMsg.data.push_back(checkSimRate());
    diagnosticDataPublisher.publish(rosMsg);
  }

}

float Diagnostics::checkSimRate() {
  return simRate;
}

void Diagnostics::checkIMU() {
  // Example
  //publishWarningLogMessage("IMU Warning");
	if (ros::Time::now() - imuTimestamp <= ros::Duration(2.0)) {
		if (!imuConnected) {
			imuConnected = true;
			publishInfoLogMessage("IMU connected");
		}
	}
	else if (imuConnected) {
		imuConnected = false;
		publishErrorLogMessage("IMU is not connected");
	}
}

void Diagnostics::checkGPS() {
  // Example
  //publishWarningLogMessage("GPS Warning");

  // Check that a U-Blox device exists in the connected USB devices list

  if ( checkGPSExists() ) {
    // Notify the GUI only if reconnected after being previously disconnected
    if (!GPSConnected) publishInfoLogMessage("GPS reconnected");
    GPSConnected = true;
  } else {
    if (GPSConnected) // Guard against repeating the error.
      publishErrorLogMessage("GPS is not connected");
    GPSConnected = false;
  }
}

void Diagnostics::checkCamera() {
    // Example
  //publishWarningLogMessage("Camera Warning");

  // Check that a Logitec c170 device exists in the connected USB devices list
  if ( checkCameraExists() ) {
    // Notify the GUI only if reconnected after being previously disconnected
    if (!cameraConnected) publishInfoLogMessage("Camera reconnected");
    cameraConnected = true;
  } else {
    publishErrorLogMessage("Camera not connected");
    cameraConnected = false;
  }
}

void Diagnostics::checkSonar() {
  //Example
  //publishErrorLogMessage("Sonar Error");

	if (ros::Time::now() - sonarLeftTimestamp <= ros::Duration(2.0)) {
		if (!sonarLeftConnected) {
			sonarLeftConnected = true;
			publishInfoLogMessage("Left ultrasound connected");
		}
	}
	else if (sonarLeftConnected) {
		sonarLeftConnected = false;
		publishErrorLogMessage("Left ultrasound is not connected");
	}

	if (ros::Time::now() - sonarCenterTimestamp <= ros::Duration(2.0)) {
		if (!sonarCenterConnected) {
			sonarCenterConnected = true;
			publishInfoLogMessage("Center ultrasound connected");
		}
	}
	else if (sonarCenterConnected) {
		sonarCenterConnected = false;
		publishErrorLogMessage("Center ultrasound is not connected");
	}

	if (ros::Time::now() - sonarRightTimestamp <= ros::Duration(2.0)) {
		if (!sonarRightConnected) {
			sonarRightConnected = true;
			publishInfoLogMessage("Right ultrasound connected");
		}
	}
	else if (sonarRightConnected) {
		sonarRightConnected = false;
		publishErrorLogMessage("Right ultrasound is not connected");
	}
}

void Diagnostics::checkGripper() {
	// Example
	//publishWarningLogMessage("Gripper Warning");

	if (ros::Time::now() - fingersTimestamp > ros::Duration(2.0)) {
		if (!fingersConnected) {
			fingersConnected = true;
			publishInfoLogMessage("Gripper fingers connected");
		}
	}
	else if (fingersConnected) {
		fingersConnected = false;
		publishErrorLogMessage("Gripper fingers are not connected");
	}

	if (ros::Time::now() - wristTimestamp > ros::Duration(2.0)) {
		if (!wristConnected) {
			wristConnected = true;
			publishInfoLogMessage("Gripper wrist connected");
		}
	}
	else if (wristConnected) {
		wristConnected = false;
		publishErrorLogMessage("Gripper wrist is not connected");
	}
}

void Diagnostics::checkOdometry() {
	// Example
	//publishWarningLogMessage("Odometry Warning");

	if (ros::Time::now() - odometryTimestamp <= ros::Duration(2.0)) {
		if (!odometryConnected) {
			odometryConnected = true;
			publishInfoLogMessage("Encoders connected");
		}
	}
	else if (odometryConnected) {
		odometryConnected = false;
		publishErrorLogMessage("Encoders are not connected");
	}
}

// Check if the U-Blox GPS is connected
// ID_VENDOR = 0x1546
// ID_PRODUCT = 0x01a6
bool Diagnostics::checkGPSExists(){
  uint16_t GPSVendorID = 0x1546;
  uint16_t GPSProductID = 0x01a6;
  return checkUSBDeviceExists( GPSVendorID, GPSProductID );
}

// Check if the Logitech c170 camera is connected
// ID_VENDOR = 0x046d
// ID_PRODUCT = 0x082b
bool Diagnostics::checkCameraExists(){
  uint16_t cameraVendorID = 0x046d;
  uint16_t cameraProductID = 0x082b;
  return checkUSBDeviceExists( cameraVendorID, cameraProductID );
}

// Search through the connected USB devices for one that matches the
// specified vendorID and productID
bool Diagnostics::checkUSBDeviceExists(uint16_t vendorID, uint16_t productID){

  struct usb_bus *bus;
  struct usb_device *dev;
  usb_init();
  usb_find_busses();
  usb_find_devices();

  // Iterate through busses and devices
  for (bus = usb_busses; bus; bus = bus->next)
    for (dev = bus->devices; dev; dev = dev->next)
      if ( dev->descriptor.idVendor == vendorID && dev->descriptor.idProduct == productID )
        return true;

  // GPS not found
  return false;
}

void Diagnostics::simWorldStatsEventHandler(ConstWorldStatisticsPtr &msg) {

  const msgs::Time simTimeMsg = msg->sim_time();
  const msgs::Time realTimeMsg = msg->real_time();

  common::Time simTime(simTimeMsg.sec(), simTimeMsg.nsec());
  common::Time realTime(realTimeMsg.sec(), realTimeMsg.nsec());

  common::Time deltaSimTime = simTime - prevSimTime;
  common::Time deltaRealTime = realTime - prevRealTime;

  prevSimTime = simTime;
  prevRealTime = realTime;

  simRate = (deltaSimTime.Double())/(deltaRealTime.Double());
}

// Check whether a rover model file exists with the same name as this rover name
// if not then we should be a physcial rover. Need a better method.
bool Diagnostics::checkIfSimulatedRover() {
  struct stat buffer;
  const char *model_path_env = "GAZEBO_MODEL_PATH";
  char *model_root = getenv(model_path_env);
  string model_path = string(model_root)+"/"+publishedName+"/model.sdf";
  return (stat(model_path.c_str(), &buffer) == 0);
}

Diagnostics::~Diagnostics() {
  gazebo::shutdown();
}

<commit_msg>Correct camera diagnostics function to avoid repeated errors<commit_after>#include "Diagnostics.h"

#include <string>
#include <usb.h>
#include <sys/stat.h> // To check if a file exists
#include <std_msgs/String.h> // For creating ROS string messages
#include <ctime> // For time()

using namespace std;
using namespace gazebo;

Diagnostics::Diagnostics(std::string name) {

  this->publishedName = name;
  diagLogPublisher = nodeHandle.advertise<std_msgs::String>("/diagsLog", 1, true);
  diagnosticDataPublisher  = nodeHandle.advertise<std_msgs::Float32MultiArray>("/"+publishedName+"/diagnostics", 10);
  fingerAngleSubscribe = nodeHandle.subscribe(publishedName + "/fingerAngle/prev_cmd", 10, &Diagnostics::fingerTimestampUpdate, this);
  wristAngleSubscribe = nodeHandle.subscribe(publishedName + "/fingerAngle/prev_cmd", 10, &Diagnostics::wristTimestampUpdate, this);
  imuSubscribe = nodeHandle.subscribe(publishedName + "/imu", 10, &Diagnostics::imuTimestampUpdate, this);
  odometrySubscribe = nodeHandle.subscribe(publishedName + "/odom", 10, &Diagnostics::odometryTimestampUpdate, this);
  sonarLeftSubscribe = nodeHandle.subscribe(publishedName + "/sonarLeft", 10, &Diagnostics::sonarLeftTimestampUpdate, this);
  sonarCenterSubscribe = nodeHandle.subscribe(publishedName + "/sonarCenter", 10, &Diagnostics::sonarCenterTimestampUpdate, this);
  sonarRightSubscribe = nodeHandle.subscribe(publishedName + "/sonarRight", 10, &Diagnostics::sonarRightTimestampUpdate, this);

  // Initialize the variables we use to track the simulation update rate
  prevRealTime = common::Time(0.0);
  prevSimTime = common::Time(0.0);
  simRate = 0.0f;

  // Setup sensor check timers
  sensorCheckTimer = nodeHandle.createTimer(ros::Duration(sensorCheckInterval), &Diagnostics::sensorCheckTimerEventHandler, this);

 simCheckTimer = nodeHandle.createTimer(ros::Duration(sensorCheckInterval), &Diagnostics::simCheckTimerEventHandler, this);

  if ( checkIfSimulatedRover() ) {
    // For processing gazebo messages from the world stats topic.
    // Used to gather information for simulated rovers

    // Create fake argv and argc for the gazebo setup
    char  arg0[] = "diagnostics";
    char* argv[] = { &arg0[0], NULL };
    int   argc   = (int)(sizeof(argv) / sizeof(argv[0])) - 1;
    gazebo::setupClient(argc, argv);

    // Create Gazebo node and init
    gazebo::transport::NodePtr newNode(new gazebo::transport::Node());
    gazeboNode = newNode;
    gazeboNode->Init();
    string worldStatsTopic = "/gazebo/default/world_stats";
    worldStatsSubscriber = gazeboNode->Subscribe(worldStatsTopic, &Diagnostics::simWorldStatsEventHandler, this);

    simulated = true;
    publishInfoLogMessage("Diagnostic Package Started. Simulated Rover.");
  } else {
    simulated = false;
    publishInfoLogMessage("Diagnostic Package Started. Physical Rover. ");

    try {
      string name = wirelessDiags.setInterface();
      publishInfoLogMessage("Monitoring wireless interface " + name);
    } catch( exception &e ) {
      publishErrorLogMessage("Error setting interface name for wireless diagnostics: " + string(e.what()));
    }
  }
}

void Diagnostics::publishDiagnosticData() {
  if (!simulated) {
  WirelessInfo info;

  // Get info about the wireless interface
  // Catch and display an error if there was an exception
  try {
    info = wirelessDiags.getInfo();
  } catch( exception &e ){
    publishErrorLogMessage(e.what());
  return;
}

  std_msgs::Float32MultiArray rosMsg;
  rosMsg.data.clear();
  rosMsg.data.push_back(info.quality);
  rosMsg.data.push_back(info.bandwidthUsed);
  rosMsg.data.push_back(-1); // Sim update rate
  diagnosticDataPublisher.publish(rosMsg);
  }
}

void Diagnostics::publishErrorLogMessage(std::string msg) {

  std_msgs::String ros_msg;
  ros_msg.data = "" + publishedName+" ("+getHumanFriendlyTime()+"): " + msg + "";
  diagLogPublisher.publish(ros_msg);

}

void Diagnostics::publishWarningLogMessage(std::string msg) {
  std_msgs::String ros_msg;
  ros_msg.data = "" + publishedName+" ("+getHumanFriendlyTime()+"): " + msg + "";
  diagLogPublisher.publish(ros_msg);
}

void Diagnostics::publishInfoLogMessage(std::string msg) {
  std_msgs::String ros_msg;
  ros_msg.data = "" + publishedName + " ("+getHumanFriendlyTime()+"): " + msg + "";
  diagLogPublisher.publish(ros_msg);
}

void Diagnostics::fingerTimestampUpdate(const geometry_msgs::QuaternionStamped::ConstPtr& message) {
	fingersTimestamp = message->header.stamp;
}

void Diagnostics::wristTimestampUpdate(const geometry_msgs::QuaternionStamped::ConstPtr& message) {
	wristTimestamp = message->header.stamp;
}

void Diagnostics::imuTimestampUpdate(const sensor_msgs::Imu::ConstPtr& message) {
	imuTimestamp = message->header.stamp;
}

void Diagnostics::odometryTimestampUpdate(const nav_msgs::Odometry::ConstPtr& message) {
	odometryTimestamp = message->header.stamp;
}

void Diagnostics::sonarLeftTimestampUpdate(const sensor_msgs::Range::ConstPtr& message) {
	sonarLeftTimestamp = message->header.stamp;
}

void Diagnostics::sonarCenterTimestampUpdate(const sensor_msgs::Range::ConstPtr& message) {
	sonarCenterTimestamp = message->header.stamp;
}

void Diagnostics::sonarRightTimestampUpdate(const sensor_msgs::Range::ConstPtr& message) {
	sonarRightTimestamp = message->header.stamp;
}

// Return the current time in this timezone in "WeekDay Month Day hr:mni:sec year" format.
// We use this instead of asctime or ctime because it is thread safe
string Diagnostics::getHumanFriendlyTime() {
   time_t t = std::time(NULL);
   char humanReadableStr[100];

   if (strftime(humanReadableStr, sizeof(humanReadableStr), "%A %c", localtime(&t)))
     return humanReadableStr;
   else
     return ""; // There was a problem getting the time. Return the empty string.

}

// sensor check timeout handler. This function is triggered periodically and calls the
// sensor check functions.
void Diagnostics::sensorCheckTimerEventHandler(const ros::TimerEvent& event) {

  if (!simulated) {
  checkIMU();
  checkGPS();
  checkSonar();
  checkCamera();
  checkGripper();
  checkOdometry();

  publishDiagnosticData();
  }

}

void Diagnostics::simCheckTimerEventHandler(const ros::TimerEvent& event) {

  if (simulated) {
    std_msgs::Float32MultiArray rosMsg;
    rosMsg.data.clear();
    rosMsg.data.push_back(0.0f);
 rosMsg.data.push_back(0.0f);
    rosMsg.data.push_back(checkSimRate());
    diagnosticDataPublisher.publish(rosMsg);
  }

}

float Diagnostics::checkSimRate() {
  return simRate;
}

void Diagnostics::checkIMU() {
  // Example
  //publishWarningLogMessage("IMU Warning");
	if (ros::Time::now() - imuTimestamp <= ros::Duration(2.0)) {
		if (!imuConnected) {
			imuConnected = true;
			publishInfoLogMessage("IMU connected");
		}
	}
	else if (imuConnected) {
		imuConnected = false;
		publishErrorLogMessage("IMU is not connected");
	}
}

void Diagnostics::checkGPS() {
  // Example
  //publishWarningLogMessage("GPS Warning");

  // Check that a U-Blox device exists in the connected USB devices list

  if ( checkGPSExists() ) {
    // Notify the GUI only if reconnected after being previously disconnected
    if (!GPSConnected) publishInfoLogMessage("GPS reconnected");
    GPSConnected = true;
  } else {
    if (GPSConnected) // Guard against repeating the error.
      publishErrorLogMessage("GPS is not connected");
    GPSConnected = false;
  }
}

void Diagnostics::checkCamera() {
    // Example
  //publishWarningLogMessage("Camera Warning");

  // Check that a Logitec c170 device exists in the connected USB devices list
  if ( checkCameraExists() ) {
    // Notify the GUI only if reconnected after being previously disconnected
    if (!cameraConnected) publishInfoLogMessage("Camera reconnected");
    cameraConnected = true;
  } else {
    if (cameraConnected)
    publishErrorLogMessage("Camera not connected");
    cameraConnected = false;
  }
}

void Diagnostics::checkSonar() {
  //Example
  //publishErrorLogMessage("Sonar Error");

	if (ros::Time::now() - sonarLeftTimestamp <= ros::Duration(2.0)) {
		if (!sonarLeftConnected) {
			sonarLeftConnected = true;
			publishInfoLogMessage("Left ultrasound connected");
		}
	}
	else if (sonarLeftConnected) {
		sonarLeftConnected = false;
		publishErrorLogMessage("Left ultrasound is not connected");
	}

	if (ros::Time::now() - sonarCenterTimestamp <= ros::Duration(2.0)) {
		if (!sonarCenterConnected) {
			sonarCenterConnected = true;
			publishInfoLogMessage("Center ultrasound connected");
		}
	}
	else if (sonarCenterConnected) {
		sonarCenterConnected = false;
		publishErrorLogMessage("Center ultrasound is not connected");
	}

	if (ros::Time::now() - sonarRightTimestamp <= ros::Duration(2.0)) {
		if (!sonarRightConnected) {
			sonarRightConnected = true;
			publishInfoLogMessage("Right ultrasound connected");
		}
	}
	else if (sonarRightConnected) {
		sonarRightConnected = false;
		publishErrorLogMessage("Right ultrasound is not connected");
	}
}

void Diagnostics::checkGripper() {
	// Example
	//publishWarningLogMessage("Gripper Warning");

	if (ros::Time::now() - fingersTimestamp > ros::Duration(2.0)) {
		if (!fingersConnected) {
			fingersConnected = true;
			publishInfoLogMessage("Gripper fingers connected");
		}
	}
	else if (fingersConnected) {
		fingersConnected = false;
		publishErrorLogMessage("Gripper fingers are not connected");
	}

	if (ros::Time::now() - wristTimestamp > ros::Duration(2.0)) {
		if (!wristConnected) {
			wristConnected = true;
			publishInfoLogMessage("Gripper wrist connected");
		}
	}
	else if (wristConnected) {
		wristConnected = false;
		publishErrorLogMessage("Gripper wrist is not connected");
	}
}

void Diagnostics::checkOdometry() {
	// Example
	//publishWarningLogMessage("Odometry Warning");

	if (ros::Time::now() - odometryTimestamp <= ros::Duration(2.0)) {
		if (!odometryConnected) {
			odometryConnected = true;
			publishInfoLogMessage("Encoders connected");
		}
	}
	else if (odometryConnected) {
		odometryConnected = false;
		publishErrorLogMessage("Encoders are not connected");
	}
}

// Check if the U-Blox GPS is connected
// ID_VENDOR = 0x1546
// ID_PRODUCT = 0x01a6
bool Diagnostics::checkGPSExists(){
  uint16_t GPSVendorID = 0x1546;
  uint16_t GPSProductID = 0x01a6;
  return checkUSBDeviceExists( GPSVendorID, GPSProductID );
}

// Check if the Logitech c170 camera is connected
// ID_VENDOR = 0x046d
// ID_PRODUCT = 0x082b
bool Diagnostics::checkCameraExists(){
  uint16_t cameraVendorID = 0x046d;
  uint16_t cameraProductID = 0x082b;
  return checkUSBDeviceExists( cameraVendorID, cameraProductID );
}

// Search through the connected USB devices for one that matches the
// specified vendorID and productID
bool Diagnostics::checkUSBDeviceExists(uint16_t vendorID, uint16_t productID){

  struct usb_bus *bus;
  struct usb_device *dev;
  usb_init();
  usb_find_busses();
  usb_find_devices();

  // Iterate through busses and devices
  for (bus = usb_busses; bus; bus = bus->next)
    for (dev = bus->devices; dev; dev = dev->next)
      if ( dev->descriptor.idVendor == vendorID && dev->descriptor.idProduct == productID )
        return true;

  // GPS not found
  return false;
}

void Diagnostics::simWorldStatsEventHandler(ConstWorldStatisticsPtr &msg) {

  const msgs::Time simTimeMsg = msg->sim_time();
  const msgs::Time realTimeMsg = msg->real_time();

  common::Time simTime(simTimeMsg.sec(), simTimeMsg.nsec());
  common::Time realTime(realTimeMsg.sec(), realTimeMsg.nsec());

  common::Time deltaSimTime = simTime - prevSimTime;
  common::Time deltaRealTime = realTime - prevRealTime;

  prevSimTime = simTime;
  prevRealTime = realTime;

  simRate = (deltaSimTime.Double())/(deltaRealTime.Double());
}

// Check whether a rover model file exists with the same name as this rover name
// if not then we should be a physcial rover. Need a better method.
bool Diagnostics::checkIfSimulatedRover() {
  struct stat buffer;
  const char *model_path_env = "GAZEBO_MODEL_PATH";
  char *model_root = getenv(model_path_env);
  string model_path = string(model_root)+"/"+publishedName+"/model.sdf";
  return (stat(model_path.c_str(), &buffer) == 0);
}

Diagnostics::~Diagnostics() {
  gazebo::shutdown();
}

<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "DiscovererWorker.h"

#include "logging/Logger.h"
#include "Folder.h"
#include "Media.h"
#include "MediaLibrary.h"
#include "Device.h"
#include "utils/Filename.h"
#include "medialibrary/filesystem/Errors.h"
#include <cassert>

namespace medialibrary
{

DiscovererWorker::DiscovererWorker(MediaLibrary* ml )
    : m_run( false )
    , m_ml( ml )
{
}

DiscovererWorker::~DiscovererWorker()
{
    stop();
}

void DiscovererWorker::addDiscoverer( std::unique_ptr<IDiscoverer> discoverer )
{
    m_discoverers.push_back( std::move( discoverer ) );
}

void DiscovererWorker::stop()
{
    bool running = true;
    if ( m_run.compare_exchange_strong( running, false ) )
    {
        {
            std::unique_lock<compat::Mutex> lock( m_mutex );
            while ( m_tasks.empty() == false )
                m_tasks.pop();
        }
        m_cond.notify_all();
        m_thread.join();
    }
}

bool DiscovererWorker::discover( const std::string& entryPoint )
{
    if ( entryPoint.length() == 0 )
        return false;
    LOG_INFO( "Adding ", entryPoint, " to the folder discovery list" );
    enqueue( utils::file::toFolderPath( entryPoint ), Task::Type::Discover );
    return true;
}

void DiscovererWorker::remove( const std::string& entryPoint )
{
    enqueue( entryPoint, Task::Type::Remove );
}

void DiscovererWorker::reload()
{
    enqueue( "", Task::Type::Reload );
}

void DiscovererWorker::reload( const std::string& entryPoint )
{
    enqueue( utils::file::toFolderPath( entryPoint ), Task::Type::Reload );
}

void DiscovererWorker::ban( const std::string& entryPoint )
{
    enqueue( utils::file::toFolderPath( entryPoint ), Task::Type::Ban );
}

void DiscovererWorker::unban( const std::string& entryPoint )
{
    enqueue( utils::file::toFolderPath( entryPoint ), Task::Type::Unban );
}

void DiscovererWorker::reloadDevice(int64_t deviceId)
{
    enqueue( deviceId, Task::Type::ReloadDevice );
}

void DiscovererWorker::enqueue( const std::string& entryPoint, Task::Type type )
{
    std::unique_lock<compat::Mutex> lock( m_mutex );

    LOG_INFO( "Queuing entrypoint ", entryPoint, " of type ",
              static_cast<typename std::underlying_type<Task::Type>::type>( type ) );
    m_tasks.emplace( entryPoint, type );
    notify();
}

void DiscovererWorker::enqueue( int64_t entityId, Task::Type type )
{
    std::unique_lock<compat::Mutex> lock( m_mutex );

    LOG_INFO( "Queuing entity ", entityId, " of type ",
              static_cast<typename std::underlying_type<Task::Type>::type>( type ) );
    m_tasks.emplace( entityId, type );
    notify();
}

void DiscovererWorker::notify()
{
    if ( m_thread.get_id() == compat::Thread::id{} )
    {
        m_run = true;
        m_thread = compat::Thread( &DiscovererWorker::run, this );
    }
    // Since we just added an element, let's not check for size == 0 :)
    else if ( m_tasks.size() == 1 )
        m_cond.notify_all();
}

void DiscovererWorker::run() ML_UNHANDLED_EXCEPTION_INIT
{
    LOG_INFO( "Entering DiscovererWorker thread" );
    m_ml->onDiscovererIdleChanged( false );
    while ( m_run == true )
    {
        Task task;
        {
            std::unique_lock<compat::Mutex> lock( m_mutex );
            if ( m_tasks.size() == 0 )
            {
                m_ml->onDiscovererIdleChanged( true );
                m_cond.wait( lock, [this]() { return m_tasks.size() > 0 || m_run == false; } );
                if ( m_run == false )
                    break;
                m_ml->onDiscovererIdleChanged( false );
            }
            task = m_tasks.front();
            m_tasks.pop();
        }
        switch ( task.type )
        {
        case Task::Type::Discover:
            runDiscover( task.entryPoint );
            break;
        case Task::Type::Reload:
            runReload( task.entryPoint );
            break;
        case Task::Type::Remove:
            runRemove( task.entryPoint );
            break;
        case Task::Type::Ban:
            runBan( task.entryPoint );
            break;
        case Task::Type::Unban:
            runUnban( task.entryPoint );
            break;
        case Task::Type::ReloadDevice:
            runReloadDevice( task.entityId );
            break;
        default:
            assert(false);
        }
    }
    LOG_INFO( "Exiting DiscovererWorker thread" );
    m_ml->onDiscovererIdleChanged( true );
}
ML_UNHANDLED_EXCEPTION_BODY( "DiscovererWorker" )

void DiscovererWorker::runReload( const std::string& entryPoint )
{
    for ( auto& d : m_discoverers )
    {
        try
        {
            if ( entryPoint.empty() == true )
            {
                // Let the discoverer invoke the callbacks for all its known folders
                d->reload( *this );
            }
            else
            {
                m_ml->getCb()->onReloadStarted( entryPoint );
                LOG_INFO( "Reloading folder ", entryPoint );
                auto res = d->reload( entryPoint, *this );
                m_ml->getCb()->onReloadCompleted( entryPoint, res );
            }
        }
        catch(std::exception& ex)
        {
            LOG_ERROR( "Fatal error while reloading: ", ex.what() );
        }
        if ( m_run == false )
            break;
    }
}

void DiscovererWorker::runRemove( const std::string& ep )
{
    auto entryPoint = utils::file::toFolderPath( ep );
    auto folder = Folder::fromMrl( m_ml, entryPoint );
    if ( folder == nullptr )
    {
        LOG_WARN( "Can't remove unknown entrypoint: ", entryPoint );
        m_ml->getCb()->onEntryPointRemoved( ep, false );
        return;
    }
    // The easy case is that this folder was directly discovered. In which case, we just
    // have to delete it and it won't be discovered again.
    // If it isn't, we also have to ban it to prevent it from reappearing. The Folder::banFolder
    // method already handles the prior deletion
    bool res;
    if ( folder->isRootFolder() == false )
        res = Folder::ban( m_ml, entryPoint );
    else
        res = m_ml->deleteFolder( *folder );
    if ( res == false )
    {
        m_ml->getCb()->onEntryPointRemoved( ep, false );
        return;
    }
    m_ml->getCb()->onEntryPointRemoved( ep, true );
}

void DiscovererWorker::runBan( const std::string& entryPoint )
{
    auto res = Folder::ban( m_ml, entryPoint );
    m_ml->getCb()->onEntryPointBanned( entryPoint, res );
}

void DiscovererWorker::runUnban( const std::string& entryPoint )
{
    auto folder = Folder::bannedFolder( m_ml, entryPoint );
    if ( folder == nullptr )
    {
        LOG_WARN( "Can't unban ", entryPoint, " as it wasn't banned" );
        m_ml->getCb()->onEntryPointUnbanned( entryPoint, false );
        return;
    }
    auto res = m_ml->deleteFolder( *folder );
    m_ml->getCb()->onEntryPointUnbanned( entryPoint, res );

    auto parentPath = utils::file::parentDirectory( entryPoint );
    // If the parent folder was never added to the media library, the discoverer will reject it.
    // We could check it from here, but that would mean fetching the folder twice, which would be a waste.
    runReload( parentPath );
}

void DiscovererWorker::runReloadDevice( int64_t deviceId )
{
    auto device = Device::fetch( m_ml, deviceId );
    if ( device == nullptr )
    {
        LOG_ERROR( "Can't fetch device ", deviceId, " to reload it" );
        return;
    }
    auto entryPoints = Folder::entryPoints( m_ml, false, device->id() );
    if ( entryPoints == nullptr )
        return;
    for ( const auto& ep : entryPoints->all() )
    {
        try
        {
            auto mrl = ep->mrl();
            LOG_INFO( "Reloading entrypoint on mounted device: ", mrl );
            runReload( mrl );
        }
        catch ( const fs::errors::DeviceRemoved& )
        {
            LOG_INFO( "Can't reload device ", device->uuid(), " as it was removed" );
        }
    }
}

bool DiscovererWorker::isInterrupted() const
{
    return m_run.load() == false;
}

void DiscovererWorker::runDiscover( const std::string& entryPoint )
{
    m_ml->getCb()->onDiscoveryStarted( entryPoint );
    auto discovered = false;
    LOG_INFO( "Running discover on: ", entryPoint );
    for ( auto& d : m_discoverers )
    {
        // Assume only one discoverer can handle an entrypoint.
        try
        {
            auto chrono = std::chrono::steady_clock::now();
            if ( d->discover( entryPoint, *this ) == true )
            {
                auto duration = std::chrono::steady_clock::now() - chrono;
                LOG_VERBOSE( "Discovered ", entryPoint, " in ",
                           std::chrono::duration_cast<std::chrono::microseconds>( duration ).count(), "µs" );
                discovered = true;
                break;
            }
        }
        catch(std::exception& ex)
        {
            LOG_ERROR( "Fatal error while discovering ", entryPoint, ": ", ex.what() );
        }

        if ( m_run == false )
            break;
    }
    if ( discovered == false )
        LOG_WARN( "No IDiscoverer found to discover ", entryPoint );
    m_ml->getCb()->onDiscoveryCompleted( entryPoint, discovered );
}

}
<commit_msg>DiscovererWorker: Clarify log<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015-2019 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "DiscovererWorker.h"

#include "logging/Logger.h"
#include "Folder.h"
#include "Media.h"
#include "MediaLibrary.h"
#include "Device.h"
#include "utils/Filename.h"
#include "medialibrary/filesystem/Errors.h"
#include <cassert>

namespace medialibrary
{

DiscovererWorker::DiscovererWorker(MediaLibrary* ml )
    : m_run( false )
    , m_ml( ml )
{
}

DiscovererWorker::~DiscovererWorker()
{
    stop();
}

void DiscovererWorker::addDiscoverer( std::unique_ptr<IDiscoverer> discoverer )
{
    m_discoverers.push_back( std::move( discoverer ) );
}

void DiscovererWorker::stop()
{
    bool running = true;
    if ( m_run.compare_exchange_strong( running, false ) )
    {
        {
            std::unique_lock<compat::Mutex> lock( m_mutex );
            while ( m_tasks.empty() == false )
                m_tasks.pop();
        }
        m_cond.notify_all();
        m_thread.join();
    }
}

bool DiscovererWorker::discover( const std::string& entryPoint )
{
    if ( entryPoint.length() == 0 )
        return false;
    LOG_INFO( "Adding ", entryPoint, " to the folder discovery list" );
    enqueue( utils::file::toFolderPath( entryPoint ), Task::Type::Discover );
    return true;
}

void DiscovererWorker::remove( const std::string& entryPoint )
{
    enqueue( entryPoint, Task::Type::Remove );
}

void DiscovererWorker::reload()
{
    enqueue( "", Task::Type::Reload );
}

void DiscovererWorker::reload( const std::string& entryPoint )
{
    enqueue( utils::file::toFolderPath( entryPoint ), Task::Type::Reload );
}

void DiscovererWorker::ban( const std::string& entryPoint )
{
    enqueue( utils::file::toFolderPath( entryPoint ), Task::Type::Ban );
}

void DiscovererWorker::unban( const std::string& entryPoint )
{
    enqueue( utils::file::toFolderPath( entryPoint ), Task::Type::Unban );
}

void DiscovererWorker::reloadDevice(int64_t deviceId)
{
    enqueue( deviceId, Task::Type::ReloadDevice );
}

void DiscovererWorker::enqueue( const std::string& entryPoint, Task::Type type )
{
    std::unique_lock<compat::Mutex> lock( m_mutex );

    if ( entryPoint.empty() == false )
    {
        LOG_INFO( "Queuing entrypoint ", entryPoint, " of type ",
                  static_cast<typename std::underlying_type<Task::Type>::type>( type ) );
    }
    else
    {
        assert( type == Task::Type::Reload );
        LOG_INFO( "Queuing global reload request" );
    }

    m_tasks.emplace( entryPoint, type );
    notify();
}

void DiscovererWorker::enqueue( int64_t entityId, Task::Type type )
{
    std::unique_lock<compat::Mutex> lock( m_mutex );

    LOG_INFO( "Queuing entity ", entityId, " of type ",
              static_cast<typename std::underlying_type<Task::Type>::type>( type ) );
    m_tasks.emplace( entityId, type );
    notify();
}

void DiscovererWorker::notify()
{
    if ( m_thread.get_id() == compat::Thread::id{} )
    {
        m_run = true;
        m_thread = compat::Thread( &DiscovererWorker::run, this );
    }
    // Since we just added an element, let's not check for size == 0 :)
    else if ( m_tasks.size() == 1 )
        m_cond.notify_all();
}

void DiscovererWorker::run() ML_UNHANDLED_EXCEPTION_INIT
{
    LOG_INFO( "Entering DiscovererWorker thread" );
    m_ml->onDiscovererIdleChanged( false );
    while ( m_run == true )
    {
        Task task;
        {
            std::unique_lock<compat::Mutex> lock( m_mutex );
            if ( m_tasks.size() == 0 )
            {
                m_ml->onDiscovererIdleChanged( true );
                m_cond.wait( lock, [this]() { return m_tasks.size() > 0 || m_run == false; } );
                if ( m_run == false )
                    break;
                m_ml->onDiscovererIdleChanged( false );
            }
            task = m_tasks.front();
            m_tasks.pop();
        }
        switch ( task.type )
        {
        case Task::Type::Discover:
            runDiscover( task.entryPoint );
            break;
        case Task::Type::Reload:
            runReload( task.entryPoint );
            break;
        case Task::Type::Remove:
            runRemove( task.entryPoint );
            break;
        case Task::Type::Ban:
            runBan( task.entryPoint );
            break;
        case Task::Type::Unban:
            runUnban( task.entryPoint );
            break;
        case Task::Type::ReloadDevice:
            runReloadDevice( task.entityId );
            break;
        default:
            assert(false);
        }
    }
    LOG_INFO( "Exiting DiscovererWorker thread" );
    m_ml->onDiscovererIdleChanged( true );
}
ML_UNHANDLED_EXCEPTION_BODY( "DiscovererWorker" )

void DiscovererWorker::runReload( const std::string& entryPoint )
{
    for ( auto& d : m_discoverers )
    {
        try
        {
            if ( entryPoint.empty() == true )
            {
                // Let the discoverer invoke the callbacks for all its known folders
                d->reload( *this );
            }
            else
            {
                m_ml->getCb()->onReloadStarted( entryPoint );
                LOG_INFO( "Reloading folder ", entryPoint );
                auto res = d->reload( entryPoint, *this );
                m_ml->getCb()->onReloadCompleted( entryPoint, res );
            }
        }
        catch(std::exception& ex)
        {
            LOG_ERROR( "Fatal error while reloading: ", ex.what() );
        }
        if ( m_run == false )
            break;
    }
}

void DiscovererWorker::runRemove( const std::string& ep )
{
    auto entryPoint = utils::file::toFolderPath( ep );
    auto folder = Folder::fromMrl( m_ml, entryPoint );
    if ( folder == nullptr )
    {
        LOG_WARN( "Can't remove unknown entrypoint: ", entryPoint );
        m_ml->getCb()->onEntryPointRemoved( ep, false );
        return;
    }
    // The easy case is that this folder was directly discovered. In which case, we just
    // have to delete it and it won't be discovered again.
    // If it isn't, we also have to ban it to prevent it from reappearing. The Folder::banFolder
    // method already handles the prior deletion
    bool res;
    if ( folder->isRootFolder() == false )
        res = Folder::ban( m_ml, entryPoint );
    else
        res = m_ml->deleteFolder( *folder );
    if ( res == false )
    {
        m_ml->getCb()->onEntryPointRemoved( ep, false );
        return;
    }
    m_ml->getCb()->onEntryPointRemoved( ep, true );
}

void DiscovererWorker::runBan( const std::string& entryPoint )
{
    auto res = Folder::ban( m_ml, entryPoint );
    m_ml->getCb()->onEntryPointBanned( entryPoint, res );
}

void DiscovererWorker::runUnban( const std::string& entryPoint )
{
    auto folder = Folder::bannedFolder( m_ml, entryPoint );
    if ( folder == nullptr )
    {
        LOG_WARN( "Can't unban ", entryPoint, " as it wasn't banned" );
        m_ml->getCb()->onEntryPointUnbanned( entryPoint, false );
        return;
    }
    auto res = m_ml->deleteFolder( *folder );
    m_ml->getCb()->onEntryPointUnbanned( entryPoint, res );

    auto parentPath = utils::file::parentDirectory( entryPoint );
    // If the parent folder was never added to the media library, the discoverer will reject it.
    // We could check it from here, but that would mean fetching the folder twice, which would be a waste.
    runReload( parentPath );
}

void DiscovererWorker::runReloadDevice( int64_t deviceId )
{
    auto device = Device::fetch( m_ml, deviceId );
    if ( device == nullptr )
    {
        LOG_ERROR( "Can't fetch device ", deviceId, " to reload it" );
        return;
    }
    auto entryPoints = Folder::entryPoints( m_ml, false, device->id() );
    if ( entryPoints == nullptr )
        return;
    for ( const auto& ep : entryPoints->all() )
    {
        try
        {
            auto mrl = ep->mrl();
            LOG_INFO( "Reloading entrypoint on mounted device: ", mrl );
            runReload( mrl );
        }
        catch ( const fs::errors::DeviceRemoved& )
        {
            LOG_INFO( "Can't reload device ", device->uuid(), " as it was removed" );
        }
    }
}

bool DiscovererWorker::isInterrupted() const
{
    return m_run.load() == false;
}

void DiscovererWorker::runDiscover( const std::string& entryPoint )
{
    m_ml->getCb()->onDiscoveryStarted( entryPoint );
    auto discovered = false;
    LOG_INFO( "Running discover on: ", entryPoint );
    for ( auto& d : m_discoverers )
    {
        // Assume only one discoverer can handle an entrypoint.
        try
        {
            auto chrono = std::chrono::steady_clock::now();
            if ( d->discover( entryPoint, *this ) == true )
            {
                auto duration = std::chrono::steady_clock::now() - chrono;
                LOG_VERBOSE( "Discovered ", entryPoint, " in ",
                           std::chrono::duration_cast<std::chrono::microseconds>( duration ).count(), "µs" );
                discovered = true;
                break;
            }
        }
        catch(std::exception& ex)
        {
            LOG_ERROR( "Fatal error while discovering ", entryPoint, ": ", ex.what() );
        }

        if ( m_run == false )
            break;
    }
    if ( discovered == false )
        LOG_WARN( "No IDiscoverer found to discover ", entryPoint );
    m_ml->getCb()->onDiscoveryCompleted( entryPoint, discovered );
}

}
<|endoftext|>


<commit_before>/*
  User Server code for CMPT 276 Group Assignment, Spring 2016.

  This server manages a user’s social networking session.

  This server supports sign on/off, add friend, unfriend, update status,
  get user's friend list.

  This server handles disallowed method malformed request.

  As defined in ServerUrls.h, the URI for this server is
  http://localhost:34572.
*/

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <string>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "../include/ClientUtils.h"
#include "../include/ServerUrls.h"
#include "../include/ServerUtils.h"
#include "../include/TableCache.h"

#include "../include/azure_keys.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;
using std::get;

using web::http::client::http_client;
using web::http::http_headers;
using web::http::http_request;
using web::http::http_response;
using web::http::method;
using web::http::methods;
using web::http::status_code;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

const string get_update_data_op {"GetUpdateData"};

const string read_entity_auth_op {"ReadEntityAuth"};
const string update_entity_auth_op {"UpdateEntityAuth"};

const string auth_table_partition {"Userid"};
const string data_table {"DataTable"};

const string sign_on {"SignOn"}; //POST
const string sign_off {"SignOff"}; //POST

const string add_friend {"AddFriend"}; // PUT
const string unfriend {"UnFriend"}; //PUT
const string update_status {"UpdateStatus"}; //PUT

const string get_friend_list {"ReadFriendList"}; //GET

// Cache of active sessions
std::unordered_map< string, std::tuple<string/*token*/, string/*partition*/, string/*row*/> > sessions;

/*
  Return true if an HTTP request has a JSON body

  This routine can be called multiple times on the same message.
 */
bool has_json_body (http_request message) {
  return message.headers()["Content-type"] == "application/json";
}

/*
  Given an HTTP message with a JSON body, return the JSON
  body as an unordered map of strings to strings.
  get_json_body and get_json_bourne are valid and identical function calls.

  If the message has no JSON body, return an empty map.

  THIS ROUTINE CAN ONLY BE CALLED ONCE FOR A GIVEN MESSAGE
  (see http://microsoft.github.io/cpprestsdk/classweb_1_1http_1_1http__request.html#ae6c3d7532fe943de75dcc0445456cbc7
  for source of this limit).

  Note that all types of JSON values are returned as strings.
  Use C++ conversion utilities to convert to numbers or dates
  as necessary.
 */
unordered_map<string,string> get_json_body(http_request message) {
  unordered_map<string,string> results {};
  const http_headers& headers {message.headers()};
  auto content_type (headers.find("Content-Type"));
  if (content_type == headers.end() ||
      content_type->second != "application/json")
    return results;

  value json{};
  message.extract_json(true)
    .then([&json](value v) -> bool
          {
            json = v;
            return true;
          })
    .wait();

  if (json.is_object()) {
    for (const auto& v : json.as_object()) {
      if (v.second.is_string()) {
        results[v.first] = v.second.as_string();
      }
      else {
        results[v.first] = v.second.serialize();
      }
    }
  }
  return results;
}

unordered_map<string,string> get_json_bourne(http_request message) {
 return get_json_body(message);
}

void handle_post (http_request message){
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  // Operation name and user ID
  if(paths.size() < 2) {
    message.reply(status_codes::BadRequest);
    return;
  }
  else if(paths[0] != sign_on && paths[0] != sign_off) {
    message.reply(status_codes::BadRequest);
  }

  const string operation = paths[0];
  const string userid = paths[1];

  if(operation == sign_on) {
    if(!has_json_body(message)) {
      message.reply(status_codes::BadRequest);
      return;
    }

    unordered_map<string, string> json_body {get_json_bourne(message)};
    if(json_body.size() != 1) {
      message.reply(status_codes::BadRequest);
      return;
    }

    unordered_map<string, string>::const_iterator json_body_password_iterator {json_body.find("Password")};
    // No 'Password' property
    if(json_body_password_iterator == json_body.end()) {
      message.reply(status_codes::BadRequest);
      return;
    }

    vector<pair<string, value>> json_pw;
    json_pw.push_back(make_pair(
        json_body_password_iterator->first,
        value::string(json_body_password_iterator->second)
    ));

    pair<status_code, value> result;
    result = do_request(
      methods::GET,
      string(server_urls::auth_server) + "/" +
      get_update_data_op + "/" +
      userid,
      value::object(json_pw)
    );
    if(result.first != status_codes::OK) {
      message.reply(result.first);
      return;
    }
    else if(result.second.size() != 3) {
      message.reply(status_codes::InternalError);
      return;
    }

    const string token = get_json_object_prop(
      result.second,
      "token"
    );
    const string data_partition = get_json_object_prop(
      result.second,
      "DataPartition"
    );
    const string data_row = get_json_object_prop(
      result.second,
      "DataRow"
    );
    if(token.empty() ||
       data_partition.empty() ||
       data_row.empty() ) {
      message.reply(status_codes::InternalError);
      return;
    }

    std::tuple<string, string, string> tuple_insert(
      token,
      data_partition,
      data_row);
    std::pair<string, std::tuple<string, string, string>> pair_insert(
      userid,
      tuple_insert
    );
    sessions.insert(pair_insert);

    message.reply(status_codes::OK);
    return;
  }

  else if(operation == sign_off) {
    auto session = sessions.find(userid);
    if(session == sessions.end()) {
      message.reply(status_codes::NotFound);
      return;
    }

    sessions.erase(session);
    message.reply(status_codes::OK);
    return;
  }

  else {
    message.reply(status_codes::InternalError);
    return;
  }
}

void handle_put (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  pair<status_code, value> result;
  string user_id {paths[1]};
  string user_token {get<0>(sessions[user_id])};
  string user_partition {get<1>(sessions[user_id])};
  string user_row {get<2>(sessions[user_id])};
  if(true/*basic criteria*/){}
  else if (paths[0] == add_friend) {
    // Get current friends list
    result = do_request(
      methods::GET,
      string(server_urls::basic_server) + "/" +
      read_entity_auth_op + "/" +
      data_table + "/" +
      user_token + "/" +
      user_partition + "/" +
      user_row
      );
    //Check status code
    //Parse JSON body
    unordered_map<string,string> json_body = unpack_json_object(result.second);
    friends_list_t user_friends = parse_friends_list(json_body["Friends"]);
    // Add new friend to list
    user_friends.push_back(make_pair(paths[2],paths[3]));
    string user_friends_string = friends_list_to_string(user_friends);
    result.second = build_json_value("Friends", user_friends_string);
    // Put new friends list
    do_request(
      methods::PUT,
      string(server_urls::basic_server) + "/" +
      update_entity_auth_op + "/" +
      string(paths[2]) + "/" +
      string(paths[3]),
      result.second
      );
    message.reply(status::codes::OK);
    return;
  }
  else if (paths[0] == unfriend) {}
  else if (paths[0] == update_status) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_get (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == get_friend_list) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

int main (int argc, char const * argv[]) {
  cout << "Opening listener" << endl;
  http_listener listener {server_urls::user_server};
  listener.support(methods::GET, &handle_get); // Get user's friend list
  listener.support(methods::POST, &handle_post); // SignOn, SignOff
  listener.support(methods::PUT, &handle_put); // Add friend, Unfriend, Update Status
  /*TO DO: Disallowed method*/
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<commit_msg>update documentation of put<commit_after>/*
  User Server code for CMPT 276 Group Assignment, Spring 2016.

  This server manages a user’s social networking session.

  This server supports sign on/off, add friend, unfriend, update status,
  get user's friend list.

  This server handles disallowed method malformed request.

  As defined in ServerUrls.h, the URI for this server is
  http://localhost:34572.
*/

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <string>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "../include/ClientUtils.h"
#include "../include/ServerUrls.h"
#include "../include/ServerUtils.h"
#include "../include/TableCache.h"

#include "../include/azure_keys.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;
using std::get;

using web::http::client::http_client;
using web::http::http_headers;
using web::http::http_request;
using web::http::http_response;
using web::http::method;
using web::http::methods;
using web::http::status_code;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

const string get_update_data_op {"GetUpdateData"};

const string read_entity_auth_op {"ReadEntityAuth"};
const string update_entity_auth_op {"UpdateEntityAuth"};

const string auth_table_partition {"Userid"};
const string data_table {"DataTable"};

const string sign_on {"SignOn"}; //POST
const string sign_off {"SignOff"}; //POST

const string add_friend {"AddFriend"}; // PUT
const string unfriend {"UnFriend"}; //PUT
const string update_status {"UpdateStatus"}; //PUT

const string get_friend_list {"ReadFriendList"}; //GET

// Cache of active sessions
std::unordered_map< string, std::tuple<string/*token*/, string/*partition*/, string/*row*/> > sessions;

/*
  Return true if an HTTP request has a JSON body

  This routine can be called multiple times on the same message.
 */
bool has_json_body (http_request message) {
  return message.headers()["Content-type"] == "application/json";
}

/*
  Given an HTTP message with a JSON body, return the JSON
  body as an unordered map of strings to strings.
  get_json_body and get_json_bourne are valid and identical function calls.

  If the message has no JSON body, return an empty map.

  THIS ROUTINE CAN ONLY BE CALLED ONCE FOR A GIVEN MESSAGE
  (see http://microsoft.github.io/cpprestsdk/classweb_1_1http_1_1http__request.html#ae6c3d7532fe943de75dcc0445456cbc7
  for source of this limit).

  Note that all types of JSON values are returned as strings.
  Use C++ conversion utilities to convert to numbers or dates
  as necessary.
 */
unordered_map<string,string> get_json_body(http_request message) {
  unordered_map<string,string> results {};
  const http_headers& headers {message.headers()};
  auto content_type (headers.find("Content-Type"));
  if (content_type == headers.end() ||
      content_type->second != "application/json")
    return results;

  value json{};
  message.extract_json(true)
    .then([&json](value v) -> bool
          {
            json = v;
            return true;
          })
    .wait();

  if (json.is_object()) {
    for (const auto& v : json.as_object()) {
      if (v.second.is_string()) {
        results[v.first] = v.second.as_string();
      }
      else {
        results[v.first] = v.second.serialize();
      }
    }
  }
  return results;
}

unordered_map<string,string> get_json_bourne(http_request message) {
 return get_json_body(message);
}

void handle_post (http_request message){
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  // Operation name and user ID
  if(paths.size() < 2) {
    message.reply(status_codes::BadRequest);
    return;
  }
  else if(paths[0] != sign_on && paths[0] != sign_off) {
    message.reply(status_codes::BadRequest);
  }

  const string operation = paths[0];
  const string userid = paths[1];

  if(operation == sign_on) {
    if(!has_json_body(message)) {
      message.reply(status_codes::BadRequest);
      return;
    }

    unordered_map<string, string> json_body {get_json_bourne(message)};
    if(json_body.size() != 1) {
      message.reply(status_codes::BadRequest);
      return;
    }

    unordered_map<string, string>::const_iterator json_body_password_iterator {json_body.find("Password")};
    // No 'Password' property
    if(json_body_password_iterator == json_body.end()) {
      message.reply(status_codes::BadRequest);
      return;
    }

    vector<pair<string, value>> json_pw;
    json_pw.push_back(make_pair(
        json_body_password_iterator->first,
        value::string(json_body_password_iterator->second)
    ));

    pair<status_code, value> result;
    result = do_request(
      methods::GET,
      string(server_urls::auth_server) + "/" +
      get_update_data_op + "/" +
      userid,
      value::object(json_pw)
    );
    if(result.first != status_codes::OK) {
      message.reply(result.first);
      return;
    }
    else if(result.second.size() != 3) {
      message.reply(status_codes::InternalError);
      return;
    }

    const string token = get_json_object_prop(
      result.second,
      "token"
    );
    const string data_partition = get_json_object_prop(
      result.second,
      "DataPartition"
    );
    const string data_row = get_json_object_prop(
      result.second,
      "DataRow"
    );
    if(token.empty() ||
       data_partition.empty() ||
       data_row.empty() ) {
      message.reply(status_codes::InternalError);
      return;
    }

    std::tuple<string, string, string> tuple_insert(
      token,
      data_partition,
      data_row);
    std::pair<string, std::tuple<string, string, string>> pair_insert(
      userid,
      tuple_insert
    );
    sessions.insert(pair_insert);

    message.reply(status_codes::OK);
    return;
  }

  else if(operation == sign_off) {
    auto session = sessions.find(userid);
    if(session == sessions.end()) {
      message.reply(status_codes::NotFound);
      return;
    }

    sessions.erase(session);
    message.reply(status_codes::OK);
    return;
  }

  else {
    message.reply(status_codes::InternalError);
    return;
  }
}

void handle_put (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  pair<status_code, value> result;
  string user_id {paths[1]};
  string user_token {get<0>(sessions[user_id])};
  string user_partition {get<1>(sessions[user_id])};
  string user_row {get<2>(sessions[user_id])};
  if(true/*basic criteria*/){}
  else if (paths[0] == add_friend) {
    // TODO: Check validity of the request
    // Get current friends list
    result = do_request(
      methods::GET,
      string(server_urls::basic_server) + "/" +
      read_entity_auth_op + "/" +
      data_table + "/" +
      user_token + "/" +
      user_partition + "/" +
      user_row
      );
    // TODO: Check status code
    // Parse JSON body
    unordered_map<string,string> json_body = unpack_json_object(result.second);
    friends_list_t user_friends = parse_friends_list(json_body["Friends"]);
    // Add new friend to list
    user_friends.push_back(make_pair(paths[2],paths[3]));
    // Rebuild json body
    string user_friends_string = friends_list_to_string(user_friends);
    result.second = build_json_value("Friends", user_friends_string);
    // Put new friends list
    do_request(
      methods::PUT,
      string(server_urls::basic_server) + "/" +
      update_entity_auth_op + "/" +
      string(paths[2]) + "/" +
      string(paths[3]),
      result.second
      );
    message.reply(status::codes::OK);
    return;
  }
  else if (paths[0] == unfriend) {}
  else if (paths[0] == update_status) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_get (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == get_friend_list) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

int main (int argc, char const * argv[]) {
  cout << "Opening listener" << endl;
  http_listener listener {server_urls::user_server};
  listener.support(methods::GET, &handle_get); // Get user's friend list
  listener.support(methods::POST, &handle_post); // SignOn, SignOff
  listener.support(methods::PUT, &handle_put); // Add friend, Unfriend, Update Status
  /*TO DO: Disallowed method*/
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "sdk/bfs_c.h"
#include "sdk/bfs.h"

#include <gflags/gflags.h>

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <map>

#include <common/string_util.h>
#include <common/timer.h>
#include <common/util.h>

DECLARE_string(flagfile);
DECLARE_string(nameserver_nodes);

extern "C"{

struct bfs_fs_t {
    baidu::bfs::FS*  bfs_fs;
};

struct bfs_file_t {
    baidu::bfs::File* bfs_file;
};

bfs_fs_t* bfs_open_file_system(const char* flag_file) {
    std::string flag = "--flagfile=";
    if (flag_file) {
        flag += flag_file;
    } else {
        flag += "./bfs.flag";
    }
    int argc = 1;
    char* file_path = new char[flag.size() + 1];
    strcpy(file_path, flag.c_str());
    char** argv = &file_path;
    ::google::ParseCommandLineFlags(&argc, &argv, false);
    delete[] file_path;

    bfs_fs_t* fs = new bfs_fs_t;
    std::string ns_address = FLAGS_nameserver_nodes;
    bool ret = baidu::bfs::FS::OpenFileSystem(ns_address.c_str(),
            &(fs->bfs_fs), baidu::bfs::FSOptions());
    if (!ret) {
        delete fs;
        return NULL;
    }
    return fs;
}

bfs_file_t* bfs_open_file(const bfs_fs_t* fs, const char* path, int flag) {
    if (flag != O_RDONLY && flag != O_WRONLY) {
        return NULL;
    }
    bfs_file_t* file = new bfs_file_t;
    int32_t ret = 0;
    if (flag == O_RDONLY) {
        ret = fs->bfs_fs->OpenFile(path, flag,
                &(file->bfs_file), baidu::bfs::ReadOptions());

    } else {
        ret = fs->bfs_fs->OpenFile(path, flag,
                &(file->bfs_file), baidu::bfs::WriteOptions());
    }
    if (ret != 0) {
        delete file->bfs_file;
        delete file;
        file = NULL;
    }
    return file;
}

int bfs_close_file(bfs_file_t* file) {
    int32_t ret = file->bfs_file->Close();
    delete file->bfs_file;
    file->bfs_file = NULL;
    delete file;
    return ret;
}

int bfs_write_file(bfs_file_t* file, const char* buf, int32_t len) {
    return file->bfs_file->Write(buf, len);
}

int bfs_read_file(bfs_file_t* file, char* buf, int32_t len) {
    return file->bfs_file->Read(buf, len);
}

int64_t bfs_seek(bfs_file_t* file, int64_t offset, int32_t whence) {
    return file->bfs_file->Seek(offset, whence);
}

int bfs_create_directory(bfs_fs_t* fs, const char* path) {
    return fs->bfs_fs->CreateDirectory(path);
}

int bfs_list_directory(bfs_fs_t* fs, const char* path) {
    char file_types[10] ={'-', 'd', 'l'};
    baidu::bfs::BfsFileInfo* files = NULL;
    int num;
    int32_t ret = fs->bfs_fs->ListDirectory(path, &files, &num);
    if (ret != 0) {
        return ret;
    }
    printf("Found %d items\n", num);
    for (int i = 0; i < num; i++) {
        char statbuf[16] = "-rwxrwxrwx";
        int32_t file_type = files[i].mode >> 9;
        int32_t file_perm = files[i].mode & 0777;
        statbuf[0] = file_types[file_type];

        for (int j = 1; j < 10; j++) {
            if ((file_perm & (1<<(9-j))) == 0) {
                statbuf[j] = '-';
            }
        }
        char timestr[64];
        struct tm stm;
        time_t ctime = files[i].ctime;
        localtime_r(&ctime, &stm);
        snprintf(timestr, sizeof(timestr), "%4d-%02d-%02d %2d:%02d",
            stm.tm_year+1900, stm.tm_mon+1, stm.tm_mday, stm.tm_hour, stm.tm_min);
        std::string prefix = path;
        if (files[i].name[0] == '\0') {
            int32_t pos = prefix.size() - 1;
            while (pos >= 0 && prefix[pos] == '/') {
                pos--;
            }
            prefix.resize(pos + 1);
        }
        printf("%s %-9s %s %s%s\n",
               statbuf, baidu::common::HumanReadableString(files[i].size).c_str(),
               timestr, prefix.c_str(), files[i].name);
    }
    delete[] files;
    return 0;
}

int bfs_delete_file(bfs_fs_t* fs, const char* path) {
    return fs->bfs_fs->DeleteFile(path);
}

int bfs_rename(bfs_fs_t* fs, const char* oldpath, const char* newpath) {
    return fs->bfs_fs->Rename(oldpath, newpath);
}

int bfs_touchz(bfs_fs_t* fs, const char* path) {
    baidu::bfs::File* file;
    int32_t ret = fs->bfs_fs->OpenFile(path, O_WRONLY, 0644,
            &file, baidu::bfs::WriteOptions());
    delete file;
    return ret;
}

int bfs_symlink(bfs_fs_t* fs, const char* src, const char* dst) {
    return fs->bfs_fs->Symlink(src, dst);
}

int bfs_cat(bfs_fs_t* fs, const char* path) {
    int64_t bytes = 0;
    baidu::bfs::File* file;
    int32_t ret = fs->bfs_fs->OpenFile(path, O_RDONLY, &file,
            baidu::bfs::ReadOptions());
    if (ret != 0) {
        return ret;
    }
    char buf[10240];
    int32_t len = 0;
    while (1) {
        len = file->Read(buf, sizeof(buf));
        if (len <= 0) {
            break;
        }
        bytes += len;
        write(1, buf, len);
    }
    delete file;
    return len;
}

int bfs_get(bfs_fs_t* fs, const char* bfs, const char* local) {
    std::string source = bfs;
    std::string target = local;
    std::vector<std::string> src_elements;
    bool src_isdir = false;
    if (!baidu::common::util::SplitPath(source, &src_elements, &src_isdir)
        || src_isdir || src_elements.empty()) {
        return 1;
    }
    std::string src_file_name = src_elements[src_elements.size() - 1];
    if (target.empty() || target[target.size() - 1] == '/') {
        target += src_file_name;
    }
    baidu::common::timer::AutoTimer at(0, "BfsGet", bfs);
    baidu::bfs::File* file;
    if (fs->bfs_fs->OpenFile(bfs, O_RDONLY, &file,
                baidu::bfs::ReadOptions()) != 0) {
        return 2;
    }
    FILE* fp = fopen(target.c_str(), "wb");
    if (fp == NULL) {
        delete file;
        return 3;
    }

    char buf[10240];
    int64_t bytes = 0;
    int32_t len = 0;
    while (1) {
        len = file->Read(buf, sizeof(buf));
        if (len <= 0) {
            if (len < 0) {
                fclose(fp);
                return 4;
            }
            break;
        }
        bytes += len;
        fwrite(buf, len, 1, fp);
    }
    printf("Read %ld bytes from %s\n", bytes, source.c_str());
    delete file;
    fclose(fp);
    return len;
}

int bfs_put(bfs_fs_t* fs, const char* local, const char* bfs) {
    std::string source = local;
    std::string target = bfs;
    if (source.empty() || source[source.size() - 1] == '/' || target.empty()) {
        return 1;
    }
    std::string src_file_name;
    size_t pos = source.rfind('/');
    if (pos == std::string::npos) {
        src_file_name = source;
    } else {
        src_file_name = source.substr(pos+1);
    }
    if (target[target.size() - 1] == '/') {
        target += src_file_name;
    }

    baidu::common::timer::AutoTimer at(0, "BfsPut", target.c_str());
    FILE* fp = fopen(local, "rb");
    if (fp == NULL) {
        return 2;
    }
    struct stat st;
    if (stat(local, &st)) {
        fclose(fp);
        return 3;
    }
    baidu::bfs::File* file;
    if (fs->bfs_fs->OpenFile(target.c_str(), O_WRONLY | O_TRUNC, st.st_mode,
                &file, baidu::bfs::WriteOptions()) != 0) {
        fclose(fp);
        return 4;
    }
    char buf[10240];
    int64_t len = 0;
    int32_t bytes = 0;
    int ret = 0;
    while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) {
        int32_t write_bytes = file->Write(buf, bytes);
        if (write_bytes < bytes) {
            ret = 5;
            break;
        }
        len += bytes;
    }
    fclose(fp);
    if (file->Close() != 0) {
        ret = 6;
    }
    delete file;
    printf("Put file to bfs %s %ld bytes\n", target.c_str(), len);
    return ret;
}

int64_t bfs_du_v2(bfs_fs_t* fs, const char* path) {
    int64_t du_size = 0;
    if (fs->bfs_fs->DiskUsage(path, &du_size) != 0) {
        fprintf(stderr, "Compute Disk Usage fail: %s\n", path);
        return -1;
    }
    printf("%-9s\t%s\n",
           baidu::common::HumanReadableString(du_size).c_str(), path);
    return du_size;
}

int bfs_du(bfs_fs_t* fs, const char* path) {
    std::string str_path = path;
    assert(str_path.size() > 0);
    if (str_path[str_path.size() - 1] != '*') {
        if (bfs_du_v2(fs, path) < 0) {
            return -1;
        }
        return 0;
    }

    // Wildcard
    str_path.resize(str_path.size() - 1);
    std::string ppath = str_path.substr(0, str_path.rfind('/') + 1);
    std::string prefix = str_path.substr(ppath.size());
    int num = 0;
    baidu::bfs::BfsFileInfo* files = NULL;
    int32_t ret = fs->bfs_fs->ListDirectory(ppath.c_str(), &files, &num);
    if (ret != 0) {
        return ret;
    }
    int64_t total_size = 0;
    for (int j = 0; j < num; j++) {
        std::string name(files[j].name);
        if (name.find(prefix) != std::string::npos) {
            int64_t sz = bfs_du_v2(fs, (ppath + name).c_str());
            if (sz > 0) total_size += sz;
        }
    }
    printf("%s Total: %s\n",
            path, baidu::common::HumanReadableString(total_size).c_str());
    delete[] files;
    return ret;
}

int bfs_rm_dir(bfs_fs_t* fs, const char* path, bool recursive) {
    return fs->bfs_fs->DeleteDirectory(path, recursive);
}

int bfs_change_bfs_fslica_num(bfs_fs_t* fs, const char* path,
        const char* bfs_fslica_num) {
    if (!isdigit(*bfs_fslica_num)) {
        return -1;
    }
    return fs->bfs_fs->ChangeReplicaNum(path, strtol(bfs_fslica_num, NULL, 10));
}

int bfs_chmod(bfs_fs_t* fs, const char* str_mode, const char* path) {
    char* end_pos = NULL;
    int32_t mode = strtol(str_mode, &end_pos, 8);
    if (end_pos != NULL) {
        return -1;
    }
    return fs->bfs_fs->Chmod(mode, path);
}

int bfs_location(bfs_fs_t* fs, const char* path) {
    std::map<int64_t, std::vector<std::string> > locations;
    int32_t ret = fs->bfs_fs->GetFileLocation(path, &locations);
    if (ret != 0) {
        return ret;
    }
    for (std::map<int64_t, std::vector<std::string> >::iterator it =
            locations.begin(); it != locations.end(); ++it) {
        printf("block_id #%ld:\n", it->first);
        for (size_t i = 0; i < (it->second).size(); ++i) {
            printf("%s\n", (it->second)[i].c_str());
        }
    }
    return 0;
}

}
/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
<commit_msg>fix parse conf bug in bfs_c.cc (#919)<commit_after>// Copyright (c) 2017, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "sdk/bfs_c.h"
#include "sdk/bfs.h"

#include <gflags/gflags.h>

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <map>

#include <common/string_util.h>
#include <common/timer.h>
#include <common/util.h>

DECLARE_string(flagfile);
DECLARE_string(nameserver_nodes);

extern "C"{

struct bfs_fs_t {
    baidu::bfs::FS*  bfs_fs;
};

struct bfs_file_t {
    baidu::bfs::File* bfs_file;
};

bfs_fs_t* bfs_open_file_system(const char* flag_file) {
    if (flag_file) {
        FLAGS_flagfile = flag_file;
    } else {
        FLAGS_flagfile = "./bfs.flag";
    }

    // This function google::ParseCommandLineFlags(&argc, &argv, false),
    // parse the config from the argv[1]. And the argv[0] just use to represent
    // a program name, it's not a config parameter.
    int argc = 1;
    char* name = const_cast<char *>("bfs_c.cc");
    char** argv = &name;
    ::google::ParseCommandLineFlags(&argc, &argv, false);

    bfs_fs_t* fs = new bfs_fs_t;
    std::string ns_address = FLAGS_nameserver_nodes;
    bool ret = baidu::bfs::FS::OpenFileSystem(ns_address.c_str(),
            &(fs->bfs_fs), baidu::bfs::FSOptions());
    if (!ret) {
        delete fs;
        return NULL;
    }
    return fs;
}

bfs_file_t* bfs_open_file(const bfs_fs_t* fs, const char* path, int flag) {
    if (flag != O_RDONLY && flag != O_WRONLY) {
        return NULL;
    }
    bfs_file_t* file = new bfs_file_t;
    int32_t ret = 0;
    if (flag == O_RDONLY) {
        ret = fs->bfs_fs->OpenFile(path, flag,
                &(file->bfs_file), baidu::bfs::ReadOptions());

    } else {
        ret = fs->bfs_fs->OpenFile(path, flag,
                &(file->bfs_file), baidu::bfs::WriteOptions());
    }
    if (ret != 0) {
        delete file->bfs_file;
        delete file;
        file = NULL;
    }
    return file;
}

int bfs_close_file(bfs_file_t* file) {
    int32_t ret = file->bfs_file->Close();
    delete file->bfs_file;
    file->bfs_file = NULL;
    delete file;
    return ret;
}

int bfs_write_file(bfs_file_t* file, const char* buf, int32_t len) {
    return file->bfs_file->Write(buf, len);
}

int bfs_read_file(bfs_file_t* file, char* buf, int32_t len) {
    return file->bfs_file->Read(buf, len);
}

int64_t bfs_seek(bfs_file_t* file, int64_t offset, int32_t whence) {
    return file->bfs_file->Seek(offset, whence);
}

int bfs_create_directory(bfs_fs_t* fs, const char* path) {
    return fs->bfs_fs->CreateDirectory(path);
}

int bfs_list_directory(bfs_fs_t* fs, const char* path) {
    char file_types[10] ={'-', 'd', 'l'};
    baidu::bfs::BfsFileInfo* files = NULL;
    int num;
    int32_t ret = fs->bfs_fs->ListDirectory(path, &files, &num);
    if (ret != 0) {
        return ret;
    }
    printf("Found %d items\n", num);
    for (int i = 0; i < num; i++) {
        char statbuf[16] = "-rwxrwxrwx";
        int32_t file_type = files[i].mode >> 9;
        int32_t file_perm = files[i].mode & 0777;
        statbuf[0] = file_types[file_type];

        for (int j = 1; j < 10; j++) {
            if ((file_perm & (1<<(9-j))) == 0) {
                statbuf[j] = '-';
            }
        }
        char timestr[64];
        struct tm stm;
        time_t ctime = files[i].ctime;
        localtime_r(&ctime, &stm);
        snprintf(timestr, sizeof(timestr), "%4d-%02d-%02d %2d:%02d",
            stm.tm_year+1900, stm.tm_mon+1, stm.tm_mday, stm.tm_hour, stm.tm_min);
        std::string prefix = path;
        if (files[i].name[0] == '\0') {
            int32_t pos = prefix.size() - 1;
            while (pos >= 0 && prefix[pos] == '/') {
                pos--;
            }
            prefix.resize(pos + 1);
        }
        printf("%s %-9s %s %s%s\n",
               statbuf, baidu::common::HumanReadableString(files[i].size).c_str(),
               timestr, prefix.c_str(), files[i].name);
    }
    delete[] files;
    return 0;
}

int bfs_delete_file(bfs_fs_t* fs, const char* path) {
    return fs->bfs_fs->DeleteFile(path);
}

int bfs_rename(bfs_fs_t* fs, const char* oldpath, const char* newpath) {
    return fs->bfs_fs->Rename(oldpath, newpath);
}

int bfs_touchz(bfs_fs_t* fs, const char* path) {
    baidu::bfs::File* file;
    int32_t ret = fs->bfs_fs->OpenFile(path, O_WRONLY, 0644,
            &file, baidu::bfs::WriteOptions());
    delete file;
    return ret;
}

int bfs_symlink(bfs_fs_t* fs, const char* src, const char* dst) {
    return fs->bfs_fs->Symlink(src, dst);
}

int bfs_cat(bfs_fs_t* fs, const char* path) {
    int64_t bytes = 0;
    baidu::bfs::File* file;
    int32_t ret = fs->bfs_fs->OpenFile(path, O_RDONLY, &file,
            baidu::bfs::ReadOptions());
    if (ret != 0) {
        return ret;
    }
    char buf[10240];
    int32_t len = 0;
    while (1) {
        len = file->Read(buf, sizeof(buf));
        if (len <= 0) {
            break;
        }
        bytes += len;
        write(1, buf, len);
    }
    delete file;
    return len;
}

int bfs_get(bfs_fs_t* fs, const char* bfs, const char* local) {
    std::string source = bfs;
    std::string target = local;
    std::vector<std::string> src_elements;
    bool src_isdir = false;
    if (!baidu::common::util::SplitPath(source, &src_elements, &src_isdir)
        || src_isdir || src_elements.empty()) {
        return 1;
    }
    std::string src_file_name = src_elements[src_elements.size() - 1];
    if (target.empty() || target[target.size() - 1] == '/') {
        target += src_file_name;
    }
    baidu::common::timer::AutoTimer at(0, "BfsGet", bfs);
    baidu::bfs::File* file;
    if (fs->bfs_fs->OpenFile(bfs, O_RDONLY, &file,
                baidu::bfs::ReadOptions()) != 0) {
        return 2;
    }
    FILE* fp = fopen(target.c_str(), "wb");
    if (fp == NULL) {
        delete file;
        return 3;
    }

    char buf[10240];
    int64_t bytes = 0;
    int32_t len = 0;
    while (1) {
        len = file->Read(buf, sizeof(buf));
        if (len <= 0) {
            if (len < 0) {
                fclose(fp);
                return 4;
            }
            break;
        }
        bytes += len;
        fwrite(buf, len, 1, fp);
    }
    printf("Read %ld bytes from %s\n", bytes, source.c_str());
    delete file;
    fclose(fp);
    return len;
}

int bfs_put(bfs_fs_t* fs, const char* local, const char* bfs) {
    std::string source = local;
    std::string target = bfs;
    if (source.empty() || source[source.size() - 1] == '/' || target.empty()) {
        return 1;
    }
    std::string src_file_name;
    size_t pos = source.rfind('/');
    if (pos == std::string::npos) {
        src_file_name = source;
    } else {
        src_file_name = source.substr(pos+1);
    }
    if (target[target.size() - 1] == '/') {
        target += src_file_name;
    }

    baidu::common::timer::AutoTimer at(0, "BfsPut", target.c_str());
    FILE* fp = fopen(local, "rb");
    if (fp == NULL) {
        return 2;
    }
    struct stat st;
    if (stat(local, &st)) {
        fclose(fp);
        return 3;
    }
    baidu::bfs::File* file;
    if (fs->bfs_fs->OpenFile(target.c_str(), O_WRONLY | O_TRUNC, st.st_mode,
                &file, baidu::bfs::WriteOptions()) != 0) {
        fclose(fp);
        return 4;
    }
    char buf[10240];
    int64_t len = 0;
    int32_t bytes = 0;
    int ret = 0;
    while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) {
        int32_t write_bytes = file->Write(buf, bytes);
        if (write_bytes < bytes) {
            ret = 5;
            break;
        }
        len += bytes;
    }
    fclose(fp);
    if (file->Close() != 0) {
        ret = 6;
    }
    delete file;
    printf("Put file to bfs %s %ld bytes\n", target.c_str(), len);
    return ret;
}

int64_t bfs_du_v2(bfs_fs_t* fs, const char* path) {
    int64_t du_size = 0;
    if (fs->bfs_fs->DiskUsage(path, &du_size) != 0) {
        fprintf(stderr, "Compute Disk Usage fail: %s\n", path);
        return -1;
    }
    printf("%-9s\t%s\n",
           baidu::common::HumanReadableString(du_size).c_str(), path);
    return du_size;
}

int bfs_du(bfs_fs_t* fs, const char* path) {
    std::string str_path = path;
    assert(str_path.size() > 0);
    if (str_path[str_path.size() - 1] != '*') {
        if (bfs_du_v2(fs, path) < 0) {
            return -1;
        }
        return 0;
    }

    // Wildcard
    str_path.resize(str_path.size() - 1);
    std::string ppath = str_path.substr(0, str_path.rfind('/') + 1);
    std::string prefix = str_path.substr(ppath.size());
    int num = 0;
    baidu::bfs::BfsFileInfo* files = NULL;
    int32_t ret = fs->bfs_fs->ListDirectory(ppath.c_str(), &files, &num);
    if (ret != 0) {
        return ret;
    }
    int64_t total_size = 0;
    for (int j = 0; j < num; j++) {
        std::string name(files[j].name);
        if (name.find(prefix) != std::string::npos) {
            int64_t sz = bfs_du_v2(fs, (ppath + name).c_str());
            if (sz > 0) total_size += sz;
        }
    }
    printf("%s Total: %s\n",
            path, baidu::common::HumanReadableString(total_size).c_str());
    delete[] files;
    return ret;
}

int bfs_rm_dir(bfs_fs_t* fs, const char* path, bool recursive) {
    return fs->bfs_fs->DeleteDirectory(path, recursive);
}

int bfs_change_bfs_fslica_num(bfs_fs_t* fs, const char* path,
        const char* bfs_fslica_num) {
    if (!isdigit(*bfs_fslica_num)) {
        return -1;
    }
    return fs->bfs_fs->ChangeReplicaNum(path, strtol(bfs_fslica_num, NULL, 10));
}

int bfs_chmod(bfs_fs_t* fs, const char* str_mode, const char* path) {
    char* end_pos = NULL;
    int32_t mode = strtol(str_mode, &end_pos, 8);
    if (end_pos != NULL) {
        return -1;
    }
    return fs->bfs_fs->Chmod(mode, path);
}

int bfs_location(bfs_fs_t* fs, const char* path) {
    std::map<int64_t, std::vector<std::string> > locations;
    int32_t ret = fs->bfs_fs->GetFileLocation(path, &locations);
    if (ret != 0) {
        return ret;
    }
    for (std::map<int64_t, std::vector<std::string> >::iterator it =
            locations.begin(); it != locations.end(); ++it) {
        printf("block_id #%ld:\n", it->first);
        for (size_t i = 0; i < (it->second).size(); ++i) {
            printf("%s\n", (it->second)[i].c_str());
        }
    }
    return 0;
}

}
/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkPM4fPriv.h"
#include "SkRasterPipeline.h"
#include "SkReadBuffer.h"
#include "SkString.h"
#include "SkToSRGBColorFilter.h"
#include "SkWriteBuffer.h"

#if SK_SUPPORT_GPU
    #include "GrColorSpaceXform.h"
#endif

void SkToSRGBColorFilter::onAppendStages(SkRasterPipeline* p,
                                         SkColorSpace* /*dst color space*/,
                                         SkArenaAlloc* alloc,
                                         bool shaderIsOpaque) const {
    // Step 1: Linearize by undoing the src transfer function.
    // Linear and sRGB will return true to isNumericalTransferFn(), so we check them first.
    SkColorSpaceTransferFn srcFn;
    if (fSrcColorSpace->gammaIsLinear()) {
        // Nothing to do.
    } else if (fSrcColorSpace->gammaCloseToSRGB()) {
        p->append(SkRasterPipeline::from_srgb);
    } else if (fSrcColorSpace->isNumericalTransferFn(&srcFn)) {
        auto copy = alloc->make<SkColorSpaceTransferFn>(srcFn);
        p->append(SkRasterPipeline::parametric, copy);
    } else {
        SkDEBUGFAIL("Looks like we got a table transfer function here, quite unexpectedly.");
        // TODO: If we really need to handle this, we can, but I don't think Ganesh does.
    }

    // Step 2: Transform to sRGB gamut (without clamping).
    append_gamut_transform(p,
                           alloc,
                           fSrcColorSpace.get(),
                           SkColorSpace::MakeSRGB().get(),
                           kPremul_SkAlphaType);

    // Step 3: Back to sRGB encoding.
    p->append(SkRasterPipeline::to_srgb);
}

sk_sp<SkColorFilter> SkToSRGBColorFilter::Make(sk_sp<SkColorSpace> srcColorSpace) {
    if (!srcColorSpace || srcColorSpace->isSRGB()) {
        return nullptr;
    } else {
        return sk_sp<SkColorFilter>(new SkToSRGBColorFilter(std::move(srcColorSpace)));
    }
}

SkToSRGBColorFilter::SkToSRGBColorFilter(sk_sp<SkColorSpace> srcColorSpace)
        : fSrcColorSpace(std::move(srcColorSpace)) {
    SkASSERT(fSrcColorSpace);
}

sk_sp<SkFlattenable> SkToSRGBColorFilter::CreateProc(SkReadBuffer& buffer) {
    auto data = buffer.readByteArrayAsData();
    return data ? Make(SkColorSpace::Deserialize(data->data(), data->size())) : nullptr;
}

void SkToSRGBColorFilter::flatten(SkWriteBuffer& buffer) const {
    buffer.writeDataAsByteArray(fSrcColorSpace->serialize().get());
}

#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> SkToSRGBColorFilter::asFragmentProcessor(
        GrContext*, const GrColorSpaceInfo&) const {
    return GrColorSpaceXformEffect::Make(fSrcColorSpace.get(), SkColorSpace::MakeSRGB().get());
}
#endif
<commit_msg>Reland "update SkToSRGBColorFilter color management"<commit_after>/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorSpaceXformSteps.h"
#include "SkPM4fPriv.h"
#include "SkRasterPipeline.h"
#include "SkReadBuffer.h"
#include "SkString.h"
#include "SkToSRGBColorFilter.h"
#include "SkWriteBuffer.h"

#if SK_SUPPORT_GPU
    #include "GrColorSpaceXform.h"
#endif

void SkToSRGBColorFilter::onAppendStages(SkRasterPipeline* p,
                                         SkColorSpace* /*dst color space*/,
                                         SkArenaAlloc* alloc,
                                         bool shaderIsOpaque) const {
    alloc->make<SkColorSpaceXformSteps>(fSrcColorSpace.get(), kPremul_SkAlphaType,
                                        SkColorSpace::MakeSRGB().get())
        ->apply(p);
}

sk_sp<SkColorFilter> SkToSRGBColorFilter::Make(sk_sp<SkColorSpace> srcColorSpace) {
    if (!srcColorSpace || srcColorSpace->isSRGB()) {
        return nullptr;
    } else {
        return sk_sp<SkColorFilter>(new SkToSRGBColorFilter(std::move(srcColorSpace)));
    }
}

SkToSRGBColorFilter::SkToSRGBColorFilter(sk_sp<SkColorSpace> srcColorSpace)
        : fSrcColorSpace(std::move(srcColorSpace)) {
    SkASSERT(fSrcColorSpace);
}

sk_sp<SkFlattenable> SkToSRGBColorFilter::CreateProc(SkReadBuffer& buffer) {
    auto data = buffer.readByteArrayAsData();
    return data ? Make(SkColorSpace::Deserialize(data->data(), data->size())) : nullptr;
}

void SkToSRGBColorFilter::flatten(SkWriteBuffer& buffer) const {
    buffer.writeDataAsByteArray(fSrcColorSpace->serialize().get());
}

#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> SkToSRGBColorFilter::asFragmentProcessor(
        GrContext*, const GrColorSpaceInfo&) const {
    return GrColorSpaceXformEffect::Make(fSrcColorSpace.get(), SkColorSpace::MakeSRGB().get());
}
#endif
<|endoftext|>