<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/iam/iam_credentials_client.h"
#include "google/cloud/spanner/admin/instance_admin_client.h"
#include "google/cloud/common_options.h"
#include "google/cloud/grpc_options.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/log.h"
#include "google/cloud/project.h"
#include "google/cloud/testing_util/example_driver.h"
#include "absl/strings/match.h"
#include "absl/strings/str_split.h"
#include "absl/time/time.h"  // NOLINT(modernize-deprecated-headers)
#include <curl/curl.h>
#include <hello_world_grpc/hello_world.grpc.pb.h>
#include <chrono>
#include <stdexcept>
#include <thread>

namespace {

auto constexpr kTokenValidationPeriod = std::chrono::seconds(30);

extern "C" size_t CurlOnWriteData(char* ptr, size_t size, size_t nmemb,
                                  void* userdata) {
  auto* buffer = reinterpret_cast<std::string*>(userdata);
  buffer->append(ptr, size * nmemb);
  return size * nmemb;
}

google::cloud::StatusOr<std::string> HttpGet(std::string const& url,
                                             std::string const& token) {
  static auto const kCurlInit = [] {
    return curl_global_init(CURL_GLOBAL_ALL);
  }();
  (void)kCurlInit;
  auto const authorization = "Authorization: Bearer " + token;
  using Headers = std::unique_ptr<curl_slist, decltype(&curl_slist_free_all)>;
  auto const headers = Headers{
      curl_slist_append(nullptr, authorization.c_str()), curl_slist_free_all};
  using CurlHandle = std::unique_ptr<CURL, decltype(&curl_easy_cleanup)>;
  auto curl = CurlHandle(curl_easy_init(), curl_easy_cleanup);
  if (!curl) throw std::runtime_error("Failed to create CurlHandle");
  std::string buffer;
  curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headers.get());
  curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, &CurlOnWriteData);
  curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &buffer);

  CURLcode code = curl_easy_perform(curl.get());
  if (code != CURLE_OK) throw std::runtime_error(curl_easy_strerror(code));
  long status;  // NOLINT(google-runtime-int)
  code = curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &status);
  if (code != CURLE_OK) throw std::runtime_error(curl_easy_strerror(code));

  // Handle common errors as Status, this is not exhaustive.
  using ::google::cloud::Status;
  using ::google::cloud::StatusCode;
  if (status == 400) return Status(StatusCode::kInvalidArgument, buffer);
  if (status == 401) return Status(StatusCode::kUnauthenticated, buffer);
  if (status == 403) return Status(StatusCode::kPermissionDenied, buffer);
  if (status >= 500) return Status(StatusCode::kInternal, buffer);
  if (status < 200 || status >= 300) {
    std::ostringstream os;
    os << "HTTP error [" << status << "]: " << buffer;
    return Status(StatusCode::kUnknown, buffer);
  }
  return buffer;
}

// TODO(#6185) - this should be done by the generated code
std::set<std::string> DefaultTracingComponents() {
  return absl::StrSplit(
      google::cloud::internal::GetEnv("GOOGLE_CLOUD_CPP_ENABLE_TRACING")
          .value_or(""),
      ',');
}

google::iam::credentials::v1::GenerateAccessTokenResponse UseAccessToken(
    google::cloud::iam::IAMCredentialsClient client,
    std::vector<std::string> const& argv) {
  namespace iam = ::google::cloud::iam;
  return [](iam::IAMCredentialsClient client,
            std::string const& service_account, std::string const& project_id) {
    google::protobuf::Duration duration;
    duration.set_seconds(
        std::chrono::seconds(2 * kTokenValidationPeriod).count());
    auto token = client.GenerateAccessToken(
        "projects/-/serviceAccounts/" + service_account, /*delegates=*/{},
        /*scope=*/{"https://www.googleapis.com/auth/cloud-platform"}, duration);
    if (!token) throw std::runtime_error(token.status().message());

    auto const expiration =
        std::chrono::system_clock::from_time_t(token->expire_time().seconds());
    std::cout << "Fetched token starting with "
              << token->access_token().substr(0, 8)
              << ", which will expire around " << absl::FromChrono(expiration)
              << std::endl;

    auto credentials = grpc::CompositeChannelCredentials(
        grpc::SslCredentials({}),
        grpc::AccessTokenCredentials(token->access_token()));

    google::cloud::spanner_admin::InstanceAdminClient admin(
        google::cloud::spanner_admin::MakeInstanceAdminConnection(
            google::cloud::Options{}.set<google::cloud::GrpcCredentialOption>(
                credentials)));
    for (auto instance :
         admin.ListInstances(google::cloud::Project(project_id).FullName())) {
      if (!instance) throw std::runtime_error(instance.status().message());
      std::cout << "Instance: " << instance->name() << "\n";
    }

    return *std::move(token);
  }(std::move(client), argv.at(0), argv.at(1));
}

void UseAccessTokenUntilExpired(google::cloud::iam::IAMCredentialsClient client,
                                std::vector<std::string> const& argv) {
  auto token = UseAccessToken(std::move(client), argv);
  auto const& project_id = argv.at(1);
  auto const expiration =
      std::chrono::system_clock::from_time_t(token.expire_time().seconds());
  auto const deadline = expiration + 4 * kTokenValidationPeriod;
  std::cout << "Running until " << absl::FromChrono(deadline)
            << ". This is past the access token expiration time ("
            << absl::FromChrono(expiration) << ")" << std::endl;

  auto iteration = [=](bool expired) {
    auto credentials = grpc::CompositeChannelCredentials(
        grpc::SslCredentials({}),
        grpc::AccessTokenCredentials(token.access_token()));
    google::cloud::spanner_admin::InstanceAdminClient admin(
        google::cloud::spanner_admin::MakeInstanceAdminConnection(
            google::cloud::Options{}.set<google::cloud::GrpcCredentialOption>(
                credentials)));
    for (auto instance :
         admin.ListInstances(google::cloud::Project(project_id).FullName())) {
      // kUnauthenticated receives special treatment, it is the error received
      // when the token expires.
      if (instance.status().code() ==
          google::cloud::StatusCode::kUnauthenticated) {
        std::cout << "error [" << instance.status() << "]";
        if (!expired) {
          std::cout << ": unexpected, but could be a race condition."
                    << " Trying again\n";
          return true;
        }
        std::cout << ": this is expected as the token is expired\n";
        return false;
      }
      if (!instance) throw std::runtime_error(instance.status().message());
      std::cout << "success (" << instance->name() << ")\n";
      return true;
    }
    return false;
  };

  for (auto now = std::chrono::system_clock::now(); now < deadline;
       now = std::chrono::system_clock::now()) {
    auto const expired = (now > expiration);
    std::cout << absl::FromChrono(now) << ": running iteration with "
              << (expired ? "an expired" : "a valid") << " token ";
    if (!iteration(expired)) break;
    std::this_thread::sleep_for(kTokenValidationPeriod);
  }
}

void UseIdTokenHttp(google::cloud::iam::IAMCredentialsClient client,
                    std::vector<std::string> const& argv) {
  namespace iam = ::google::cloud::iam;
  [](iam::IAMCredentialsClient client, std::string const& service_account,
     std::string const& hello_world_url) {
    auto token = client.GenerateIdToken(
        "projects/-/serviceAccounts/" + service_account, /*delegates=*/{},
        /*audience=*/{hello_world_url},
        /*include_email=*/true);
    if (!token) throw std::runtime_error(token.status().message());

    auto backoff = std::chrono::milliseconds(250);
    for (int i = 0; i != 3; ++i) {
      auto text = HttpGet(hello_world_url, token->token());
      if (text.ok()) {
        std::cout << "Server says: " << *text << "\n";
        return;
      }
      std::this_thread::sleep_for(backoff);
      backoff *= 2;
    }
    throw std::runtime_error("Could not contact server after 3 attempts");
  }(std::move(client), argv.at(0), argv.at(1));
}

void UseIdTokenGrpc(google::cloud::iam::IAMCredentialsClient client,
                    std::vector<std::string> const& argv) {
  namespace iam = ::google::cloud::iam;
  [](iam::IAMCredentialsClient client, std::string const& service_account,
     std::string const& url) {
    auto token = client.GenerateIdToken(
        "projects/-/serviceAccounts/" + service_account, /*delegates=*/{},
        /*audience=*/{url},
        /*include_email=*/true);
    if (!token) throw std::runtime_error(token.status().message());

    auto const prefix = std::string{"https://"};
    if (!absl::StartsWith(url, prefix)) {
      throw std::runtime_error("Invalid URL" + url);
    }
    auto endpoint = url.substr(prefix.length()) + ":443";
    auto credentials = grpc::CompositeChannelCredentials(
        grpc::SslCredentials(grpc::SslCredentialsOptions{}),
        grpc::AccessTokenCredentials(token->token()));
    auto channel = grpc::CreateChannel(endpoint, credentials);
    auto stub = google::cloud::examples::Greet::NewStub(channel);
    auto request = google::cloud::examples::HelloRequest{};
    auto backoff = std::chrono::milliseconds(250);
    for (int i = 0; i != 3; ++i) {
      grpc::ClientContext context;
      google::cloud::examples::HelloResponse response;
      auto status = stub->Hello(&context, request, &response);
      if (status.ok()) {
        std::cout << "Servers says: " << response.greeting() << "\n";
        return;
      }
      std::cout << "Server returned error=" << status.error_code()
                << ", message=" << status.error_message() << "\n";
      std::this_thread::sleep_for(backoff);
      backoff *= 2;
    }
    throw std::runtime_error("Could not contact server after 3 attempts");
  }(std::move(client), argv.at(0), argv.at(1));
}

void AutoRun(std::vector<std::string> const& argv) {
  namespace examples = ::google::cloud::testing_util;
  using ::google::cloud::internal::GetEnv;

  if (!argv.empty()) throw examples::Usage{"auto"};
  examples::CheckEnvironmentVariablesAreSet({
      "GOOGLE_CLOUD_PROJECT",
      "GOOGLE_CLOUD_CPP_IAM_TEST_SERVICE_ACCOUNT",
      "GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_SERVICE_ACCOUNT",
      "GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_HTTP_URL",
      "GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_GRPC_URL",
  });
  auto project_id = GetEnv("GOOGLE_CLOUD_PROJECT").value();
  auto const test_iam_service_account =
      GetEnv("GOOGLE_CLOUD_CPP_IAM_TEST_SERVICE_ACCOUNT").value_or("");
  auto const hello_world_service_account =
      GetEnv("GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_SERVICE_ACCOUNT").value_or("");
  auto const hello_world_http_url =
      GetEnv("GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_HTTP_URL").value_or("");
  auto const hello_world_grpc_url =
      GetEnv("GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_GRPC_URL").value_or("");

  auto client = google::cloud::iam::IAMCredentialsClient(
      google::cloud::iam::MakeIAMCredentialsConnection(
          google::cloud::Options{}
              .set<google::cloud::TracingComponentsOption>(
                  DefaultTracingComponents())
              .set<google::cloud::GrpcTracingOptionsOption>(
                  // There are some credentials returned by RPCs. On an error
                  // these are printed. This truncates them, making the output
                  // safe, and yet useful for debugging.
                  google::cloud::TracingOptions{}.SetOptions(
                      "truncate_string_field_longer_than=32"))));

  std::cout << "\nRunning UseAccessToken() example" << std::endl;
  UseAccessToken(client, {test_iam_service_account, project_id});

  std::cout << "\nRunning UseAccessTokenUntilExpired() example" << std::endl;
  UseAccessTokenUntilExpired(client, {test_iam_service_account, project_id});

  std::cout << "\nRunning UseIdTokenHttp() example" << std::endl;
  UseIdTokenHttp(client, {hello_world_service_account, hello_world_http_url});

  std::cout << "\nRunning UseIdTokenGrpc() example" << std::endl;
  UseIdTokenGrpc(client, {hello_world_service_account, hello_world_grpc_url});
}

}  // namespace

int main(int argc, char* argv[]) {  // NOLINT(bugprone-exception-escape)
  using ::google::cloud::testing_util::Example;

  using ClientCommand = std::function<void(
      google::cloud::iam::IAMCredentialsClient, std::vector<std::string> argv)>;

  auto make_entry = [](std::string name,
                       std::vector<std::string> const& arg_names,
                       ClientCommand const& command) {
    auto adapter = [=](std::vector<std::string> argv) {
      if ((argv.size() == 1 && argv[0] == "--help") ||
          argv.size() != arg_names.size()) {
        std::string usage = name;
        for (auto const& a : arg_names) usage += " <" + a + ">";
        throw google::cloud::testing_util::Usage{std::move(usage)};
      }
      auto client = google::cloud::iam::IAMCredentialsClient(
          google::cloud::iam::MakeIAMCredentialsConnection(
              google::cloud::Options{}
                  .set<google::cloud::TracingComponentsOption>(
                      DefaultTracingComponents())));
      command(client, std::move(argv));
    };
    return google::cloud::testing_util::Commands::value_type(std::move(name),
                                                             adapter);
  };

  Example example({
      make_entry("use-access-token", {"service-account", "project-id"},
                 UseAccessToken),
      make_entry("use-access-token-until-expired",
                 {"service-account", "project-id"}, UseAccessTokenUntilExpired),
      make_entry("use-id-token-http",
                 {"service-account", "hello-world-http-url"}, UseIdTokenHttp),
      make_entry("use-id-token-grpc",
                 {"service-account", "hello-world-http-url"}, UseIdTokenGrpc),
      {"auto", AutoRun},
  });
  return example.Run(argc, argv);
}
<commit_msg>chore: change Spanner instance admin call used by example (#10120)<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/iam/iam_credentials_client.h"
#include "google/cloud/spanner/admin/instance_admin_client.h"
#include "google/cloud/common_options.h"
#include "google/cloud/grpc_options.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/log.h"
#include "google/cloud/project.h"
#include "google/cloud/testing_util/example_driver.h"
#include "absl/strings/match.h"
#include "absl/strings/str_split.h"
#include "absl/time/time.h"  // NOLINT(modernize-deprecated-headers)
#include <curl/curl.h>
#include <hello_world_grpc/hello_world.grpc.pb.h>
#include <chrono>
#include <stdexcept>
#include <thread>

namespace {

auto constexpr kTokenValidationPeriod = std::chrono::seconds(30);

extern "C" size_t CurlOnWriteData(char* ptr, size_t size, size_t nmemb,
                                  void* userdata) {
  auto* buffer = reinterpret_cast<std::string*>(userdata);
  buffer->append(ptr, size * nmemb);
  return size * nmemb;
}

google::cloud::StatusOr<std::string> HttpGet(std::string const& url,
                                             std::string const& token) {
  static auto const kCurlInit = [] {
    return curl_global_init(CURL_GLOBAL_ALL);
  }();
  (void)kCurlInit;
  auto const authorization = "Authorization: Bearer " + token;
  using Headers = std::unique_ptr<curl_slist, decltype(&curl_slist_free_all)>;
  auto const headers = Headers{
      curl_slist_append(nullptr, authorization.c_str()), curl_slist_free_all};
  using CurlHandle = std::unique_ptr<CURL, decltype(&curl_easy_cleanup)>;
  auto curl = CurlHandle(curl_easy_init(), curl_easy_cleanup);
  if (!curl) throw std::runtime_error("Failed to create CurlHandle");
  std::string buffer;
  curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
  curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headers.get());
  curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, &CurlOnWriteData);
  curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &buffer);

  CURLcode code = curl_easy_perform(curl.get());
  if (code != CURLE_OK) throw std::runtime_error(curl_easy_strerror(code));
  long status;  // NOLINT(google-runtime-int)
  code = curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &status);
  if (code != CURLE_OK) throw std::runtime_error(curl_easy_strerror(code));

  // Handle common errors as Status, this is not exhaustive.
  using ::google::cloud::Status;
  using ::google::cloud::StatusCode;
  if (status == 400) return Status(StatusCode::kInvalidArgument, buffer);
  if (status == 401) return Status(StatusCode::kUnauthenticated, buffer);
  if (status == 403) return Status(StatusCode::kPermissionDenied, buffer);
  if (status >= 500) return Status(StatusCode::kInternal, buffer);
  if (status < 200 || status >= 300) {
    std::ostringstream os;
    os << "HTTP error [" << status << "]: " << buffer;
    return Status(StatusCode::kUnknown, buffer);
  }
  return buffer;
}

// TODO(#6185) - this should be done by the generated code
std::set<std::string> DefaultTracingComponents() {
  return absl::StrSplit(
      google::cloud::internal::GetEnv("GOOGLE_CLOUD_CPP_ENABLE_TRACING")
          .value_or(""),
      ',');
}

google::iam::credentials::v1::GenerateAccessTokenResponse UseAccessToken(
    google::cloud::iam::IAMCredentialsClient client,
    std::vector<std::string> const& argv) {
  namespace iam = ::google::cloud::iam;
  return [](iam::IAMCredentialsClient client,
            std::string const& service_account, std::string const& project_id) {
    google::protobuf::Duration duration;
    duration.set_seconds(
        std::chrono::seconds(2 * kTokenValidationPeriod).count());
    auto token = client.GenerateAccessToken(
        "projects/-/serviceAccounts/" + service_account, /*delegates=*/{},
        /*scope=*/{"https://www.googleapis.com/auth/cloud-platform"}, duration);
    if (!token) throw std::runtime_error(token.status().message());

    auto const expiration =
        std::chrono::system_clock::from_time_t(token->expire_time().seconds());
    std::cout << "Fetched token starting with "
              << token->access_token().substr(0, 8)
              << ", which will expire around " << absl::FromChrono(expiration)
              << std::endl;

    auto credentials = grpc::CompositeChannelCredentials(
        grpc::SslCredentials({}),
        grpc::AccessTokenCredentials(token->access_token()));

    google::cloud::spanner_admin::InstanceAdminClient admin(
        google::cloud::spanner_admin::MakeInstanceAdminConnection(
            google::cloud::Options{}.set<google::cloud::GrpcCredentialOption>(
                credentials)));
    for (auto config : admin.ListInstanceConfigs(
             google::cloud::Project(project_id).FullName())) {
      if (!config) throw std::runtime_error(config.status().message());
      std::cout << "InstanceConfig: " << config->name() << "\n";
    }

    return *std::move(token);
  }(std::move(client), argv.at(0), argv.at(1));
}

void UseAccessTokenUntilExpired(google::cloud::iam::IAMCredentialsClient client,
                                std::vector<std::string> const& argv) {
  auto token = UseAccessToken(std::move(client), argv);
  auto const& project_id = argv.at(1);
  auto const expiration =
      std::chrono::system_clock::from_time_t(token.expire_time().seconds());
  auto const deadline = expiration + 4 * kTokenValidationPeriod;
  std::cout << "Running until " << absl::FromChrono(deadline)
            << ". This is past the access token expiration time ("
            << absl::FromChrono(expiration) << ")" << std::endl;

  auto iteration = [=](bool expired) {
    auto credentials = grpc::CompositeChannelCredentials(
        grpc::SslCredentials({}),
        grpc::AccessTokenCredentials(token.access_token()));
    google::cloud::spanner_admin::InstanceAdminClient admin(
        google::cloud::spanner_admin::MakeInstanceAdminConnection(
            google::cloud::Options{}.set<google::cloud::GrpcCredentialOption>(
                credentials)));
    for (auto config : admin.ListInstanceConfigs(
             google::cloud::Project(project_id).FullName())) {
      // kUnauthenticated receives special treatment, it is the error received
      // when the token expires.
      if (config.status().code() ==
          google::cloud::StatusCode::kUnauthenticated) {
        std::cout << "error [" << config.status() << "]";
        if (!expired) {
          std::cout << ": unexpected, but could be a race condition."
                    << " Trying again\n";
          return true;
        }
        std::cout << ": this is expected as the token is expired\n";
        return false;
      }
      if (!config) throw std::runtime_error(config.status().message());
      std::cout << "success (" << config->name() << ")\n";
      return true;
    }
    return false;
  };

  for (auto now = std::chrono::system_clock::now(); now < deadline;
       now = std::chrono::system_clock::now()) {
    auto const expired = (now > expiration);
    std::cout << absl::FromChrono(now) << ": running iteration with "
              << (expired ? "an expired" : "a valid") << " token ";
    if (!iteration(expired)) break;
    std::this_thread::sleep_for(kTokenValidationPeriod);
  }
}

void UseIdTokenHttp(google::cloud::iam::IAMCredentialsClient client,
                    std::vector<std::string> const& argv) {
  namespace iam = ::google::cloud::iam;
  [](iam::IAMCredentialsClient client, std::string const& service_account,
     std::string const& hello_world_url) {
    auto token = client.GenerateIdToken(
        "projects/-/serviceAccounts/" + service_account, /*delegates=*/{},
        /*audience=*/{hello_world_url},
        /*include_email=*/true);
    if (!token) throw std::runtime_error(token.status().message());

    auto backoff = std::chrono::milliseconds(250);
    for (int i = 0; i != 3; ++i) {
      auto text = HttpGet(hello_world_url, token->token());
      if (text.ok()) {
        std::cout << "Server says: " << *text << "\n";
        return;
      }
      std::this_thread::sleep_for(backoff);
      backoff *= 2;
    }
    throw std::runtime_error("Could not contact server after 3 attempts");
  }(std::move(client), argv.at(0), argv.at(1));
}

void UseIdTokenGrpc(google::cloud::iam::IAMCredentialsClient client,
                    std::vector<std::string> const& argv) {
  namespace iam = ::google::cloud::iam;
  [](iam::IAMCredentialsClient client, std::string const& service_account,
     std::string const& url) {
    auto token = client.GenerateIdToken(
        "projects/-/serviceAccounts/" + service_account, /*delegates=*/{},
        /*audience=*/{url},
        /*include_email=*/true);
    if (!token) throw std::runtime_error(token.status().message());

    auto const prefix = std::string{"https://"};
    if (!absl::StartsWith(url, prefix)) {
      throw std::runtime_error("Invalid URL" + url);
    }
    auto endpoint = url.substr(prefix.length()) + ":443";
    auto credentials = grpc::CompositeChannelCredentials(
        grpc::SslCredentials(grpc::SslCredentialsOptions{}),
        grpc::AccessTokenCredentials(token->token()));
    auto channel = grpc::CreateChannel(endpoint, credentials);
    auto stub = google::cloud::examples::Greet::NewStub(channel);
    auto request = google::cloud::examples::HelloRequest{};
    auto backoff = std::chrono::milliseconds(250);
    for (int i = 0; i != 3; ++i) {
      grpc::ClientContext context;
      google::cloud::examples::HelloResponse response;
      auto status = stub->Hello(&context, request, &response);
      if (status.ok()) {
        std::cout << "Servers says: " << response.greeting() << "\n";
        return;
      }
      std::cout << "Server returned error=" << status.error_code()
                << ", message=" << status.error_message() << "\n";
      std::this_thread::sleep_for(backoff);
      backoff *= 2;
    }
    throw std::runtime_error("Could not contact server after 3 attempts");
  }(std::move(client), argv.at(0), argv.at(1));
}

void AutoRun(std::vector<std::string> const& argv) {
  namespace examples = ::google::cloud::testing_util;
  using ::google::cloud::internal::GetEnv;

  if (!argv.empty()) throw examples::Usage{"auto"};
  examples::CheckEnvironmentVariablesAreSet({
      "GOOGLE_CLOUD_PROJECT",
      "GOOGLE_CLOUD_CPP_IAM_TEST_SERVICE_ACCOUNT",
      "GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_SERVICE_ACCOUNT",
      "GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_HTTP_URL",
      "GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_GRPC_URL",
  });
  auto project_id = GetEnv("GOOGLE_CLOUD_PROJECT").value();
  auto const test_iam_service_account =
      GetEnv("GOOGLE_CLOUD_CPP_IAM_TEST_SERVICE_ACCOUNT").value_or("");
  auto const hello_world_service_account =
      GetEnv("GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_SERVICE_ACCOUNT").value_or("");
  auto const hello_world_http_url =
      GetEnv("GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_HTTP_URL").value_or("");
  auto const hello_world_grpc_url =
      GetEnv("GOOGLE_CLOUD_CPP_TEST_HELLO_WORLD_GRPC_URL").value_or("");

  auto client = google::cloud::iam::IAMCredentialsClient(
      google::cloud::iam::MakeIAMCredentialsConnection(
          google::cloud::Options{}
              .set<google::cloud::TracingComponentsOption>(
                  DefaultTracingComponents())
              .set<google::cloud::GrpcTracingOptionsOption>(
                  // There are some credentials returned by RPCs. On an error
                  // these are printed. This truncates them, making the output
                  // safe, and yet useful for debugging.
                  google::cloud::TracingOptions{}.SetOptions(
                      "truncate_string_field_longer_than=32"))));

  std::cout << "\nRunning UseAccessToken() example" << std::endl;
  UseAccessToken(client, {test_iam_service_account, project_id});

  std::cout << "\nRunning UseAccessTokenUntilExpired() example" << std::endl;
  UseAccessTokenUntilExpired(client, {test_iam_service_account, project_id});

  std::cout << "\nRunning UseIdTokenHttp() example" << std::endl;
  UseIdTokenHttp(client, {hello_world_service_account, hello_world_http_url});

  std::cout << "\nRunning UseIdTokenGrpc() example" << std::endl;
  UseIdTokenGrpc(client, {hello_world_service_account, hello_world_grpc_url});
}

}  // namespace

int main(int argc, char* argv[]) {  // NOLINT(bugprone-exception-escape)
  using ::google::cloud::testing_util::Example;

  using ClientCommand = std::function<void(
      google::cloud::iam::IAMCredentialsClient, std::vector<std::string> argv)>;

  auto make_entry = [](std::string name,
                       std::vector<std::string> const& arg_names,
                       ClientCommand const& command) {
    auto adapter = [=](std::vector<std::string> argv) {
      if ((argv.size() == 1 && argv[0] == "--help") ||
          argv.size() != arg_names.size()) {
        std::string usage = name;
        for (auto const& a : arg_names) usage += " <" + a + ">";
        throw google::cloud::testing_util::Usage{std::move(usage)};
      }
      auto client = google::cloud::iam::IAMCredentialsClient(
          google::cloud::iam::MakeIAMCredentialsConnection(
              google::cloud::Options{}
                  .set<google::cloud::TracingComponentsOption>(
                      DefaultTracingComponents())));
      command(client, std::move(argv));
    };
    return google::cloud::testing_util::Commands::value_type(std::move(name),
                                                             adapter);
  };

  Example example({
      make_entry("use-access-token", {"service-account", "project-id"},
                 UseAccessToken),
      make_entry("use-access-token-until-expired",
                 {"service-account", "project-id"}, UseAccessTokenUntilExpired),
      make_entry("use-id-token-http",
                 {"service-account", "hello-world-http-url"}, UseIdTokenHttp),
      make_entry("use-id-token-grpc",
                 {"service-account", "hello-world-http-url"}, UseIdTokenGrpc),
      {"auto", AutoRun},
  });
  return example.Run(argc, argv);
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <string>
#include <b5m-manager/image_server_client.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include <glog/logging.h>

#define MAX_STORAGE_COUNT 2
#define STAT_FILENAME_BY_STORAGE_IP  "stat_upload_by_storage"
#define STAT_FILENAME_BY_OVERALL "stat_upload_by_overall"
#define FILENAME_FILE_ID  "success_upload"
#define FILENAME_FAIL  "fail_upload"
#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
#define INT64_PRINTF_FORMAT   "%lld"

using namespace std;
namespace po = boost::program_options;
using namespace sf1r;

typedef struct {
    int total_count;
    int success_count;
    int64_t time_used;
} StorageStat;

const char* nsip = "172.16.0.168:8108";

static StorageStat storages[MAX_STORAGE_COUNT];
static int storage_count = 0;
static time_t start_time;
static int total_count = 0;
static int success_count = 0;
static FILE *fpSuccess = NULL;
static FILE *fpFail = NULL;

static int test_init();
static int save_stats_by_overall();
static int save_stats_by_storage_ip();
static int add_to_storage_stat(int storage_i, const int result, const int time_used);

bool read_file_data(const char* local_file, char* buf, size_t bufsize)
{
    int fd;
    if (NULL == local_file)
    {
        return false;
    }
    else if ((fd = ::open(local_file, O_RDONLY)) < 0)
    {
        printf("open local file %s fail: %s", local_file, strerror(errno));
        return false;
    }
    else
    {
        int64_t read_len = 0;
        while (true)
        {
            if ((read_len = ::read(fd, buf, bufsize)) < 0)
            {
                if (EAGAIN == errno)
                {
                    continue;
                }
                printf("read local file %s fail, error: %s", local_file, strerror(errno));
                ::close(fd);
                return false;
            }
            if (0 == read_len)
            {
                assert(bufsize == 0);
                break;
            }

            buf += read_len;
            bufsize -= read_len;
            if (bufsize == 0)
            {
                break;
            }
            assert(bufsize > 0);
        }
    }
    ::close(fd);
    return true;
}

bool write_dir(const std::string& dir)
{
    std::string file_id;
    int result = 0;
	struct timeval tv_start;
	struct timeval tv_end;
	int time_used;

    char dirpath[1024];
    strcpy(dirpath, dir.c_str());
    if(dirpath[strlen(dirpath)-1]=='/'){
    }else{
        strcat(dirpath,"/");
    }
    DIR *d;
    struct dirent *file;
    struct stat sb;
    if(!(d=opendir(dirpath))){
        return false;
    }
    std::string filepath;
    while((file=readdir(d))!=NULL){
        if(strncmp(file->d_name,".",1)==0){
            continue;
        }
        filepath = dirpath;
        filepath += file->d_name;
        if(stat(filepath.c_str(), &sb)>=0){
            if(!S_ISDIR(sb.st_mode)){

                if(filepath.find(".pic") == std::string::npos &&
                    filepath.find(".jpeg") == std::string::npos &&
                    filepath.find(".jpg") == std::string::npos &&
                    filepath.find(".png") == std::string::npos&&
                    filepath.find(".bmp") == std::string::npos )
                    continue;

                total_count++;

                gettimeofday(&tv_start, NULL);

                // read file content.
                char* filedata = new char[sb.st_size];
                if(!read_file_data(filepath.c_str(), filedata, sb.st_size))
                {
                    result = -1;
                }
                else
                {
                    result = ImageServerClient::UploadImageData(std::string(filedata, sb.st_size), file_id) ? 0:-1;
                }
                delete[] filedata;
                gettimeofday(&tv_end, NULL);
                time_used = TIME_SUB_MS(tv_end, tv_start);
                add_to_storage_stat(0, result, time_used);

                if (result == 0) //success
                {
                    success_count++;
                    fprintf(fpSuccess, "%d %s %zu %s %d\n",
                        (int)tv_end.tv_sec, filepath.c_str(), sb.st_size,
                        file_id.c_str(), time_used);
                }
                else //fail
                {
                    fprintf(fpFail, "%d %s %d\n", (int)tv_end.tv_sec,
                        filepath.c_str(), result);
                    fflush(fpFail);
                    fflush(fpSuccess);
                    if(total_count - success_count > 100)
                        exit(-1);
                }

                if (total_count % 100 == 0)
                {
                    if ((result=save_stats_by_overall()) != 0)
                    {
                        break;
                    }

                    if ((result=save_stats_by_storage_ip()) != 0)
                    {
                        break;
                    }
                    fflush(fpSuccess);
                }
            }
            else
            {
                write_dir(filepath);
            }
        }
    }
    closedir(d);
    return true;
}

void write_file(const std::string& image_path)
{
    int result = 0;

	if ((result=test_init()) != 0)
	{
		return;
	}

    if(image_path.empty())
    {
        std::cout << "empty local image path, no images will be uploaded." << std::endl;
        return;
    }
	memset(&storages, 0, sizeof(storages));
	start_time = time(NULL);
	result = 0;
	total_count = 0;
    success_count = 0;

    write_dir(image_path);

    save_stats_by_overall();
    save_stats_by_storage_ip();

    fclose(fpSuccess);
    fclose(fpFail);

    printf("time used: %ds\n", (int)(time(NULL) - start_time));
    return;

}

int main(int argc, char **argv)
{
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("imgserver-config", po::value<std::string>(), "image server config string(ip|port)")
        ("localimagepath", po::value<std::string>(), "specify the root path of local image that need to be uploaded.")
    ;
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);
    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 1;
    }

    boost::shared_ptr<RpcServerConnectionConfig> imgserver_config;
    if(vm.count("imgserver-config"))
    {
        std::string config_string = vm["imgserver-config"].as<std::string>();
        std::vector<std::string> vec;
        boost::algorithm::split( vec, config_string, boost::algorithm::is_any_of("|") );
        if(vec.size()==2)
        {
            std::string host = vec[0];
            uint32_t rpc_port = boost::lexical_cast<uint32_t>(vec[1]);
            imgserver_config.reset(new RpcServerConnectionConfig(host, rpc_port));
        }
        else
        {
            std::cout << "image server configure string invalid" << std::endl;
            return EXIT_FAILURE;
        }
    }

    if(!imgserver_config)
    {
        std::cout << "image server must be configured" << std::endl;
        return -1;
    }

    if(!ImageServerClient::Init(*(imgserver_config.get())))
    {
        LOG(ERROR) << "Image Server Client Init failed." << std::endl;
        return -1;
    }
    if(!ImageServerClient::Test())
    {
        LOG(ERROR) << "Image Server Client Test failed." << std::endl;
        return -1;
    }

    std::string local_image_path;
    if(vm.count("localimagepath"))
    {
        local_image_path = vm["localimagepath"].as<std::string>();
    }
    write_file(local_image_path);
    return 0;
}

static int save_stats_by_storage_ip()
{
	int k;
	char filename[256];
	FILE *fp;

	sprintf(filename, "%s", STAT_FILENAME_BY_STORAGE_IP);
	if ((fp=fopen(filename, "wb")) == NULL)
	{
		printf("open file %s fail \n",
			filename);
        perror("error:");
		return errno != 0 ? errno : EPERM;
	}

	fprintf(fp, "#ip_addr total_count success_count time_used(ms)\n");
	for (k=0; k<storage_count; k++)
	{
		fprintf(fp, "%d %d "INT64_PRINTF_FORMAT"\n", \
			storages[k].total_count, \
			storages[k].success_count, storages[k].time_used);
	}

	fclose(fp);
	return 0;
}

static int save_stats_by_overall()
{
	char filename[256];
	FILE *fp;

	sprintf(filename, "%s", STAT_FILENAME_BY_OVERALL);
	if ((fp=fopen(filename, "wb")) == NULL)
	{
		printf("open file %s fail\n",
			filename);
        perror("error:");
		return errno != 0 ? errno : EPERM;
	}

	fprintf(fp, "#total_count success_count  time_used(s)\n");
	fprintf(fp, "%d %d %d\n", total_count, success_count, (int)(time(NULL) - start_time));

	fclose(fp);
	return 0;
}

static int add_to_storage_stat(int storage_i, const int result, const int time_used)
{
	StorageStat *pStorage;
    pStorage = storages + storage_i;

    storage_count = storage_i + 1;

	pStorage->time_used += time_used;
	pStorage->total_count++;
	if (result == 0)
	{
		pStorage->success_count++;
	}

	return 0;
}

static int test_init()
{
	char filename[256];

	if (access("tfs_upload", 0) != 0 && mkdir("tfs_upload", 0755) != 0)
	{
	}

	if (chdir("tfs_upload") != 0)
	{
		printf("chdir fail\n");
        perror("err:");
		return errno != 0 ? errno : EPERM;
	}

	sprintf(filename, "%s", FILENAME_FILE_ID);
	if ((fpSuccess=fopen(filename, "wb")) == NULL)
	{
		printf("open file %s fail\n",
			filename);
        perror("err:");
		return errno != 0 ? errno : EPERM;
	}

	sprintf(filename, "%s", FILENAME_FAIL);
	if ((fpFail=fopen(filename, "wb")) == NULL)
	{
		printf("open file %s fail\n",
			filename);
        perror("err:");
		return errno != 0 ? errno : EPERM;
	}

	return 0;
}

<commit_msg>tiny adjust for the image upload test<commit_after>#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <string>
#include <b5m-manager/image_server_client.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include <glog/logging.h>

#define MAX_STORAGE_COUNT 2
#define STAT_FILENAME_BY_STORAGE_IP  "stat_upload_by_storage"
#define STAT_FILENAME_BY_OVERALL "stat_upload_by_overall"
#define FILENAME_FILE_ID  "success_upload"
#define FILENAME_FAIL  "fail_upload"
#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
#define INT64_PRINTF_FORMAT   "%lld"

using namespace std;
namespace po = boost::program_options;
using namespace sf1r;

typedef struct {
    int total_count;
    int success_count;
    int64_t time_used;
} StorageStat;

const char* nsip = "172.16.0.168:8108";

static StorageStat storages[MAX_STORAGE_COUNT];
static int storage_count = 0;
static time_t start_time;
static int total_count = 0;
static int success_count = 0;
static FILE *fpSuccess = NULL;
static FILE *fpFail = NULL;

static int test_init();
static int save_stats_by_overall();
static int save_stats_by_storage_ip();
static int add_to_storage_stat(int storage_i, const int result, const int time_used);

bool read_file_data(const char* local_file, char* buf, size_t bufsize)
{
    int fd;
    if (NULL == local_file)
    {
        return false;
    }
    else if ((fd = ::open(local_file, O_RDONLY)) < 0)
    {
        printf("open local file %s fail: %s", local_file, strerror(errno));
        return false;
    }
    else
    {
        int64_t read_len = 0;
        while (true)
        {
            if ((read_len = ::read(fd, buf, bufsize)) < 0)
            {
                if (EAGAIN == errno)
                {
                    continue;
                }
                printf("read local file %s fail, error: %s", local_file, strerror(errno));
                ::close(fd);
                return false;
            }
            if (0 == read_len)
            {
                assert(bufsize == 0);
                break;
            }

            buf += read_len;
            bufsize -= read_len;
            if (bufsize == 0)
            {
                break;
            }
            assert(bufsize > 0);
        }
    }
    ::close(fd);
    return true;
}

bool write_dir(const std::string& dir)
{
    std::string file_id;
    int result = 0;
	struct timeval tv_start;
	struct timeval tv_end;
	int time_used;

    char dirpath[1024];
    strcpy(dirpath, dir.c_str());
    if(dirpath[strlen(dirpath)-1]=='/'){
    }else{
        strcat(dirpath,"/");
    }
    DIR *d;
    struct dirent *file;
    struct stat sb;
    if(!(d=opendir(dirpath))){
        return false;
    }
    std::string filepath;
    while((file=readdir(d))!=NULL){
        if(strncmp(file->d_name,".",1)==0){
            continue;
        }
        filepath = dirpath;
        filepath += file->d_name;
        if(stat(filepath.c_str(), &sb)>=0){
            if(!S_ISDIR(sb.st_mode)){

                if(filepath.find(".pic") == std::string::npos &&
                    filepath.find(".jpeg") == std::string::npos &&
                    filepath.find(".jpg") == std::string::npos &&
                    filepath.find(".png") == std::string::npos&&
                    filepath.find(".bmp") == std::string::npos )
                    continue;

                if( sb.st_size == 0 )
                    continue;
                total_count++;

                gettimeofday(&tv_start, NULL);

                // read file content.
                char* filedata = new char[sb.st_size];
                if(!read_file_data(filepath.c_str(), filedata, sb.st_size))
                {
                    result = -1;
                }
                else
                {
                    try
                    {
                        result = ImageServerClient::UploadImageData(std::string(filedata, sb.st_size), file_id) ? 0:-1;
                    }
                    catch(std::exception& e)
                    {
                        cout << "upload caught exception." << endl;
                        cout << e.what() << endl;
                        gettimeofday(&tv_end, NULL);
                        cout << "time: " << TIME_SUB_MS(tv_end, tv_start) << endl;
                        continue;
                    }
                }
                delete[] filedata;
                gettimeofday(&tv_end, NULL);
                time_used = TIME_SUB_MS(tv_end, tv_start);
                add_to_storage_stat(0, result, time_used);

                if (result == 0) //success
                {
                    success_count++;
                    fprintf(fpSuccess, "%d %s %zu %s %d\n",
                        (int)tv_end.tv_sec, filepath.c_str(), sb.st_size,
                        file_id.c_str(), time_used);
                }
                else //fail
                {
                    fprintf(fpFail, "%d %s %d\n", (int)tv_end.tv_sec,
                        filepath.c_str(), result);
                    fflush(fpFail);
                    fflush(fpSuccess);
                    //if(total_count - success_count > 100)
                    //    exit(-1);
                }

                if (total_count % 100 == 0)
                {
                    if ((result=save_stats_by_overall()) != 0)
                    {
                        break;
                    }

                    if ((result=save_stats_by_storage_ip()) != 0)
                    {
                        break;
                    }
                    fflush(fpSuccess);
                }
            }
            else
            {
                write_dir(filepath);
            }
        }
    }
    closedir(d);
    return true;
}

void write_file(const std::string& image_path)
{
    int result = 0;

	if ((result=test_init()) != 0)
	{
		return;
	}

    if(image_path.empty())
    {
        std::cout << "empty local image path, no images will be uploaded." << std::endl;
        return;
    }
	memset(&storages, 0, sizeof(storages));
	start_time = time(NULL);
	result = 0;
	total_count = 0;
    success_count = 0;

    write_dir(image_path);

    save_stats_by_overall();
    save_stats_by_storage_ip();

    fclose(fpSuccess);
    fclose(fpFail);

    printf("time used: %ds\n", (int)(time(NULL) - start_time));
    return;

}

int main(int argc, char **argv)
{
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("imgserver-config", po::value<std::string>(), "image server config string(ip|port)")
        ("localimagepath", po::value<std::string>(), "specify the root path of local image that need to be uploaded.")
    ;
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);
    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 1;
    }

    boost::shared_ptr<RpcServerConnectionConfig> imgserver_config;
    if(vm.count("imgserver-config"))
    {
        std::string config_string = vm["imgserver-config"].as<std::string>();
        std::vector<std::string> vec;
        boost::algorithm::split( vec, config_string, boost::algorithm::is_any_of("|") );
        if(vec.size()==2)
        {
            std::string host = vec[0];
            uint32_t rpc_port = boost::lexical_cast<uint32_t>(vec[1]);
            imgserver_config.reset(new RpcServerConnectionConfig(host, rpc_port));
        }
        else
        {
            std::cout << "image server configure string invalid" << std::endl;
            return EXIT_FAILURE;
        }
    }

    if(!imgserver_config)
    {
        std::cout << "image server must be configured" << std::endl;
        return -1;
    }

    if(!ImageServerClient::Init(*(imgserver_config.get())))
    {
        LOG(ERROR) << "Image Server Client Init failed." << std::endl;
        return -1;
    }
    if(!ImageServerClient::Test())
    {
        LOG(ERROR) << "Image Server Client Test failed." << std::endl;
        return -1;
    }

    std::string local_image_path;
    if(vm.count("localimagepath"))
    {
        local_image_path = vm["localimagepath"].as<std::string>();
    }
    write_file(local_image_path);
    return 0;
}

static int save_stats_by_storage_ip()
{
	int k;
	char filename[256];
	FILE *fp;

	sprintf(filename, "%s", STAT_FILENAME_BY_STORAGE_IP);
	if ((fp=fopen(filename, "wb")) == NULL)
	{
		printf("open file %s fail \n",
			filename);
        perror("error:");
		return errno != 0 ? errno : EPERM;
	}

	fprintf(fp, "#ip_addr total_count success_count time_used(ms)\n");
	for (k=0; k<storage_count; k++)
	{
		fprintf(fp, "%d %d "INT64_PRINTF_FORMAT"\n", \
			storages[k].total_count, \
			storages[k].success_count, storages[k].time_used);
	}

	fclose(fp);
	return 0;
}

static int save_stats_by_overall()
{
	char filename[256];
	FILE *fp;

	sprintf(filename, "%s", STAT_FILENAME_BY_OVERALL);
	if ((fp=fopen(filename, "wb")) == NULL)
	{
		printf("open file %s fail\n",
			filename);
        perror("error:");
		return errno != 0 ? errno : EPERM;
	}

	fprintf(fp, "#total_count success_count  time_used(s)\n");
	fprintf(fp, "%d %d %d\n", total_count, success_count, (int)(time(NULL) - start_time));

	fclose(fp);
	return 0;
}

static int add_to_storage_stat(int storage_i, const int result, const int time_used)
{
	StorageStat *pStorage;
    pStorage = storages + storage_i;

    storage_count = storage_i + 1;

	pStorage->time_used += time_used;
	pStorage->total_count++;
	if (result == 0)
	{
		pStorage->success_count++;
	}

	return 0;
}

static int test_init()
{
	char filename[256];

	if (access("tfs_upload", 0) != 0 && mkdir("tfs_upload", 0755) != 0)
	{
	}

	if (chdir("tfs_upload") != 0)
	{
		printf("chdir fail\n");
        perror("err:");
		return errno != 0 ? errno : EPERM;
	}

	sprintf(filename, "%s", FILENAME_FILE_ID);
	if ((fpSuccess=fopen(filename, "wb")) == NULL)
	{
		printf("open file %s fail\n",
			filename);
        perror("err:");
		return errno != 0 ? errno : EPERM;
	}

	sprintf(filename, "%s", FILENAME_FAIL);
	if ((fpFail=fopen(filename, "wb")) == NULL)
	{
		printf("open file %s fail\n",
			filename);
        perror("err:");
		return errno != 0 ? errno : EPERM;
	}

	return 0;
}

<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// Qmitk related includes
#include "QmitkPropertyListViewItem.h"
#include "QmitkPropertyListViewItemFactory.h"
#include "QmitkMaterialEditor.h"

// mitk related includes
#include "mitkConfig.h"
#include "mitkRenderWindow.h"
#include "mitkPropertyList.h"
#include "mitkProperties.h"
#include "mitkColorProperty.h"
#include "mitkPropertyManager.h"
#include "mitkRenderingManager.h"
#include "mitkEnumerationProperty.h"
#include "mitkMaterialProperty.h"

// QT related includes
#include <qapplication.h>
#include <qcheckbox.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qpixmap.h>
#include <qcolordialog.h>
#include <qvalidator.h>
#include <qhbox.h>
#include <qslider.h>
#include <qcombobox.h>

#include "enabled.xpm"
#include "disabled.xpm"

QmitkPropertyListViewItem::QmitkPropertyListViewItem(std::string name, mitk::PropertyList* propertyList, QWidget* parent, bool createOnlyControl)
  : m_Name(name), m_PropertyList(propertyList), m_Label(NULL), m_Control(NULL)
{
}

void QmitkPropertyListViewItem::CreateEnabledButton(QWidget* parent)
{
  m_EnabledButton = new QPushButton(parent);
  connect(
      (QObject*)(m_EnabledButton),
      SIGNAL(clicked()),
      (QObject*)(this),
      SLOT(EnabledButtonClicked())
      );
  m_EnabledButton->show();
  UpdateEnabledView();
}

QmitkPropertyListViewItem* QmitkPropertyListViewItem::CreateInstance(mitk::PropertyList *propList, const std::string name, QWidget* parent, bool createOnlyControl)
{
  return QmitkPropertyListViewItemFactory::GetInstance()->CreateQmitkPropertyListViewItem(propList,name,parent,createOnlyControl);
}

void QmitkPropertyListViewItem::CheckBoxControlActivated(bool on)
{
  m_PropertyList->SetProperty(m_Name.c_str(), new mitk::BoolProperty(on));
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::StringControlActivated(const QString &text)
{
  m_PropertyList->SetProperty(m_Name.c_str(), new mitk::StringProperty(text.ascii()));
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::FloatControlActivated(const QString &text)
{
  if (((QLineEdit*)m_Control)->hasAcceptableInput())
  {
    m_Control->setPaletteForegroundColor(QApplication::palette().active().foreground());
    float value = text.toFloat();
    mitk::FloatProperty* floatProp = dynamic_cast<mitk::FloatProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
    if (value != floatProp->GetValue())
    {
      m_PropertyList->SetProperty(m_Name.c_str(), new mitk::FloatProperty(value));
    }
  }
  else
  {
    m_Control->setPaletteForegroundColor(Qt::red);
  }
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::IntControlActivated(const QString &text)
{
  if (((QLineEdit*)m_Control)->hasAcceptableInput())
  {
    m_Control->setPaletteForegroundColor(QApplication::palette().active().foreground());
    int value = text.toInt();
    mitk::IntProperty* intProp = dynamic_cast<mitk::IntProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
    if (value != intProp->GetValue())
    {
      m_PropertyList->SetProperty(m_Name.c_str(), new mitk::IntProperty(value));
    }
  }
  else
  {
    m_Control->setPaletteForegroundColor(Qt::red);
  }
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::ColorControlActivated()
{
  mitk::ColorProperty* colorProp = dynamic_cast<mitk::ColorProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
  mitk::Color col = colorProp->GetColor();
  QColor result = QColorDialog::getColor(QColor((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255), (int)(col.GetBlue() * 255)));
  if (result.isValid())
  {
    col.SetRed(result.red() / 255.0);
    col.SetGreen(result.green() / 255.0);
    col.SetBlue(result.blue() / 255.0);
    colorProp->SetColor(col);
    m_PropertyList->InvokeEvent(itk::ModifiedEvent());
    m_Control->setPaletteBackgroundColor(result);
    mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  }
}

void QmitkPropertyListViewItem::UpdateView()
{
  m_Control->blockSignals(true);
  mitk::BaseProperty* baseProp = m_PropertyList->GetProperty(m_Name.c_str());
  if (mitk::BoolProperty* boolProp = dynamic_cast<mitk::BoolProperty*>(baseProp))
  {
    if (QCheckBox* cb = dynamic_cast<QCheckBox*>(m_Control)) {
      cb ->setChecked(boolProp->GetValue());
    } else {
      //std::cout << "warning: non-checkbox control for bool property " << m_Name << std::endl;
    }
  }
  else if (mitk::StringProperty* stringProp = dynamic_cast<mitk::StringProperty*>(baseProp))
  {
    if (QLineEdit* qle = dynamic_cast<QLineEdit*>(m_Control)) {
      qle->setText(QString(stringProp->GetValue()));
    } else {
      //std::cout << "warning: non-lineedit control for string property " << m_Name << std::endl;
    }

  }
  else if (mitk::FloatProperty* floatProp = dynamic_cast<mitk::FloatProperty*>(baseProp))
  {
    QString text;
    text.setNum(floatProp->GetValue());
    ((QLineEdit*)(m_Control))->setText(text);
  }

  else if (mitk::ColorProperty* colorProp = dynamic_cast<mitk::ColorProperty*>(baseProp))
  {
    mitk::Color col = colorProp->GetColor();
    QColor qcol((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255),(int)( col.GetBlue() * 255));
    ((QPushButton*)(m_Control))->setPaletteBackgroundColor(qcol);
  }

  else if (mitk::EnumerationProperty* enumerationProp = dynamic_cast<mitk::EnumerationProperty*>(baseProp))
  {
    QComboBox* combo = ( ( QComboBox* ) m_Control );
    std::string enumerationValue = enumerationProp->GetValueAsString();
    for ( int item = 0 ; item < combo->count() ; ++item )
    {
      if ( enumerationValue == combo->text( item ).latin1() )
      {
        combo->setCurrentItem( item );
        break;
      }
    }
  }
  m_Control->blockSignals(false);
}

void QmitkPropertyListViewItem::UpdateEnabledView()
{
  static const QPixmap enabledPix((const char **)enabled_xpm);
  static const QPixmap disabledPix((const char **)disabled_xpm);
  if (m_PropertyList->IsEnabled(m_Name.c_str())) /* baseProp->GetEnabled()) */
  {
    m_EnabledButton->setPixmap(enabledPix);
    if (m_Control) {m_Control->setEnabled(true);}
    if (m_Label) {m_Label->setEnabled(true);}
  }
  else
  {
    m_EnabledButton->setPixmap(disabledPix);
    if (m_Control) {m_Control->setEnabled(false);}
    if (m_Label) {m_Label->setEnabled(false);}
  }
}

void QmitkPropertyListViewItem::EnabledButtonClicked()
{
  //baseProp->SetEnabled(! baseProp->GetEnabled());
  m_PropertyList->SetEnabled(m_Name.c_str(), ! m_PropertyList->IsEnabled(m_Name.c_str()));
  UpdateEnabledView();
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::ComboBoxItemActivated(const QString &item)
{
  mitk::EnumerationProperty* enumProp = dynamic_cast<mitk::EnumerationProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
  if ( enumProp != NULL )
  {
    std::string activatedItem( item.latin1() );
    if ( activatedItem != enumProp->GetValueAsString() )
    {
      if ( enumProp->IsValidEnumerationValue( activatedItem ) )
      {
        enumProp->SetValue( activatedItem );
        m_PropertyList->InvokeEvent( itk::ModifiedEvent() );
        mitk::RenderingManager::GetInstance()->RequestUpdateAll();
      }
    }
  }
}

void  QmitkPropertyListViewFloatSlider::SliderValueChanged(int value)
{
  m_PropertyList->SetProperty(m_Name.c_str(), new mitk::FloatProperty(value / 100.0f));
  UpdateView();
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewFloatSlider::UpdateView()
{
  m_Slider->blockSignals(true);
  mitk::FloatProperty* floatProp = dynamic_cast<mitk::FloatProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
  if (floatProp)
  {
    QString text;
    text.setNum(floatProp->GetValue(),'f',2);
    m_ValueLabel->setText(text);
    m_Slider->setValue((int)(floatProp->GetValue() * 100));
  }
  m_Slider->blockSignals(false);
}

void QmitkPropertyListViewItem::MaterialEditorActivated()
{
  if ( mitk::MaterialProperty* materialProperty = dynamic_cast<mitk::MaterialProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer()))
  {
    QmitkMaterialEditor* materialEditor = new QmitkMaterialEditor( NULL );
    materialEditor->Initialize( materialProperty );
    if ( materialEditor->exec() == QDialog::Accepted )
    {
      m_PropertyList->InvokeEvent(itk::ModifiedEvent());
      mitk::RenderingManager::GetInstance()->RequestUpdateAll();
    }
    delete materialEditor;
  }
}

<commit_msg>FIX: warnings<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// Qmitk related includes
#include "QmitkPropertyListViewItem.h"
#include "QmitkPropertyListViewItemFactory.h"
#include "QmitkMaterialEditor.h"

// mitk related includes
#include "mitkConfig.h"
#include "mitkRenderWindow.h"
#include "mitkPropertyList.h"
#include "mitkProperties.h"
#include "mitkColorProperty.h"
#include "mitkPropertyManager.h"
#include "mitkRenderingManager.h"
#include "mitkEnumerationProperty.h"
#include "mitkMaterialProperty.h"

// QT related includes
#include <qapplication.h>
#include <qcheckbox.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qpixmap.h>
#include <qcolordialog.h>
#include <qvalidator.h>
#include <qhbox.h>
#include <qslider.h>
#include <qcombobox.h>

#include "enabled.xpm"
#include "disabled.xpm"

QmitkPropertyListViewItem::QmitkPropertyListViewItem(std::string name, mitk::PropertyList* propertyList, QWidget* /*parent*/, bool /*createOnlyControl*/)
  : m_Name(name), m_PropertyList(propertyList), m_Label(NULL), m_Control(NULL)
{
}

void QmitkPropertyListViewItem::CreateEnabledButton(QWidget* parent)
{
  m_EnabledButton = new QPushButton(parent);
  connect(
      (QObject*)(m_EnabledButton),
      SIGNAL(clicked()),
      (QObject*)(this),
      SLOT(EnabledButtonClicked())
      );
  m_EnabledButton->show();
  UpdateEnabledView();
}

QmitkPropertyListViewItem* QmitkPropertyListViewItem::CreateInstance(mitk::PropertyList *propList, const std::string name, QWidget* parent, bool createOnlyControl)
{
  return QmitkPropertyListViewItemFactory::GetInstance()->CreateQmitkPropertyListViewItem(propList,name,parent,createOnlyControl);
}

void QmitkPropertyListViewItem::CheckBoxControlActivated(bool on)
{
  m_PropertyList->SetProperty(m_Name.c_str(), new mitk::BoolProperty(on));
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::StringControlActivated(const QString &text)
{
  m_PropertyList->SetProperty(m_Name.c_str(), new mitk::StringProperty(text.ascii()));
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::FloatControlActivated(const QString &text)
{
  if (((QLineEdit*)m_Control)->hasAcceptableInput())
  {
    m_Control->setPaletteForegroundColor(QApplication::palette().active().foreground());
    float value = text.toFloat();
    mitk::FloatProperty* floatProp = dynamic_cast<mitk::FloatProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
    if (value != floatProp->GetValue())
    {
      m_PropertyList->SetProperty(m_Name.c_str(), new mitk::FloatProperty(value));
    }
  }
  else
  {
    m_Control->setPaletteForegroundColor(Qt::red);
  }
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::IntControlActivated(const QString &text)
{
  if (((QLineEdit*)m_Control)->hasAcceptableInput())
  {
    m_Control->setPaletteForegroundColor(QApplication::palette().active().foreground());
    int value = text.toInt();
    mitk::IntProperty* intProp = dynamic_cast<mitk::IntProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
    if (value != intProp->GetValue())
    {
      m_PropertyList->SetProperty(m_Name.c_str(), new mitk::IntProperty(value));
    }
  }
  else
  {
    m_Control->setPaletteForegroundColor(Qt::red);
  }
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::ColorControlActivated()
{
  mitk::ColorProperty* colorProp = dynamic_cast<mitk::ColorProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
  mitk::Color col = colorProp->GetColor();
  QColor result = QColorDialog::getColor(QColor((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255), (int)(col.GetBlue() * 255)));
  if (result.isValid())
  {
    col.SetRed(result.red() / 255.0);
    col.SetGreen(result.green() / 255.0);
    col.SetBlue(result.blue() / 255.0);
    colorProp->SetColor(col);
    m_PropertyList->InvokeEvent(itk::ModifiedEvent());
    m_Control->setPaletteBackgroundColor(result);
    mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  }
}

void QmitkPropertyListViewItem::UpdateView()
{
  m_Control->blockSignals(true);
  mitk::BaseProperty* baseProp = m_PropertyList->GetProperty(m_Name.c_str());
  if (mitk::BoolProperty* boolProp = dynamic_cast<mitk::BoolProperty*>(baseProp))
  {
    if (QCheckBox* cb = dynamic_cast<QCheckBox*>(m_Control)) {
      cb ->setChecked(boolProp->GetValue());
    } else {
      //std::cout << "warning: non-checkbox control for bool property " << m_Name << std::endl;
    }
  }
  else if (mitk::StringProperty* stringProp = dynamic_cast<mitk::StringProperty*>(baseProp))
  {
    if (QLineEdit* qle = dynamic_cast<QLineEdit*>(m_Control)) {
      qle->setText(QString(stringProp->GetValue()));
    } else {
      //std::cout << "warning: non-lineedit control for string property " << m_Name << std::endl;
    }

  }
  else if (mitk::FloatProperty* floatProp = dynamic_cast<mitk::FloatProperty*>(baseProp))
  {
    QString text;
    text.setNum(floatProp->GetValue());
    ((QLineEdit*)(m_Control))->setText(text);
  }

  else if (mitk::ColorProperty* colorProp = dynamic_cast<mitk::ColorProperty*>(baseProp))
  {
    mitk::Color col = colorProp->GetColor();
    QColor qcol((int)(col.GetRed() * 255), (int)(col.GetGreen() * 255),(int)( col.GetBlue() * 255));
    ((QPushButton*)(m_Control))->setPaletteBackgroundColor(qcol);
  }

  else if (mitk::EnumerationProperty* enumerationProp = dynamic_cast<mitk::EnumerationProperty*>(baseProp))
  {
    QComboBox* combo = ( ( QComboBox* ) m_Control );
    std::string enumerationValue = enumerationProp->GetValueAsString();
    for ( int item = 0 ; item < combo->count() ; ++item )
    {
      if ( enumerationValue == combo->text( item ).latin1() )
      {
        combo->setCurrentItem( item );
        break;
      }
    }
  }
  m_Control->blockSignals(false);
}

void QmitkPropertyListViewItem::UpdateEnabledView()
{
  static const QPixmap enabledPix((const char **)enabled_xpm);
  static const QPixmap disabledPix((const char **)disabled_xpm);
  if (m_PropertyList->IsEnabled(m_Name.c_str())) /* baseProp->GetEnabled()) */
  {
    m_EnabledButton->setPixmap(enabledPix);
    if (m_Control) {m_Control->setEnabled(true);}
    if (m_Label) {m_Label->setEnabled(true);}
  }
  else
  {
    m_EnabledButton->setPixmap(disabledPix);
    if (m_Control) {m_Control->setEnabled(false);}
    if (m_Label) {m_Label->setEnabled(false);}
  }
}

void QmitkPropertyListViewItem::EnabledButtonClicked()
{
  //baseProp->SetEnabled(! baseProp->GetEnabled());
  m_PropertyList->SetEnabled(m_Name.c_str(), ! m_PropertyList->IsEnabled(m_Name.c_str()));
  UpdateEnabledView();
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewItem::ComboBoxItemActivated(const QString &item)
{
  mitk::EnumerationProperty* enumProp = dynamic_cast<mitk::EnumerationProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
  if ( enumProp != NULL )
  {
    std::string activatedItem( item.latin1() );
    if ( activatedItem != enumProp->GetValueAsString() )
    {
      if ( enumProp->IsValidEnumerationValue( activatedItem ) )
      {
        enumProp->SetValue( activatedItem );
        m_PropertyList->InvokeEvent( itk::ModifiedEvent() );
        mitk::RenderingManager::GetInstance()->RequestUpdateAll();
      }
    }
  }
}

void  QmitkPropertyListViewFloatSlider::SliderValueChanged(int value)
{
  m_PropertyList->SetProperty(m_Name.c_str(), new mitk::FloatProperty(value / 100.0f));
  UpdateView();
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkPropertyListViewFloatSlider::UpdateView()
{
  m_Slider->blockSignals(true);
  mitk::FloatProperty* floatProp = dynamic_cast<mitk::FloatProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer());
  if (floatProp)
  {
    QString text;
    text.setNum(floatProp->GetValue(),'f',2);
    m_ValueLabel->setText(text);
    m_Slider->setValue((int)(floatProp->GetValue() * 100));
  }
  m_Slider->blockSignals(false);
}

void QmitkPropertyListViewItem::MaterialEditorActivated()
{
  if ( mitk::MaterialProperty* materialProperty = dynamic_cast<mitk::MaterialProperty*>(m_PropertyList->GetProperty(m_Name.c_str()).GetPointer()))
  {
    QmitkMaterialEditor* materialEditor = new QmitkMaterialEditor( NULL );
    materialEditor->Initialize( materialProperty );
    if ( materialEditor->exec() == QDialog::Accepted )
    {
      m_PropertyList->InvokeEvent(itk::ModifiedEvent());
      mitk::RenderingManager::GetInstance()->RequestUpdateAll();
    }
    delete materialEditor;
  }
}

<|endoftext|>


<commit_before>/* Copyright 2007-2015 QReal Research Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

#include "trikPythonGeneratorLibrary/trikPythonGeneratorPluginBase.h"

#include <QtWidgets/QApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QStateMachine>
#include <QtCore/QState>
#include <QtCore/QFinalState>

#include <qrkernel/logging.h>
#include <trikGeneratorBase/trikGeneratorPluginBase.h>
#include <trikGeneratorBase/robotModel/generatorModelExtensionInterface.h>
#include <trikKit/robotModel/trikRobotModelBase.h>
#include <utils/robotCommunication/tcpRobotCommunicator.h>
#include <utils/robotCommunication/runProgramProtocol.h>
#include <utils/robotCommunication/stopRobotProtocol.h>
#include <utils/robotCommunication/uploadProgramProtocol.h>
#include <utils/robotCommunication/networkCommunicationErrorReporter.h>

#include "trikPythonMasterGenerator.h"
#include "emptyShell.h"

using namespace trik::python;
using namespace kitBase::robotModel;
using namespace qReal;
using namespace utils::robotCommunication;

TrikPythonGeneratorPluginBase::TrikPythonGeneratorPluginBase(
		trik::robotModel::TrikRobotModelBase * const robotModel
		, kitBase::blocksBase::BlocksFactoryInterface * const blocksFactory
		, const QStringList &pathsToTemplates)
	: TrikGeneratorPluginBase(robotModel, blocksFactory)
	, mGenerateCodeAction(new QAction(nullptr))
	, mUploadProgramAction(new QAction(nullptr))
	, mRunProgramAction(new QAction(nullptr))
	, mStopRobotAction(new QAction(nullptr))
	, mRobotModel(*robotModel)
	, mPathsToTemplates(pathsToTemplates)
{
}

TrikPythonGeneratorPluginBase::~TrikPythonGeneratorPluginBase()
{
}

void TrikPythonGeneratorPluginBase::init(const kitBase::KitPluginConfigurator &configurer)
{
	const auto errorReporter = configurer.qRealConfigurator().mainWindowInterpretersInterface().errorReporter();
	RobotsGeneratorPluginBase::init(configurer);
	mCommunicator.reset(new TcpRobotCommunicator("TrikTcpServer"));
	NetworkCommunicationErrorReporter::connectErrorReporter(*mCommunicator, *errorReporter);

	mUploadProgramProtocol.reset(new UploadProgramProtocol(*mCommunicator));
	mStopRobotProtocol.reset(new StopRobotProtocol(*mCommunicator));

	const auto timeout = [this, errorReporter]() {
		errorReporter->addError(tr("Network operation timed out"));
		onProtocolFinished();
	};

	connect(mUploadProgramProtocol.data(), &UploadProgramProtocol::timeout, timeout);
	connect(mStopRobotProtocol.data(), &StopRobotProtocol::timeout, timeout);

	connect(mUploadProgramProtocol.data(), &UploadProgramProtocol::error
			, this, &TrikPythonGeneratorPluginBase::onProtocolFinished);
	connect(mStopRobotProtocol.data(), &StopRobotProtocol::error
			, this, &TrikPythonGeneratorPluginBase::onProtocolFinished);

	connect(mUploadProgramProtocol.data(), &UploadProgramProtocol::success
			, this, &TrikPythonGeneratorPluginBase::onProtocolFinished);
	connect(mStopRobotProtocol.data(), &StopRobotProtocol::success
			, this, &TrikPythonGeneratorPluginBase::onProtocolFinished);
}

QList<ActionInfo> TrikPythonGeneratorPluginBase::customActions()
{
	mGenerateCodeAction->setObjectName("generatePythonTrikCode");
	mGenerateCodeAction->setText(tr("Generate python code"));
	mGenerateCodeAction->setIcon(QIcon(":/trik/python/images/generatePythonCode.svg"));
	ActionInfo generateCodeActionInfo(mGenerateCodeAction, "generators", "tools");
	connect(mGenerateCodeAction, SIGNAL(triggered()), this, SLOT(generateCode()), Qt::UniqueConnection);

	mUploadProgramAction->setObjectName("uploadPythonTrikProgram");
	mUploadProgramAction->setText(tr("Upload program"));
	mUploadProgramAction->setIcon(QIcon(":/trik/python/images/uploadProgram.svg"));
	ActionInfo uploadProgramActionInfo(mUploadProgramAction, "generators", "tools");
	connect(mUploadProgramAction, SIGNAL(triggered()), this, SLOT(uploadProgram()), Qt::UniqueConnection);

	mRunProgramAction->setObjectName("runPythonTrikProgram");
	mRunProgramAction->setText(tr("Run program"));
	mRunProgramAction->setIcon(QIcon(":/trik/python/images/run.png"));
	ActionInfo runProgramActionInfo(mRunProgramAction, "interpreters", "tools");
	connect(mRunProgramAction, SIGNAL(triggered()), this, SLOT(runProgram()), Qt::UniqueConnection);

	mStopRobotAction->setObjectName("stopPythonTrikRobot");
	mStopRobotAction->setText(tr("Stop robot"));
	mStopRobotAction->setIcon(QIcon(":/trik/python/images/stop.png"));
	ActionInfo stopRobotActionInfo(mStopRobotAction, "interpreters", "tools");
	connect(mStopRobotAction, SIGNAL(triggered()), this, SLOT(stopRobot()), Qt::UniqueConnection);

	return {generateCodeActionInfo, uploadProgramActionInfo, runProgramActionInfo, stopRobotActionInfo};
}

QList<HotKeyActionInfo> TrikPythonGeneratorPluginBase::hotKeyActions()
{
	mGenerateCodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_G));
	mUploadProgramAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
	mRunProgramAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F5));
	mStopRobotAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_F5));

	HotKeyActionInfo generateCodeInfo("Generator.GenerateTrik", tr("Generate Python code"), mGenerateCodeAction);
	HotKeyActionInfo uploadProgramInfo("Generator.UploadTrik", tr("Upload Python program"), mUploadProgramAction);
	HotKeyActionInfo runProgramInfo("Generator.RunTrik", tr("Run Python program"), mRunProgramAction);
	HotKeyActionInfo stopRobotInfo("Generator.StopTrik", tr("Stop Python program"), mStopRobotAction);

	return {generateCodeInfo, uploadProgramInfo, runProgramInfo, stopRobotInfo};
}

QIcon TrikPythonGeneratorPluginBase::iconForFastSelector(const RobotModelInterface &robotModel) const
{
	Q_UNUSED(robotModel)

	return QIcon(":/trik/python/images/switch-to-trik-python.svg");
}

generatorBase::MasterGeneratorBase *TrikPythonGeneratorPluginBase::masterGenerator()
{
	return new TrikPythonMasterGenerator(*mRepo
			, *mMainWindowInterface->errorReporter()
			, *mParserErrorReporter
			, *mRobotModelManager
			, *mTextLanguage
			, mMainWindowInterface->activeDiagram()
			, mPathsToTemplates);
}

QString TrikPythonGeneratorPluginBase::defaultFilePath(const QString &projectName) const
{
	return QString("trik/%1/%1.py").arg(projectName);
}

text::LanguageInfo TrikPythonGeneratorPluginBase::language() const
{
	return qReal::text::Languages::python({"brick"});
}

QString TrikPythonGeneratorPluginBase::generatorName() const
{
	return "trikPython";
}

void TrikPythonGeneratorPluginBase::addShellDevice(robotModel::GeneratorModelExtensionInterface &robotModel) const
{
	const PortInfo shellPort("ShellPort", output);
	EmptyShell * const shell = new EmptyShell(DeviceInfo::create<trik::robotModel::parts::TrikShell>(), shellPort);
	connect(mCommunicator.data(), &TcpRobotCommunicator::printText, shell, &EmptyShell::print);
	robotModel.addDevice(shellPort, shell);
}

void TrikPythonGeneratorPluginBase::uploadProgram()
{
	const QFileInfo fileInfo = generateCodeForProcessing();

	if (fileInfo != QFileInfo() && !fileInfo.absoluteFilePath().isEmpty()) {
		disableButtons();
		mUploadProgramProtocol->run(fileInfo);
	} else {
		QLOG_ERROR() << "Code generation failed, aborting";
	}
}

void TrikPythonGeneratorPluginBase::runProgram()
{
	const QFileInfo fileInfo = generateCodeForProcessing();
	if (fileInfo != QFileInfo() && !fileInfo.absoluteFilePath().isEmpty()) {
		disableButtons();
		connect(mUploadProgramProtocol.data(), &UploadProgramProtocol::success, this ,[=]() {
			const QString directCommand =
					"script.system(\"mv /home/root/trik/scripts/%1 /home/root/; "
					"python '`/home/root/%1'\")";
			mCommunicator->runDirectCommand(directCommand.arg(fileInfo.fileName()), false);
		});
		mUploadProgramProtocol->run(fileInfo);
	} else {
		QLOG_ERROR() << "Code generation failed, aborting";
	}
}

void TrikPythonGeneratorPluginBase::stopRobot()
{
	if (mStopRobotProtocol) {
		disableButtons();
		mStopRobotProtocol->run(
				"script.system(\"killall python\"); \n"
				"script.system(\"killall aplay\"); \n"
				"script.system(\"killall vlc\");"
				);
	} else {
		QLOG_ERROR() << "Stop robot protocol is not initialized";
	}
}

void TrikPythonGeneratorPluginBase::onProtocolFinished()
{
	mUploadProgramAction->setEnabled(true);
	mRunProgramAction->setEnabled(true);
	mStopRobotAction->setEnabled(true);
}

void TrikPythonGeneratorPluginBase::disableButtons()
{
	mUploadProgramAction->setEnabled(false);
	mRunProgramAction->setEnabled(false);
	mStopRobotAction->setEnabled(false);
}
<commit_msg>Removed excess tick in python plugin base<commit_after>/* Copyright 2007-2015 QReal Research Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. */

#include "trikPythonGeneratorLibrary/trikPythonGeneratorPluginBase.h"

#include <QtWidgets/QApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QStateMachine>
#include <QtCore/QState>
#include <QtCore/QFinalState>

#include <qrkernel/logging.h>
#include <trikGeneratorBase/trikGeneratorPluginBase.h>
#include <trikGeneratorBase/robotModel/generatorModelExtensionInterface.h>
#include <trikKit/robotModel/trikRobotModelBase.h>
#include <utils/robotCommunication/tcpRobotCommunicator.h>
#include <utils/robotCommunication/runProgramProtocol.h>
#include <utils/robotCommunication/stopRobotProtocol.h>
#include <utils/robotCommunication/uploadProgramProtocol.h>
#include <utils/robotCommunication/networkCommunicationErrorReporter.h>

#include "trikPythonMasterGenerator.h"
#include "emptyShell.h"

using namespace trik::python;
using namespace kitBase::robotModel;
using namespace qReal;
using namespace utils::robotCommunication;

TrikPythonGeneratorPluginBase::TrikPythonGeneratorPluginBase(
		trik::robotModel::TrikRobotModelBase * const robotModel
		, kitBase::blocksBase::BlocksFactoryInterface * const blocksFactory
		, const QStringList &pathsToTemplates)
	: TrikGeneratorPluginBase(robotModel, blocksFactory)
	, mGenerateCodeAction(new QAction(nullptr))
	, mUploadProgramAction(new QAction(nullptr))
	, mRunProgramAction(new QAction(nullptr))
	, mStopRobotAction(new QAction(nullptr))
	, mRobotModel(*robotModel)
	, mPathsToTemplates(pathsToTemplates)
{
}

TrikPythonGeneratorPluginBase::~TrikPythonGeneratorPluginBase()
{
}

void TrikPythonGeneratorPluginBase::init(const kitBase::KitPluginConfigurator &configurer)
{
	const auto errorReporter = configurer.qRealConfigurator().mainWindowInterpretersInterface().errorReporter();
	RobotsGeneratorPluginBase::init(configurer);
	mCommunicator.reset(new TcpRobotCommunicator("TrikTcpServer"));
	NetworkCommunicationErrorReporter::connectErrorReporter(*mCommunicator, *errorReporter);

	mUploadProgramProtocol.reset(new UploadProgramProtocol(*mCommunicator));
	mStopRobotProtocol.reset(new StopRobotProtocol(*mCommunicator));

	const auto timeout = [this, errorReporter]() {
		errorReporter->addError(tr("Network operation timed out"));
		onProtocolFinished();
	};

	connect(mUploadProgramProtocol.data(), &UploadProgramProtocol::timeout, timeout);
	connect(mStopRobotProtocol.data(), &StopRobotProtocol::timeout, timeout);

	connect(mUploadProgramProtocol.data(), &UploadProgramProtocol::error
			, this, &TrikPythonGeneratorPluginBase::onProtocolFinished);
	connect(mStopRobotProtocol.data(), &StopRobotProtocol::error
			, this, &TrikPythonGeneratorPluginBase::onProtocolFinished);

	connect(mUploadProgramProtocol.data(), &UploadProgramProtocol::success
			, this, &TrikPythonGeneratorPluginBase::onProtocolFinished);
	connect(mStopRobotProtocol.data(), &StopRobotProtocol::success
			, this, &TrikPythonGeneratorPluginBase::onProtocolFinished);
}

QList<ActionInfo> TrikPythonGeneratorPluginBase::customActions()
{
	mGenerateCodeAction->setObjectName("generatePythonTrikCode");
	mGenerateCodeAction->setText(tr("Generate python code"));
	mGenerateCodeAction->setIcon(QIcon(":/trik/python/images/generatePythonCode.svg"));
	ActionInfo generateCodeActionInfo(mGenerateCodeAction, "generators", "tools");
	connect(mGenerateCodeAction, SIGNAL(triggered()), this, SLOT(generateCode()), Qt::UniqueConnection);

	mUploadProgramAction->setObjectName("uploadPythonTrikProgram");
	mUploadProgramAction->setText(tr("Upload program"));
	mUploadProgramAction->setIcon(QIcon(":/trik/python/images/uploadProgram.svg"));
	ActionInfo uploadProgramActionInfo(mUploadProgramAction, "generators", "tools");
	connect(mUploadProgramAction, SIGNAL(triggered()), this, SLOT(uploadProgram()), Qt::UniqueConnection);

	mRunProgramAction->setObjectName("runPythonTrikProgram");
	mRunProgramAction->setText(tr("Run program"));
	mRunProgramAction->setIcon(QIcon(":/trik/python/images/run.png"));
	ActionInfo runProgramActionInfo(mRunProgramAction, "interpreters", "tools");
	connect(mRunProgramAction, SIGNAL(triggered()), this, SLOT(runProgram()), Qt::UniqueConnection);

	mStopRobotAction->setObjectName("stopPythonTrikRobot");
	mStopRobotAction->setText(tr("Stop robot"));
	mStopRobotAction->setIcon(QIcon(":/trik/python/images/stop.png"));
	ActionInfo stopRobotActionInfo(mStopRobotAction, "interpreters", "tools");
	connect(mStopRobotAction, SIGNAL(triggered()), this, SLOT(stopRobot()), Qt::UniqueConnection);

	return {generateCodeActionInfo, uploadProgramActionInfo, runProgramActionInfo, stopRobotActionInfo};
}

QList<HotKeyActionInfo> TrikPythonGeneratorPluginBase::hotKeyActions()
{
	mGenerateCodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_G));
	mUploadProgramAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
	mRunProgramAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F5));
	mStopRobotAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_F5));

	HotKeyActionInfo generateCodeInfo("Generator.GenerateTrik", tr("Generate Python code"), mGenerateCodeAction);
	HotKeyActionInfo uploadProgramInfo("Generator.UploadTrik", tr("Upload Python program"), mUploadProgramAction);
	HotKeyActionInfo runProgramInfo("Generator.RunTrik", tr("Run Python program"), mRunProgramAction);
	HotKeyActionInfo stopRobotInfo("Generator.StopTrik", tr("Stop Python program"), mStopRobotAction);

	return {generateCodeInfo, uploadProgramInfo, runProgramInfo, stopRobotInfo};
}

QIcon TrikPythonGeneratorPluginBase::iconForFastSelector(const RobotModelInterface &robotModel) const
{
	Q_UNUSED(robotModel)

	return QIcon(":/trik/python/images/switch-to-trik-python.svg");
}

generatorBase::MasterGeneratorBase *TrikPythonGeneratorPluginBase::masterGenerator()
{
	return new TrikPythonMasterGenerator(*mRepo
			, *mMainWindowInterface->errorReporter()
			, *mParserErrorReporter
			, *mRobotModelManager
			, *mTextLanguage
			, mMainWindowInterface->activeDiagram()
			, mPathsToTemplates);
}

QString TrikPythonGeneratorPluginBase::defaultFilePath(const QString &projectName) const
{
	return QString("trik/%1/%1.py").arg(projectName);
}

text::LanguageInfo TrikPythonGeneratorPluginBase::language() const
{
	return qReal::text::Languages::python({"brick"});
}

QString TrikPythonGeneratorPluginBase::generatorName() const
{
	return "trikPython";
}

void TrikPythonGeneratorPluginBase::addShellDevice(robotModel::GeneratorModelExtensionInterface &robotModel) const
{
	const PortInfo shellPort("ShellPort", output);
	EmptyShell * const shell = new EmptyShell(DeviceInfo::create<trik::robotModel::parts::TrikShell>(), shellPort);
	connect(mCommunicator.data(), &TcpRobotCommunicator::printText, shell, &EmptyShell::print);
	robotModel.addDevice(shellPort, shell);
}

void TrikPythonGeneratorPluginBase::uploadProgram()
{
	const QFileInfo fileInfo = generateCodeForProcessing();

	if (fileInfo != QFileInfo() && !fileInfo.absoluteFilePath().isEmpty()) {
		disableButtons();
		mUploadProgramProtocol->run(fileInfo);
	} else {
		QLOG_ERROR() << "Code generation failed, aborting";
	}
}

void TrikPythonGeneratorPluginBase::runProgram()
{
	const QFileInfo fileInfo = generateCodeForProcessing();
	if (fileInfo != QFileInfo() && !fileInfo.absoluteFilePath().isEmpty()) {
		disableButtons();
		connect(mUploadProgramProtocol.data(), &UploadProgramProtocol::success, this ,[=]() {
			const QString directCommand =
					"script.system(\"mv /home/root/trik/scripts/%1 /home/root/; "
					"python '/home/root/%1'\")";
			mCommunicator->runDirectCommand(directCommand.arg(fileInfo.fileName()), false);
		});
		mUploadProgramProtocol->run(fileInfo);
	} else {
		QLOG_ERROR() << "Code generation failed, aborting";
	}
}

void TrikPythonGeneratorPluginBase::stopRobot()
{
	if (mStopRobotProtocol) {
		disableButtons();
		mStopRobotProtocol->run(
				"script.system(\"killall python\"); \n"
				"script.system(\"killall aplay\"); \n"
				"script.system(\"killall vlc\");"
				);
	} else {
		QLOG_ERROR() << "Stop robot protocol is not initialized";
	}
}

void TrikPythonGeneratorPluginBase::onProtocolFinished()
{
	mUploadProgramAction->setEnabled(true);
	mRunProgramAction->setEnabled(true);
	mStopRobotAction->setEnabled(true);
}

void TrikPythonGeneratorPluginBase::disableButtons()
{
	mUploadProgramAction->setEnabled(false);
	mRunProgramAction->setEnabled(false);
	mStopRobotAction->setEnabled(false);
}
<|endoftext|>