<commit_before>// Copyright 2019 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
//
//     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 "google/cloud/spanner/internal/background_threads_impl.h"
#include <gmock/gmock.h>

namespace google {
namespace cloud {
namespace spanner {
inline namespace SPANNER_CLIENT_NS {
namespace internal {
namespace {

/// @test Verify we can create and use a CustomerSuppliedBackgroundThreads
/// without impacting the completion queue
TEST(CustomerSuppliedBackgroundThreads, LifecycleNoShutdown) {
  grpc_utils::CompletionQueue cq;
  promise<void> p;
  std::thread t([&cq, &p] {
    cq.Run();
    p.set_value();
  });

  { CustomerSuppliedBackgroundThreads actual(cq); }

  using ms = std::chrono::milliseconds;

  auto has_shutdown = p.get_future();
  EXPECT_NE(std::future_status::ready, has_shutdown.wait_for(ms(2)));

  auto expired = cq.MakeRelativeTimer(ms(0));
  EXPECT_EQ(std::future_status::ready, expired.wait_for(ms(100)));

  cq.Shutdown();
  EXPECT_EQ(std::future_status::ready, has_shutdown.wait_for(ms(100)));

  t.join();
}

/// @test Verify that users can supply their own queue and threads.
TEST(CustomerSuppliedBackgroundThreads, SharesCompletionQueue) {
  grpc_utils::CompletionQueue cq;

  CustomerSuppliedBackgroundThreads actual(cq);

  // Verify the completion queue is shared, scheduling work in actual.cq() works
  // if our thread is blocked in cq.Run().
  std::thread t([&cq] { cq.Run(); });
  using ms = std::chrono::milliseconds;
  future<std::thread::id> id = actual.cq().MakeRelativeTimer(ms(0)).then(
      [](future<std::chrono::system_clock::time_point>) {
        return std::this_thread::get_id();
      });
  EXPECT_EQ(std::future_status::ready, id.wait_for(ms(100)));
  EXPECT_EQ(t.get_id(), id.get());

  cq.Shutdown();
  t.join();
}

/// @test Verify that automatically created completion queues are usable.
TEST(AutomaticallyCreatedBackgroundThreads, IsActive) {
  AutomaticallyCreatedBackgroundThreads actual;

  using ms = std::chrono::milliseconds;

  auto expired = actual.cq().MakeRelativeTimer(ms(0));
  EXPECT_EQ(std::future_status::ready, expired.wait_for(ms(100)));
}

}  // namespace
}  // namespace internal
}  // namespace SPANNER_CLIENT_NS
}  // namespace spanner
}  // namespace cloud
}  // namespace google
<commit_msg>bug: remove another flaky test (#1087)<commit_after>// Copyright 2019 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
//
//     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 "google/cloud/spanner/internal/background_threads_impl.h"
#include <gmock/gmock.h>

namespace google {
namespace cloud {
namespace spanner {
inline namespace SPANNER_CLIENT_NS {
namespace internal {
namespace {

/// @test Verify we can create and use a CustomerSuppliedBackgroundThreads
/// without impacting the completion queue
TEST(CustomerSuppliedBackgroundThreads, LifecycleNoShutdown) {
  grpc_utils::CompletionQueue cq;
  promise<void> p;
  std::thread t([&cq, &p] {
    cq.Run();
    p.set_value();
  });

  { CustomerSuppliedBackgroundThreads actual(cq); }

  using ms = std::chrono::milliseconds;

  auto has_shutdown = p.get_future();
  EXPECT_NE(std::future_status::ready, has_shutdown.wait_for(ms(2)));

  auto expired = cq.MakeRelativeTimer(ms(0));
  EXPECT_EQ(std::future_status::ready, expired.wait_for(ms(100)));

  cq.Shutdown();
  EXPECT_EQ(std::future_status::ready, has_shutdown.wait_for(ms(100)));

  t.join();
}

/// @test Verify that users can supply their own queue and threads.
TEST(CustomerSuppliedBackgroundThreads, SharesCompletionQueue) {
  grpc_utils::CompletionQueue cq;

  CustomerSuppliedBackgroundThreads actual(cq);

  using ms = std::chrono::milliseconds;
  // Verify the completion queue is shared. Scheduling work in actual.cq() works
  // once a thread is blocked in cq.Run(). Start that thread after scheduling
  // the work to avoid flaky failures where the timer expires immediately.
  future<std::thread::id> id = actual.cq().MakeRelativeTimer(ms(1)).then(
      [](future<std::chrono::system_clock::time_point>) {
        return std::this_thread::get_id();
      });
  std::thread t([&cq] { cq.Run(); });
  EXPECT_EQ(std::future_status::ready, id.wait_for(ms(100)));
  EXPECT_EQ(t.get_id(), id.get());

  cq.Shutdown();
  t.join();
}

/// @test Verify that automatically created completion queues are usable.
TEST(AutomaticallyCreatedBackgroundThreads, IsActive) {
  AutomaticallyCreatedBackgroundThreads actual;

  using ms = std::chrono::milliseconds;

  auto expired = actual.cq().MakeRelativeTimer(ms(0));
  EXPECT_EQ(std::future_status::ready, expired.wait_for(ms(100)));
}

}  // namespace
}  // namespace internal
}  // namespace SPANNER_CLIENT_NS
}  // namespace spanner
}  // namespace cloud
}  // namespace google
<|endoftext|>


<commit_before>/*
 * nghttp2 - HTTP/2 C Library
 *
 * Copyright (c) 2013 Tatsuhiro Tsujikawa
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "http2_test.h"

#include <cassert>
#include <cstring>
#include <iostream>

#include <CUnit/CUnit.h>

#include "http-parser/http_parser.h"

#include "http2.h"
#include "util.h"

using namespace nghttp2;

#define MAKE_NV(K, V) {(uint8_t*)K, (uint8_t*)V,        \
      sizeof(K) - 1, sizeof(V) - 1,                     \
      NGHTTP2_NV_FLAG_NONE}

namespace shrpx {

namespace {
void check_nv(const Header& a, const nghttp2_nv *b)
{
  CU_ASSERT(a.name.size() == b->namelen);
  CU_ASSERT(a.value.size() == b->valuelen);
  CU_ASSERT(memcmp(a.name.c_str(), b->name, b->namelen) == 0);
  CU_ASSERT(memcmp(a.value.c_str(), b->value, b->valuelen) == 0);
}
} // namespace

void test_http2_sort_nva(void)
{
  // Last 0 is stripped in MAKE_NV
  const uint8_t concatval[] = { '4', 0x00, 0x00, '6', 0x00, '5', 0x00 };
  nghttp2_nv nv[] = {MAKE_NV("alpha", "1"),
                     MAKE_NV("charlie", "3"),
                     MAKE_NV("bravo", "2"),
                     MAKE_NV("delta", concatval)};
  auto nvlen = sizeof(nv)/sizeof(nv[0]);
  auto nva = http2::sort_nva(nv, nvlen);
  CU_ASSERT(6 == nva.size());
  check_nv({"alpha", "1"}, &nva[0]);
  check_nv({"bravo", "2"}, &nva[1]);
  check_nv({"charlie", "3"}, &nva[2]);
  check_nv({"delta", "4"}, &nva[3]);
  check_nv({"delta", "6"}, &nva[4]);
  check_nv({"delta", "5"}, &nva[5]);
}

void test_http2_add_header(void)
{
  auto nva = Headers();

  http2::add_header(nva, (const uint8_t*)"alpha", 5,
                    (const uint8_t*)"123", 3, false);
  CU_ASSERT(Headers::value_type("alpha", "123") == nva[0]);
  CU_ASSERT(!nva[0].no_index);

  nva.clear();

  http2::add_header(nva, (const uint8_t*)"alpha", 5,
                    (const uint8_t*)"", 0, true);
  CU_ASSERT(Headers::value_type("alpha", "") == nva[0]);
  CU_ASSERT(nva[0].no_index);
}

void test_http2_check_http2_headers(void)
{
  auto nva1 = Headers{
    { "alpha", "1" },
    { "bravo", "2" },
    { "upgrade", "http2" }
  };
  CU_ASSERT(!http2::check_http2_headers(nva1));

  auto nva2 = Headers{
    { "connection", "1" },
    { "delta", "2" },
    { "echo", "3" }
  };
  CU_ASSERT(!http2::check_http2_headers(nva2));

  auto nva3 = Headers{
    { "alpha", "1" },
    { "bravo", "2" },
    { "te2", "3" }
  };
  CU_ASSERT(http2::check_http2_headers(nva3));
}

void test_http2_get_unique_header(void)
{
  auto nva = Headers{
    { "alpha", "1" },
    { "bravo", "2" },
    { "bravo", "3" },
    { "charlie", "4" },
    { "delta", "5" },
    { "echo", "6" }
  };
  const Headers::value_type *rv;
  rv = http2::get_unique_header(nva, "delta");
  CU_ASSERT(rv != nullptr);
  CU_ASSERT("delta" == rv->name);

  rv = http2::get_unique_header(nva, "bravo");
  CU_ASSERT(rv == nullptr);

  rv = http2::get_unique_header(nva, "foxtrot");
  CU_ASSERT(rv == nullptr);
}

void test_http2_get_header(void)
{
  auto nva = Headers{
    { "alpha", "1" },
    { "bravo", "2" },
    { "bravo", "3" },
    { "charlie", "4" },
    { "delta", "5" },
    { "echo", "6" }
  };
  const Headers::value_type *rv;
  rv = http2::get_header(nva, "delta");
  CU_ASSERT(rv != nullptr);
  CU_ASSERT("delta" == rv->name);

  rv = http2::get_header(nva, "bravo");
  CU_ASSERT(rv != nullptr);
  CU_ASSERT("bravo" == rv->name);

  rv = http2::get_header(nva, "foxtrot");
  CU_ASSERT(rv == nullptr);
}

void test_http2_value_lws(void)
{
  auto nva = Headers{
    { "0", "alpha" },
    { "1", " alpha" },
    { "2", "" },
    {" 3", " " },
    {" 4", " a "}
  };
  CU_ASSERT(!http2::value_lws(&nva[0]));
  CU_ASSERT(!http2::value_lws(&nva[1]));
  CU_ASSERT(http2::value_lws(&nva[2]));
  CU_ASSERT(http2::value_lws(&nva[3]));
  CU_ASSERT(!http2::value_lws(&nva[4]));
}

namespace {
auto headers = Headers
  {{"alpha", "0", true},
   {"bravo", "1"},
   {"connection", "2"},
   {"connection", "3"},
   {"delta", "4"},
   {"expect", "5"},
   {"foxtrot", "6"},
   {"tango", "7"},
   {"te", "8"},
   {"te", "9"},
   {"x-forwarded-proto", "10"},
   {"x-forwarded-proto", "11"},
   {"zulu", "12"}};
} // namespace

void test_http2_copy_norm_headers_to_nva(void)
{
  std::vector<nghttp2_nv> nva;
  http2::copy_norm_headers_to_nva(nva, headers);
  CU_ASSERT(6 == nva.size());
  auto ans = std::vector<int>{0, 1, 4, 6, 7, 12};
  for(size_t i = 0; i < ans.size(); ++i) {
    check_nv(headers[ans[i]], &nva[i]);

    if(ans[i] == 0) {
      CU_ASSERT(nva[i].flags & NGHTTP2_NV_FLAG_NO_INDEX);
    } else {
      CU_ASSERT(NGHTTP2_NV_FLAG_NONE == nva[i].flags);
    }
  }
}

void test_http2_build_http1_headers_from_norm_headers(void)
{
  std::string hdrs;
  http2::build_http1_headers_from_norm_headers(hdrs, headers);
  CU_ASSERT(hdrs ==
            "Alpha: 0\r\n"
            "Bravo: 1\r\n"
            "Delta: 4\r\n"
            "Foxtrot: 6\r\n"
            "Tango: 7\r\n"
            "Te: 8\r\n"
            "Te: 9\r\n"
            "Zulu: 12\r\n");

  hdrs.clear();
  // Both nghttp2 and spdylay do not allow \r and \n in header value
  // now.

  // auto hd2 = std::vector<std::pair<std::string, std::string>>
  //   {{"alpha", "bravo\r\ncharlie\r\n"}};
  // http2::build_http1_headers_from_norm_headers(hdrs, hd2);
  // CU_ASSERT(hdrs == "Alpha: bravo  charlie  \r\n");
}

void test_http2_lws(void)
{
  CU_ASSERT(!http2::lws("alpha"));
  CU_ASSERT(http2::lws(" "));
  CU_ASSERT(http2::lws(""));
}

namespace {
void check_rewrite_location_uri(const std::string& new_uri,
                                const std::string& uri,
                                const std::string& req_host,
                                const std::string& upstream_scheme,
                                uint16_t upstream_port)
{
  http_parser_url u;
  memset(&u, 0, sizeof(u));
  CU_ASSERT(0 == http_parser_parse_url(uri.c_str(), uri.size(), 0, &u));
  CU_ASSERT(new_uri ==
            http2::rewrite_location_uri(uri, u, req_host,
                                        upstream_scheme, upstream_port));
}
} // namespace

void test_http2_rewrite_location_uri(void)
{
  check_rewrite_location_uri("https://localhost:3000/alpha?bravo#charlie",
                             "http://localhost:3001/alpha?bravo#charlie",
                             "localhost:3001", "https", 3000);
  check_rewrite_location_uri("https://localhost/",
                             "http://localhost:3001/",
                             "localhost:3001", "https", 443);
  check_rewrite_location_uri("http://localhost/",
                             "http://localhost:3001/",
                             "localhost:3001", "http", 80);
  check_rewrite_location_uri("http://localhost:443/",
                             "http://localhost:3001/",
                             "localhost:3001", "http", 443);
  check_rewrite_location_uri("https://localhost:80/",
                             "http://localhost:3001/",
                             "localhost:3001", "https", 80);
  check_rewrite_location_uri("",
                             "http://localhost:3001/",
                             "127.0.0.1", "https", 3000);
  check_rewrite_location_uri("https://localhost:3000/",
                             "http://localhost:3001/",
                             "localhost", "https", 3000);
  check_rewrite_location_uri("",
                             "https://localhost:3001/",
                             "localhost", "https", 3000);
  check_rewrite_location_uri("https://localhost:3000/",
                             "http://localhost/",
                             "localhost", "https", 3000);
}

} // namespace shrpx
<commit_msg>Fix unittest failure<commit_after>/*
 * nghttp2 - HTTP/2 C Library
 *
 * Copyright (c) 2013 Tatsuhiro Tsujikawa
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "http2_test.h"

#include <cassert>
#include <cstring>
#include <iostream>

#include <CUnit/CUnit.h>

#include "http-parser/http_parser.h"

#include "http2.h"
#include "util.h"

using namespace nghttp2;

#define MAKE_NV(K, V) {(uint8_t*)K, (uint8_t*)V,        \
      sizeof(K) - 1, sizeof(V) - 1,                     \
      NGHTTP2_NV_FLAG_NONE}

namespace shrpx {

namespace {
void check_nv(const Header& a, const nghttp2_nv *b)
{
  CU_ASSERT(a.name.size() == b->namelen);
  CU_ASSERT(a.value.size() == b->valuelen);
  CU_ASSERT(memcmp(a.name.c_str(), b->name, b->namelen) == 0);
  CU_ASSERT(memcmp(a.value.c_str(), b->value, b->valuelen) == 0);
}
} // namespace

void test_http2_sort_nva(void)
{
  // Last 0 is stripped in MAKE_NV
  const uint8_t concatval[] = { '4', 0x00, 0x00, '6', 0x00, '5', 0x00 };
  nghttp2_nv nv[] = {MAKE_NV("alpha", "1"),
                     MAKE_NV("charlie", "3"),
                     MAKE_NV("bravo", "2"),
                     MAKE_NV("delta", concatval)};
  auto nvlen = sizeof(nv)/sizeof(nv[0]);
  auto nva = http2::sort_nva(nv, nvlen);
  CU_ASSERT(6 == nva.size());
  check_nv({"alpha", "1"}, &nva[0]);
  check_nv({"bravo", "2"}, &nva[1]);
  check_nv({"charlie", "3"}, &nva[2]);
  check_nv({"delta", "4"}, &nva[3]);
  check_nv({"delta", "6"}, &nva[4]);
  check_nv({"delta", "5"}, &nva[5]);
}

void test_http2_add_header(void)
{
  auto nva = Headers();

  http2::add_header(nva, (const uint8_t*)"alpha", 5,
                    (const uint8_t*)"123", 3, false);
  CU_ASSERT(Headers::value_type("alpha", "123") == nva[0]);
  CU_ASSERT(!nva[0].no_index);

  nva.clear();

  http2::add_header(nva, (const uint8_t*)"alpha", 5,
                    (const uint8_t*)"", 0, true);
  CU_ASSERT(Headers::value_type("alpha", "") == nva[0]);
  CU_ASSERT(nva[0].no_index);
}

void test_http2_check_http2_headers(void)
{
  auto nva1 = Headers{
    { "alpha", "1" },
    { "bravo", "2" },
    { "upgrade", "http2" }
  };
  CU_ASSERT(!http2::check_http2_headers(nva1));

  auto nva2 = Headers{
    { "connection", "1" },
    { "delta", "2" },
    { "echo", "3" }
  };
  CU_ASSERT(!http2::check_http2_headers(nva2));

  auto nva3 = Headers{
    { "alpha", "1" },
    { "bravo", "2" },
    { "te2", "3" }
  };
  CU_ASSERT(http2::check_http2_headers(nva3));
}

void test_http2_get_unique_header(void)
{
  auto nva = Headers{
    { "alpha", "1" },
    { "bravo", "2" },
    { "bravo", "3" },
    { "charlie", "4" },
    { "delta", "5" },
    { "echo", "6" }
  };
  const Headers::value_type *rv;
  rv = http2::get_unique_header(nva, "delta");
  CU_ASSERT(rv != nullptr);
  CU_ASSERT("delta" == rv->name);

  rv = http2::get_unique_header(nva, "bravo");
  CU_ASSERT(rv == nullptr);

  rv = http2::get_unique_header(nva, "foxtrot");
  CU_ASSERT(rv == nullptr);
}

void test_http2_get_header(void)
{
  auto nva = Headers{
    { "alpha", "1" },
    { "bravo", "2" },
    { "bravo", "3" },
    { "charlie", "4" },
    { "delta", "5" },
    { "echo", "6" }
  };
  const Headers::value_type *rv;
  rv = http2::get_header(nva, "delta");
  CU_ASSERT(rv != nullptr);
  CU_ASSERT("delta" == rv->name);

  rv = http2::get_header(nva, "bravo");
  CU_ASSERT(rv != nullptr);
  CU_ASSERT("bravo" == rv->name);

  rv = http2::get_header(nva, "foxtrot");
  CU_ASSERT(rv == nullptr);
}

void test_http2_value_lws(void)
{
  auto nva = Headers{
    { "0", "alpha" },
    { "1", " alpha" },
    { "2", "" },
    {" 3", " " },
    {" 4", " a "}
  };
  CU_ASSERT(!http2::value_lws(&nva[0]));
  CU_ASSERT(!http2::value_lws(&nva[1]));
  CU_ASSERT(http2::value_lws(&nva[2]));
  CU_ASSERT(http2::value_lws(&nva[3]));
  CU_ASSERT(!http2::value_lws(&nva[4]));
}

namespace {
auto headers = Headers
  {{"alpha", "0", true},
   {"bravo", "1"},
   {"connection", "2"},
   {"connection", "3"},
   {"delta", "4"},
   {"expect", "5"},
   {"foxtrot", "6"},
   {"tango", "7"},
   {"te", "8"},
   {"te", "9"},
   {"x-forwarded-proto", "10"},
   {"x-forwarded-proto", "11"},
   {"zulu", "12"}};
} // namespace

void test_http2_copy_norm_headers_to_nva(void)
{
  std::vector<nghttp2_nv> nva;
  http2::copy_norm_headers_to_nva(nva, headers);
  CU_ASSERT(7 == nva.size());
  auto ans = std::vector<int>{0, 1, 4, 5, 6, 7, 12};
  for(size_t i = 0; i < ans.size(); ++i) {
    check_nv(headers[ans[i]], &nva[i]);

    if(ans[i] == 0) {
      CU_ASSERT(nva[i].flags & NGHTTP2_NV_FLAG_NO_INDEX);
    } else {
      CU_ASSERT(NGHTTP2_NV_FLAG_NONE == nva[i].flags);
    }
  }
}

void test_http2_build_http1_headers_from_norm_headers(void)
{
  std::string hdrs;
  http2::build_http1_headers_from_norm_headers(hdrs, headers);
  CU_ASSERT(hdrs ==
            "Alpha: 0\r\n"
            "Bravo: 1\r\n"
            "Delta: 4\r\n"
            "Expect: 5\r\n"
            "Foxtrot: 6\r\n"
            "Tango: 7\r\n"
            "Te: 8\r\n"
            "Te: 9\r\n"
            "Zulu: 12\r\n");

  hdrs.clear();
  // Both nghttp2 and spdylay do not allow \r and \n in header value
  // now.

  // auto hd2 = std::vector<std::pair<std::string, std::string>>
  //   {{"alpha", "bravo\r\ncharlie\r\n"}};
  // http2::build_http1_headers_from_norm_headers(hdrs, hd2);
  // CU_ASSERT(hdrs == "Alpha: bravo  charlie  \r\n");
}

void test_http2_lws(void)
{
  CU_ASSERT(!http2::lws("alpha"));
  CU_ASSERT(http2::lws(" "));
  CU_ASSERT(http2::lws(""));
}

namespace {
void check_rewrite_location_uri(const std::string& new_uri,
                                const std::string& uri,
                                const std::string& req_host,
                                const std::string& upstream_scheme,
                                uint16_t upstream_port)
{
  http_parser_url u;
  memset(&u, 0, sizeof(u));
  CU_ASSERT(0 == http_parser_parse_url(uri.c_str(), uri.size(), 0, &u));
  CU_ASSERT(new_uri ==
            http2::rewrite_location_uri(uri, u, req_host,
                                        upstream_scheme, upstream_port));
}
} // namespace

void test_http2_rewrite_location_uri(void)
{
  check_rewrite_location_uri("https://localhost:3000/alpha?bravo#charlie",
                             "http://localhost:3001/alpha?bravo#charlie",
                             "localhost:3001", "https", 3000);
  check_rewrite_location_uri("https://localhost/",
                             "http://localhost:3001/",
                             "localhost:3001", "https", 443);
  check_rewrite_location_uri("http://localhost/",
                             "http://localhost:3001/",
                             "localhost:3001", "http", 80);
  check_rewrite_location_uri("http://localhost:443/",
                             "http://localhost:3001/",
                             "localhost:3001", "http", 443);
  check_rewrite_location_uri("https://localhost:80/",
                             "http://localhost:3001/",
                             "localhost:3001", "https", 80);
  check_rewrite_location_uri("",
                             "http://localhost:3001/",
                             "127.0.0.1", "https", 3000);
  check_rewrite_location_uri("https://localhost:3000/",
                             "http://localhost:3001/",
                             "localhost", "https", 3000);
  check_rewrite_location_uri("",
                             "https://localhost:3001/",
                             "localhost", "https", 3000);
  check_rewrite_location_uri("https://localhost:3000/",
                             "http://localhost/",
                             "localhost", "https", 3000);
}

} // namespace shrpx
<|endoftext|>


<commit_before>#include <string>
#include <vector>

static char int_to_char(int num) {
    if(num < 10 && num >= 0) return num + 48;
    return '*';
}

std::string int_to_str(int num) {
    if(num == 0) return "0";
    if(num < 0) return std::string("-") + int_to_str(-num);
    int digits = 0, process = num, single;
    std::string numString;
    //count number of digits
    while(process != 0) {
        single = process % 10;
        process = (process - single)/10;
        digits++;
    }
    process = num;
    numString.reserve(digits);
    for(int i = 0; i < digits; i++)
        numString += '*';
    for(int i = digits - 1; i >= 0; i--) {
        single = process % 10;
        numString[i] = int_to_char(single);
        process = (process - single) / 10;
    }
    return numString;
}

std::string bool_to_str(bool b) {
    if(b) return "true";
    return "false";
}

std::string inter_space(const std::vector<std::string>* vec) {
    std::string result;
    for(int i = 0; i < vec->size() - 1; i++) {
        result += (*vec)[i];
        result += " ";
    }
    result += (*vec)[vec->size() - 1];
    return result;
}
<commit_msg>``inter_space'' works on empty vector<commit_after>#include <string>
#include <vector>

static char int_to_char(int num) {
    if(num < 10 && num >= 0) return num + 48;
    return '*';
}

std::string int_to_str(int num) {
    if(num == 0) return "0";
    if(num < 0) return std::string("-") + int_to_str(-num);
    int digits = 0, process = num, single;
    std::string numString;
    //count number of digits
    while(process != 0) {
        single = process % 10;
        process = (process - single)/10;
        digits++;
    }
    process = num;
    numString.reserve(digits);
    for(int i = 0; i < digits; i++)
        numString += '*';
    for(int i = digits - 1; i >= 0; i--) {
        single = process % 10;
        numString[i] = int_to_char(single);
        process = (process - single) / 10;
    }
    return numString;
}

std::string bool_to_str(bool b) {
    if(b) return "true";
    return "false";
}

std::string inter_space(const std::vector<std::string>* vec) {
    if(vec->size() == 0) return "";
    std::string result;
    for(int i = 0; i < vec->size() - 1; i++) {
        result += (*vec)[i];
        result += " ";
    }
    result += (*vec)[vec->size() - 1];
    return result;
}
<|endoftext|>


<commit_before>#include <cmath>
#include <iostream>
#include <valarray>
#include "nbody.hpp"
#include "nbody_rk4.hpp"

/*
 * TODO:
 *     parse input file / arguments
 */

int main(int argc, char *argv[]) {
    // masses
    //double m[] = {1.0, 0.1};
    double m[] = {150.0, 200.0, 250.0};

    // positions and velocities
    //double x_init[] = {0.0, 1.0, 0.0, 0.0,  0.02, 0.0,
    //                   5.0, 0.0, 0.0, 0.0, -0.2,  0.0};
    double x_init[] = { 3.0,  1.0, 0.0, 0.0, 0.0, 0.0,
                       -1.0, -2.0, 0.0, 0.0, 0.0, 0.0,
                       -1.0,  1.0, 0.0, 0.0, 0.0, 0.0};

    NBodyRK4 system = NBodyRK4(3, 3, m, 0.0, x_init, false, NULL);
    system.integrate(10.0, 1e-6, 1e-6);

    return 0;
}
<commit_msg>Now reads integration parameters from input file<commit_after>//#include <cstdlib>
#include <fstream>
#include <iterator>
#include <vector>
#include "nbody.hpp"
#include "nbody_rk4.hpp"

/*
 * TODO:
 *     parse input file / arguments
 */

const int MAX_LINE_LEN = 256;
const int MAX_ELEM_LEN = 32;

int main(int argc, char *argv[]) {
    // TODO: Let user choose filename
    std::ifstream infile("params");
    std::vector<double> params((std::istream_iterator<double>(infile)),
                                std::istream_iterator<double>());

    // Get number of bodies and number of dimensions
    int n_bodies = (int) params[0];
    int n_dims = (int) params[1];

    double m[n_bodies];
    double x_init[2 * n_dims * n_bodies];
    // Get masses, positions and velocities
    for (int i = 0; i < n_bodies; i++) {
        m[i] = params[2 + i * (2 * n_dims + 1)];
        for (int j = 0; j < 2 * n_dims; j++) {
            x_init[i * (2 * n_dims) + j] =
                params[2 + i * (2 * n_dims + 1) + j + 1];
        }
    }

    NBodyRK4 system = NBodyRK4(n_bodies, n_dims, m, 0.0, x_init, false, NULL);
    system.integrate(10.0, 1e-6, 1e-6);

    return 0;
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)
Copyright (c) 2015 University of Central Florida's Computer Software Engineering
Scalable & Secure Systems (CSE - S3) Lab
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string>
#include <fstream>
#include <iostream>

#include "connection.h"

#define MAXDATASIZE 100

/*************************************************************************
 * Private Helper Functions                                              *
 *************************************************************************/
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

/**
 * Builds a network packet with the passed in parameters.
 * This network packet is necessary to send data across sockets.
 * @param type The type of command being passed.
 * @param command The command being sent to the server
 * @return a NetworkPacket containing the information to be sent across the socket.
 */
NetworkPacket buildPacket(CommandType type, std::string command) {
  NetworkPacket networkPacket;
  // command needs to be made into char[]
  strncpy(networkPacket.message, command.c_str(), sizeof(networkPacket.message));
  networkPacket.message[sizeof(networkPacket.message) -1] = 0;
  networkPacket.commandType = type;
  networkPacket.terminator = THE_TERMINATOR;

  return networkPacket;
}

libomdb::Connection buildConnectionObj(int socket, char* buffer) {
  // TODO: Parse connection string and create new Connection object

}

libomdb::CommandResult parseCommandResult(std::string result) {
  //TODO: build CommandResult requires parsing neils string
}

libomdb::Result parseQueryResult(std::string result) {
  //TODO: build Result, requires parsing Neils stirng
}

/**
 * Sends message across the socket passed in
 * @param message The message to send to the server
 * @param socket The file descriptor of the listening socket
 */
std::string sendMessage(NetworkPacket packet, int socket) {
  // Need to convert message to c string in order to send it.
  char message[MESSAGE_SIZE];
  memcpy(message, &packet, sizeof(packet));
  std::cout << "Message being sent: " << message <<std::endl;
  // const char* c_message = message.c_str();
  std::cout << "Attempting to send message to socket" << socket << std::endl;
  int bytes_sent = send(socket, message, sizeof message, 0);
  std::cout<< "Bytes sent: " << bytes_sent << std::endl;
  if (bytes_sent == -1) {
    perror("send");
    return NULL;
  }

  // Wait for receipt of message;
  char result[MAXDATASIZE];
  int bytes_recieved = recv(socket, result, sizeof(result), 0);
  std::cout << "Bytes relieved: " << bytes_recieved << std::endl;
  if (bytes_recieved == -1) {
    perror("recv");
    return NULL;
  }

  return result;
}

/*************************************************************************
 * ConnectionMetaData Implementations                                    *
 *************************************************************************/
libomdb::ConnectionMetaData::ConnectionMetaData(std::string dbName, bool isValid)
        :m_databaseName(dbName), m_isValid(isValid) {}

std::string libomdb::ConnectionMetaData::getDbName() {
  return this->m_databaseName;
}

bool libomdb::ConnectionMetaData::isValid() {
  return this->m_isValid;
}

/*************************************************************************
 * Connection Implementations                                            *
 *************************************************************************/

  // TODO: Break up this monstrosity.
libomdb::Connection libomdb::Connection::connect(std::string hostname,
                                                 uint16_t port,
                                                 std::string db) {
  int sockfd, numbytes;
  char buf[MAXDATASIZE];
  struct addrinfo hints, *servinfo, *p;
  int rv;
  char s[INET6_ADDRSTRLEN];

  // Convert hostname to c string
  const char* connection_ip = hostname.c_str();

  //Convert port to c string.
  const char* port_string = std::to_string(port).c_str();

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;

  if ((rv = getaddrinfo(connection_ip, port_string,
                        &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %d\n", rv);
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return errorConnection();
  }

  // loop through all the results and connect to the first we can
  for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
                                p->ai_protocol)) == -1) {
        perror("client: socket");
        continue;
      }

    if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
      close(sockfd);
      perror("client: connect");
      continue;
    }

    break;
  }

  if (p == NULL) {
    fprintf(stderr, "client: failed to connect\n");
    return errorConnection();
  }

  inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
                                                          s, sizeof s);
  printf("client: connecting to %s\n", s);
  freeaddrinfo(servinfo); // all done with this structure

  if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
    perror("recv");
    return errorConnection();
  }

  buf[numbytes] = '\0';

  printf("client: received '%s'\n",buf);
  std::string dbConnectString = "k:"+db;
  const char* dbString = dbConnectString.c_str();
  // Sending the name of the database to the server.
  int bytesSent = send(sockfd, dbString, dbConnectString.length(), 0);
  if (bytesSent == -1) {
    perror("send");
    return errorConnection();
  }

  int bytesReceived = recv(sockfd, buf, MAXDATASIZE -1, 0);
  if (bytesReceived == -1) {
    perror("recv");
    return errorConnection();
  }

  buf[bytesReceived] = '\0';
  printf("client received response from server: %s\n", buf);

  return buildConnectionObj(sockfd, buf);
}

void libomdb::Connection::disconnect() {
  close(this->m_socket_fd);
}

libomdb::CommandResult libomdb::Connection::executeCommand(std::string command) {
  NetworkPacket packet = buildPacket(DB_COMMAND, command);
  return parseCommandResult(sendMessage(packet, this->m_socket_fd));
  // TODO: Change command to packet when sendMessage is fixed
}

libomdb::Result libomdb::Connection::executeQuery(std::string query) {
  NetworkPacket packet = buildPacket(SQL_STATEMENT, query);
  return parseQueryResult(sendMessage(packet, this->m_socket_fd));
  // TODO: Change query to packet when sendMessage is fixed
}

libomdb::ConnectionMetaData libomdb::Connection::getMetaData() {
  return this->m_metaData;
}

void libomdb::Connection::setMetaData(libomdb::ConnectionMetaData data) {
  this->m_metaData = data;
}

libomdb::Connection::Connection(uint64_t socket_fd, ConnectionMetaData metaData)
        :m_metaData(metaData), m_socket_fd(socket_fd) {}<commit_msg>Converted NetworkPacket to CommandPacket<commit_after>/*
The MIT License (MIT)
Copyright (c) 2015 University of Central Florida's Computer Software Engineering
Scalable & Secure Systems (CSE - S3) Lab
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string>
#include <fstream>
#include <iostream>

#include "connection.h"

#define MAXDATASIZE 100

/*************************************************************************
 * Private Helper Functions                                              *
 *************************************************************************/
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

/**
 * Builds a network packet with the passed in parameters.
 * This network packet is necessary to send data across sockets.
 * @param type The type of command being passed.
 * @param command The command being sent to the server
 * @return a CommandPacket containing the information to be sent across the socket.
 */
CommandPacket buildPacket(CommandType type, std::string command) {
  CommandPacket commandPacket;
  // command needs to be made into char[]
  strncpy(commandPacket.message, command.c_str(), sizeof(commandPacket.message));
  commandPacket.message[sizeof(commandPacket.message) -1] = 0;
  commandPacket.commandType = type;
  commandPacket.terminator = THE_TERMINATOR;

  return commandPacket;
}

libomdb::Connection buildConnectionObj(int socket, char* buffer) {
  // TODO: Parse connection string and create new Connection object

}

libomdb::CommandResult parseCommandResult(std::string result) {
  //TODO: build CommandResult requires parsing neils string
}

libomdb::Result parseQueryResult(std::string result) {
  //TODO: build Result, requires parsing Neils stirng
  // The result packet comes in two stages, first the ResultMetaDataPacket. Then the ResultPacket.
}

/**
 * Sends message across the socket passed in
 * @param message The message to send to the server
 * @param socket The file descriptor of the listening socket
 */
std::string sendMessage(CommandPacket packet, int socket) {
  // Need to convert message to c string in order to send it.
  char message[MESSAGE_SIZE];
  memcpy(message, &packet, sizeof(packet));
  std::cout << "Message being sent: " << message <<std::endl;
  // const char* c_message = message.c_str();
  std::cout << "Attempting to send message to socket" << socket << std::endl;
  int bytes_sent = send(socket, message, sizeof message, 0);
  std::cout<< "Bytes sent: " << bytes_sent << std::endl;
  if (bytes_sent == -1) {
    perror("send");
    return NULL;
  }

  // Wait for receipt of message;
  char result[MAXDATASIZE];
  int bytes_recieved = recv(socket, result, sizeof(result), 0);
  std::cout << "Bytes relieved: " << bytes_recieved << std::endl;
  if (bytes_recieved == -1) {
    perror("recv");
    return NULL;
  }

  return result;
}

/*************************************************************************
 * ConnectionMetaData Implementations                                    *
 *************************************************************************/
libomdb::ConnectionMetaData::ConnectionMetaData(std::string dbName, bool isValid)
        :m_databaseName(dbName), m_isValid(isValid) {}

std::string libomdb::ConnectionMetaData::getDbName() {
  return this->m_databaseName;
}

bool libomdb::ConnectionMetaData::isValid() {
  return this->m_isValid;
}

/*************************************************************************
 * Connection Implementations                                            *
 *************************************************************************/

  // TODO: Break up this monstrosity.
libomdb::Connection libomdb::Connection::connect(std::string hostname,
                                                 uint16_t port,
                                                 std::string db) {
  int sockfd, numbytes;
  char buf[MAXDATASIZE];
  struct addrinfo hints, *servinfo, *p;
  int rv;
  char s[INET6_ADDRSTRLEN];

  // Convert hostname to c string
  const char* connection_ip = hostname.c_str();

  //Convert port to c string.
  const char* port_string = std::to_string(port).c_str();

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;

  if ((rv = getaddrinfo(connection_ip, port_string,
                        &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %d\n", rv);
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return errorConnection();
  }

  // loop through all the results and connect to the first we can
  for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
                                p->ai_protocol)) == -1) {
        perror("client: socket");
        continue;
      }

    if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
      close(sockfd);
      perror("client: connect");
      continue;
    }

    break;
  }

  if (p == NULL) {
    fprintf(stderr, "client: failed to connect\n");
    return errorConnection();
  }

  inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
                                                          s, sizeof s);
  printf("client: connecting to %s\n", s);
  freeaddrinfo(servinfo); // all done with this structure

  if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
    perror("recv");
    return errorConnection();
  }

  buf[numbytes] = '\0';

  printf("client: received '%s'\n",buf);
  std::string dbConnectString = "k:"+db;
  const char* dbString = dbConnectString.c_str();
  // Sending the name of the database to the server.
  int bytesSent = send(sockfd, dbString, dbConnectString.length(), 0);
  if (bytesSent == -1) {
    perror("send");
    return errorConnection();
  }

  int bytesReceived = recv(sockfd, buf, MAXDATASIZE -1, 0);
  if (bytesReceived == -1) {
    perror("recv");
    return errorConnection();
  }

  buf[bytesReceived] = '\0';
  printf("client received response from server: %s\n", buf);

  return buildConnectionObj(sockfd, buf);
}

void libomdb::Connection::disconnect() {
  close(this->m_socket_fd);
}

libomdb::CommandResult libomdb::Connection::executeCommand(std::string command) {
  CommandPacket packet = buildPacket(CommandType::DB_COMMAND, command);
  return parseCommandResult(sendMessage(packet, this->m_socket_fd));
  // TODO: Change command to packet when sendMessage is fixed
}

libomdb::Result libomdb::Connection::executeQuery(std::string query) {
  CommandPacket packet = buildPacket(CommandType::SQL_STATEMENT, query);
  return parseQueryResult(sendMessage(packet, this->m_socket_fd));
  // TODO: Change query to packet when sendMessage is fixed
}

libomdb::ConnectionMetaData libomdb::Connection::getMetaData() {
  return this->m_metaData;
}

void libomdb::Connection::setMetaData(libomdb::ConnectionMetaData data) {
  this->m_metaData = data;
}

libomdb::Connection::Connection(uint64_t socket_fd, ConnectionMetaData metaData)
        :m_metaData(metaData), m_socket_fd(socket_fd) {}<|endoftext|>


<commit_before>/*##############################################################################
#    GIPPY: Geospatial Image Processing library for Python
#
#    Copyright (C) 2014 Matthew A Hanson
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 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 General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program. If not, see <http://www.gnu.org/licenses/>
##############################################################################*/

#include <gip/GeoResource.h>
#include <boost/filesystem.hpp>

namespace gip {
    // Constructors
    GeoResource::GeoResource(string filename)
        : _Filename(filename) {}

    GeoResource::GeoResource(const GeoResource& resource)
        : _Filename(resource._Filename) {}

    GeoResource& GeoResource::operator=(const GeoResource& resource) {
        if (this == &resource) return *this;
        _Filename = resource._Filename;
        return *this;
    }

    // Info
    string GeoResource::Filename() const {
        return _Filename.string();
    }

    path GeoResource::Path() const {
        return _Filename;
    }

    string GeoResource::Basename() const {
        return _Filename.stem().string();
    }

    // Geospatial
    Point<double> GeoResource::GeoLoc(float xloc, float yloc) const {
        CImg<double> affine = Affine();
        Point<double> pt(affine[0] + xloc*affine[1] + yloc*affine[2], affine[3] + xloc*affine[4] + yloc*affine[5]);
        return pt;
    }

    Point<double> GeoResource::TopLeft() const {
        return GeoLoc(0, 0);
    }

    Point<double> GeoResource::LowerLeft() const {
        return GeoLoc(0, YSize()-1);
    }

    Point<double> GeoResource::TopRight() const {
        return GeoLoc(XSize()-1, 0);
    }

    Point<double> GeoResource::LowerRight() const {
        return GeoLoc(XSize()-1, YSize()-1);
    }

    Point<double> GeoResource::MinXY() const {
        Point<double> pt1(TopLeft()), pt2(LowerRight());
        double MinX(std::min(pt1.x(), pt2.x()));
        double MinY(std::min(pt1.y(), pt2.y()));
        return Point<double>(MinX, MinY);
    }

    Point<double> GeoResource::MaxXY() const {
        Point<double> pt1(TopLeft()), pt2(LowerRight());
        double MaxX(std::max(pt1.x(), pt2.x()));
        double MaxY(std::max(pt1.y(), pt2.y()));
        return Point<double>(MaxX, MaxY);
    }

    OGRSpatialReference GeoResource::SRS() const {
        string s(Projection());
        return OGRSpatialReference(s.c_str());
    }

    GeoResource& SetCoordinateSystem(const GeoResource& res) {
        SetProjection(res.Projection());
        SetAffine(res.Affine());
        return *this;
    }

    ChunkSet GeoResource::Chunks(unsigned int padding, unsigned int numchunks) const {
        return ChunkSet(XSize(), YSize(), padding, numchunks);
    }

    // Metadata
    string GeoResource::Meta(string key) const {
        const char* item = GDALObject()->GetMetadataItem(key.c_str());
        return (item == NULL) ? "": item;
    }

    // Get metadata group
    vector<string> GeoResource::MetaGroup(string group, string filter) const {
        char** meta= GDALObject()->GetMetadata(group.c_str());
        int num = CSLCount(meta);
        std::vector<string> items;
        for (int i=0;i<num; i++) {
                if (filter != "") {
                        string md = string(meta[i]);
                        string::size_type pos = md.find(filter);
                        if (pos != string::npos) items.push_back(md.substr(pos+filter.length()));
                } else items.push_back( meta[i] );
        }
        return items;
    }

    GeoResource& GeoResource::SetMeta(string key, string item) {
        GDALObject()->SetMetadataItem(key.c_str(), item.c_str());
        return *this;
    }

    GeoResource& GeoResource::SetMeta(std::map<string, string> items) {
        for (dictionary::const_iterator i=items.begin(); i!=items.end(); i++) {
            SetMeta(i->first, i->second);
        }
        return *this;
    }

    GeoResource& GeoResource::CopyMeta(const GeoResource& resource) {
        GDALObject()->SetMetadata(resource.GDALObject()->GetMetadata());
        return *this;
    }

} // namespace gip<commit_msg>fixed definition of SetCoordinateSystem<commit_after>/*##############################################################################
#    GIPPY: Geospatial Image Processing library for Python
#
#    Copyright (C) 2014 Matthew A Hanson
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 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 General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program. If not, see <http://www.gnu.org/licenses/>
##############################################################################*/

#include <gip/GeoResource.h>
#include <boost/filesystem.hpp>

namespace gip {
    // Constructors
    GeoResource::GeoResource(string filename)
        : _Filename(filename) {}

    GeoResource::GeoResource(const GeoResource& resource)
        : _Filename(resource._Filename) {}

    GeoResource& GeoResource::operator=(const GeoResource& resource) {
        if (this == &resource) return *this;
        _Filename = resource._Filename;
        return *this;
    }

    // Info
    string GeoResource::Filename() const {
        return _Filename.string();
    }

    path GeoResource::Path() const {
        return _Filename;
    }

    string GeoResource::Basename() const {
        return _Filename.stem().string();
    }

    // Geospatial
    Point<double> GeoResource::GeoLoc(float xloc, float yloc) const {
        CImg<double> affine = Affine();
        Point<double> pt(affine[0] + xloc*affine[1] + yloc*affine[2], affine[3] + xloc*affine[4] + yloc*affine[5]);
        return pt;
    }

    Point<double> GeoResource::TopLeft() const {
        return GeoLoc(0, 0);
    }

    Point<double> GeoResource::LowerLeft() const {
        return GeoLoc(0, YSize()-1);
    }

    Point<double> GeoResource::TopRight() const {
        return GeoLoc(XSize()-1, 0);
    }

    Point<double> GeoResource::LowerRight() const {
        return GeoLoc(XSize()-1, YSize()-1);
    }

    Point<double> GeoResource::MinXY() const {
        Point<double> pt1(TopLeft()), pt2(LowerRight());
        double MinX(std::min(pt1.x(), pt2.x()));
        double MinY(std::min(pt1.y(), pt2.y()));
        return Point<double>(MinX, MinY);
    }

    Point<double> GeoResource::MaxXY() const {
        Point<double> pt1(TopLeft()), pt2(LowerRight());
        double MaxX(std::max(pt1.x(), pt2.x()));
        double MaxY(std::max(pt1.y(), pt2.y()));
        return Point<double>(MaxX, MaxY);
    }

    OGRSpatialReference GeoResource::SRS() const {
        string s(Projection());
        return OGRSpatialReference(s.c_str());
    }

    GeoResource& GeoResource::SetCoordinateSystem(const GeoResource& res) {
        SetProjection(res.Projection());
        SetAffine(res.Affine());
        return *this;
    }

    ChunkSet GeoResource::Chunks(unsigned int padding, unsigned int numchunks) const {
        return ChunkSet(XSize(), YSize(), padding, numchunks);
    }

    // Metadata
    string GeoResource::Meta(string key) const {
        const char* item = GDALObject()->GetMetadataItem(key.c_str());
        return (item == NULL) ? "": item;
    }

    // Get metadata group
    vector<string> GeoResource::MetaGroup(string group, string filter) const {
        char** meta= GDALObject()->GetMetadata(group.c_str());
        int num = CSLCount(meta);
        std::vector<string> items;
        for (int i=0;i<num; i++) {
                if (filter != "") {
                        string md = string(meta[i]);
                        string::size_type pos = md.find(filter);
                        if (pos != string::npos) items.push_back(md.substr(pos+filter.length()));
                } else items.push_back( meta[i] );
        }
        return items;
    }

    GeoResource& GeoResource::SetMeta(string key, string item) {
        GDALObject()->SetMetadataItem(key.c_str(), item.c_str());
        return *this;
    }

    GeoResource& GeoResource::SetMeta(std::map<string, string> items) {
        for (dictionary::const_iterator i=items.begin(); i!=items.end(); i++) {
            SetMeta(i->first, i->second);
        }
        return *this;
    }

    GeoResource& GeoResource::CopyMeta(const GeoResource& resource) {
        GDALObject()->SetMetadata(resource.GDALObject()->GetMetadata());
        return *this;
    }

} // namespace gip<|endoftext|>


<commit_before>#include "ipfs.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QElapsedTimer>
#include <QEventLoop>
#include <QUrl>
#include <QProcess>
#include <QRegExp>
#include <QStandardPaths>
#include <QDir>
#include <QDebug>

#include "directory.h"

/*
 * PlanUML
 * @startuml
 *
 * [*] --> LAUNCH_DAEMON
 * LAUNCH_DAEMON --> RUNNING : read stdin
 * RUNNING --> LAUNCH_DAEMON : crash
 * RUNNING --> QUITTING
 *
 * @enduml
 */

Q_GLOBAL_STATIC(Ipfs, singleton)

enum IpfsState : short
{
    LAUNCH_DAEMON,
    RUNNING,
    QUITTING
};

Ipfs::Ipfs()
    : state_(LAUNCH_DAEMON),
      manager_(new QNetworkAccessManager()),
      daemon_process_(NULL),
      cli_process_(NULL),
      api_ip_("127.0.0.1"),
      api_port_("5001")
{
    launch_daemon();
}

Ipfs::~Ipfs()
{
    this->state_ = QUITTING;
    if(daemon_process_)
    {
        daemon_process_->terminate();
        if(!daemon_process_->waitForFinished())
        {
            daemon_process_->kill();
        }
        daemon_process_->deleteLater();
    }
    manager_->deleteLater();
}

Ipfs *Ipfs::instance()
{
    return singleton();
}

QUrl Ipfs::api_url(const QString &command)
{
    return QUrl(QString("http://%1:%2/api/v0/%3")
                .arg(api_ip_, api_port_, command));
}

IpfsAccess *Ipfs::query(const QUrl &url)
{
    IpfsAccess *access = new IpfsAccess();
    access->timer = new QElapsedTimer();
    access->request = new QNetworkRequest(url);

    // If not connected to the daemon, pill up the requests in a buffer
    if(online())
        launch_access((access));
    else
        access_buffer_ << access;

    return access;
}

bool Ipfs::online() const
{
    return state_ == RUNNING;
}

bool Ipfs::is_object_local(const IpfsHash &hash) const
{
    return local_objects_.contains(hash);
}

void Ipfs::init_commands()
{
    id.init();
    stats.init();
    swarm.init();
    version.init();
}

void Ipfs::launch_daemon()
{
    state_ = LAUNCH_DAEMON;

    // Add a custom repo location
    QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/repo");
    qDebug() << "Repo path: " << dir.absolutePath();

    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    env.insert("IPFS_PATH", dir.absolutePath());

    if(cli_process_ == NULL)
    {
        cli_process_ = new QProcess();
        cli_process_->setProcessEnvironment(env);
    }

    // Initialize the repo if needed
    if(!dir.exists())
    {
        dir.mkpath(".");

        // ipfs should be in the PATH
        cli_process_->start("ipfs", QStringList() << "init");
        cli_process_->waitForFinished();

        qDebug() << "Repo initialized";
    }

    // Configure the HTTP API addresse
    cli_process_->start("ipfs", QStringList() << "config" << "Addresses.API" << "/ip4/127.0.0.1/tcp/4280");
    cli_process_->waitForFinished();
    api_port_ = "4280";
    qDebug() << "HTTP API set to /ip4/127.0.0.1/tcp/4280";

    daemon_process_ = new QProcess(this);

    connect(daemon_process_, SIGNAL(started()),
            this, SLOT(daemon_started()));
    connect(daemon_process_, SIGNAL(error(QProcess::ProcessError)),
            this, SLOT(daemon_error(QProcess::ProcessError)));
    connect(daemon_process_, SIGNAL(finished(int,QProcess::ExitStatus)),
            this, SLOT(daemon_finished(int,QProcess::ExitStatus)));
    connect(daemon_process_, SIGNAL(readyReadStandardOutput()),
            this, SLOT(daemon_stdout()));
    connect(daemon_process_, SIGNAL(readyReadStandardError()),
            this, SLOT(daemon_stderr()));

    // ipfs should be in the PATH
    daemon_process_->setProcessEnvironment(env);
    daemon_process_->start("ipfs", QStringList() << "daemon");
}

void Ipfs::launch_access(IpfsAccess *access)
{
    access->timer->start();
    access->reply = manager_->get(*access->request);

    connect(access->reply, &QNetworkReply::finished,
            this, [this, access]()
    {
        if(access->reply->error())
        {
            qDebug() << "http error: " << access->reply->errorString() << endl;
            qDebug() << "request: " << access->request->url() << endl;

            if(this->state_ == RUNNING)
            {
                // TODO: restart process ?
            }

            delete access;

            return;
        }

        QString url = access->request->url().toString().remove(QRegExp("^.*/v0/"));
        qDebug() << url << access->timer->elapsed() << "ms";

        emit access->finished();
    });
}

void Ipfs::on_online()
{
    // Configure the various log level we need
    cli_process_->start("ipfs", QStringList() << "log" << "level" << "all" << "info");
    cli_process_->waitForFinished();

    init_commands();

    // Refresh local objects
    RefsReply *refs_reply = refs.local();
    connect(refs_reply, &RefsReply::finished,
            this, [this, refs_reply]()
    {
        qDebug() << refs_reply->refs.size() << " obj";

        foreach (IpfsHash hash, refs_reply->refs)
        {
            if(this->local_objects_.contains(hash))
            {
                this->local_objects_.remove(hash);
            }
            else
            {
                emit objectAdded(hash);
            }
        }

        foreach (IpfsHash hash, this->local_objects_)
        {
            emit objectRemoved(hash);
        }

        this->local_objects_ = refs_reply->refs;
    });

    while(!access_buffer_.empty())
    {
        launch_access(access_buffer_.dequeue());
    }
}

void Ipfs::daemon_started()
{
    qDebug() << "daemon started";
}

void Ipfs::daemon_error(QProcess::ProcessError error)
{
    qDebug() << "daemon error " << error;
    if(state_ == RUNNING && daemon_process_->state() == QProcess::NotRunning)
    {
        // TODO: restart process
    }
}

void Ipfs::daemon_finished(int exit_code, QProcess::ExitStatus exit_status)
{
    qDebug() << "daemon finished exit code: " << exit_code
             << "exit status: " << exit_status;

    if(state_ == RUNNING && daemon_process_->state() == QProcess::NotRunning)
    {
        // TODO: restart process
    }
}

void Ipfs::daemon_stdout()
{
    QByteArray raw = daemon_process_->readAllStandardOutput();
    QTextStream stdout(&raw);

    while (!stdout.atEnd())
    {
        QString line = stdout.readLine();

        if(state_ == LAUNCH_DAEMON)
        {
            QRegExp regex("^Daemon is ready$");
            if(regex.indexIn(line) >= 0)
            {
                state_ = RUNNING;
                on_online();
            }
        }
    }
}

// Ipfs daemon output its log on stderr
void Ipfs::daemon_stderr()
{
    QByteArray raw = daemon_process_->readAllStandardError();
    QTextStream stderr(&raw);

    while (!stderr.atEnd())
    {
        QString line = stderr.readLine();

        QRegExp added("^.*Added block ([a-zA-Z0-9]*).* module=blockstore.*$");
        if(added.indexIn(line) >= 0)
        {
            try
            {
                const IpfsHash hash(added.cap(1));
                local_objects_.insert(hash);
                emit objectAdded(hash);
                qDebug() << "added " << hash;
            }
            catch(std::exception& e)
            {
                qDebug() << e.what() << added.cap(1);
            }
        }

        QRegExp removed("^.*Removed block ([a-zA-Z0-9]*).* module=blockstore.*$");
        if(removed.indexIn(line) >= 0)
        {
            try
            {
                const IpfsHash hash(removed.cap(1));
                local_objects_.remove(hash);
                qDebug() << "removed" << hash;
                emit objectRemoved(hash);
            }
            catch(std::exception& e)
            {
                qDebug() << e.what() << added.cap(1);
            }
        }
    }
}

IpfsAccess::~IpfsAccess()
{
    delete this->request;
    this->reply->deleteLater();
    delete this->timer;
}

const QJsonObject IpfsAccess::json()
{
    QString str = this->reply->readAll();

    QJsonDocument doc = QJsonDocument::fromJson(str.toUtf8());
    return doc.object();
}
<commit_msg>configure CORS to avoid 403 error when requesting the API<commit_after>#include "ipfs.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QElapsedTimer>
#include <QEventLoop>
#include <QUrl>
#include <QProcess>
#include <QRegExp>
#include <QStandardPaths>
#include <QDir>
#include <QDebug>

#include "directory.h"

/*
 * PlanUML
 * @startuml
 *
 * [*] --> LAUNCH_DAEMON
 * LAUNCH_DAEMON --> RUNNING : read stdin
 * RUNNING --> LAUNCH_DAEMON : crash
 * RUNNING --> QUITTING
 *
 * @enduml
 */

Q_GLOBAL_STATIC(Ipfs, singleton)

enum IpfsState : short
{
    LAUNCH_DAEMON,
    RUNNING,
    QUITTING
};

Ipfs::Ipfs()
    : state_(LAUNCH_DAEMON),
      manager_(new QNetworkAccessManager()),
      daemon_process_(NULL),
      cli_process_(NULL),
      api_ip_("127.0.0.1"),
      api_port_("5001")
{
    launch_daemon();
}

Ipfs::~Ipfs()
{
    this->state_ = QUITTING;
    if(daemon_process_)
    {
        daemon_process_->terminate();
        if(!daemon_process_->waitForFinished())
        {
            daemon_process_->kill();
        }
        daemon_process_->deleteLater();
    }
    manager_->deleteLater();
}

Ipfs *Ipfs::instance()
{
    return singleton();
}

QUrl Ipfs::api_url(const QString &command)
{
    return QUrl(QString("http://%1:%2/api/v0/%3")
                .arg(api_ip_, api_port_, command));
}

IpfsAccess *Ipfs::query(const QUrl &url)
{
    IpfsAccess *access = new IpfsAccess();
    access->timer = new QElapsedTimer();
    access->request = new QNetworkRequest(url);

    // If not connected to the daemon, pill up the requests in a buffer
    if(online())
        launch_access((access));
    else
        access_buffer_ << access;

    return access;
}

bool Ipfs::online() const
{
    return state_ == RUNNING;
}

bool Ipfs::is_object_local(const IpfsHash &hash) const
{
    return local_objects_.contains(hash);
}

void Ipfs::init_commands()
{
    id.init();
    stats.init();
    swarm.init();
    version.init();
}

void Ipfs::launch_daemon()
{
    state_ = LAUNCH_DAEMON;

    // Add a custom repo location
    QDir dir(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/repo");
    qDebug() << "Repo path: " << dir.absolutePath();

    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    env.insert("IPFS_PATH", dir.absolutePath());

    if(cli_process_ == NULL)
    {
        cli_process_ = new QProcess();
        cli_process_->setProcessEnvironment(env);
    }

    // Initialize the repo if needed
    if(!dir.exists())
    {
        dir.mkpath(".");

        // ipfs should be in the PATH
        cli_process_->start("ipfs", QStringList() << "init");
        cli_process_->waitForFinished();

        qDebug() << "Repo initialized";
    }

    // Configure the HTTP API addresse
    cli_process_->start("ipfs", QStringList() << "config" << "Addresses.API" << "/ip4/127.0.0.1/tcp/4280");
    cli_process_->waitForFinished();
    api_port_ = "4280";
    qDebug() << "HTTP API set to /ip4/127.0.0.1/tcp/4280";

    // Add the API url to the CORS config to avoid 403
    cli_process_->start("ipfs",
        QStringList() << "config"
            << "--json"
            << "API.HTTPHeaders"
            << "{\"Access-Control-Allow-Origin\" : [\"http://127.0.0.1\", \"http://127.0.0.1:4280\"]}");
    cli_process_->waitForFinished();
    qDebug() << "Configured CORS";

    daemon_process_ = new QProcess(this);

    connect(daemon_process_, SIGNAL(started()),
            this, SLOT(daemon_started()));
    connect(daemon_process_, SIGNAL(error(QProcess::ProcessError)),
            this, SLOT(daemon_error(QProcess::ProcessError)));
    connect(daemon_process_, SIGNAL(finished(int,QProcess::ExitStatus)),
            this, SLOT(daemon_finished(int,QProcess::ExitStatus)));
    connect(daemon_process_, SIGNAL(readyReadStandardOutput()),
            this, SLOT(daemon_stdout()));
    connect(daemon_process_, SIGNAL(readyReadStandardError()),
            this, SLOT(daemon_stderr()));

    // ipfs should be in the PATH
    daemon_process_->setProcessEnvironment(env);
    daemon_process_->start("ipfs", QStringList() << "daemon");
}

void Ipfs::launch_access(IpfsAccess *access)
{
    access->timer->start();
    access->reply = manager_->get(*access->request);

    connect(access->reply, &QNetworkReply::finished,
            this, [this, access]()
    {
        if(access->reply->error())
        {
            qDebug() << "http error: " << access->reply->errorString() << endl;
            qDebug() << "request: " << access->request->url() << endl;

            if(this->state_ == RUNNING)
            {
                // TODO: restart process ?
            }

            delete access;

            return;
        }

        QString url = access->request->url().toString().remove(QRegExp("^.*/v0/"));
        qDebug() << url << access->timer->elapsed() << "ms";

        emit access->finished();
    });
}

void Ipfs::on_online()
{
    // Configure the various log level we need
    cli_process_->start("ipfs", QStringList() << "log" << "level" << "all" << "info");
    cli_process_->waitForFinished();

    init_commands();

    // Refresh local objects
    RefsReply *refs_reply = refs.local();
    connect(refs_reply, &RefsReply::finished,
            this, [this, refs_reply]()
    {
        qDebug() << refs_reply->refs.size() << " obj";

        foreach (IpfsHash hash, refs_reply->refs)
        {
            if(this->local_objects_.contains(hash))
            {
                this->local_objects_.remove(hash);
            }
            else
            {
                emit objectAdded(hash);
            }
        }

        foreach (IpfsHash hash, this->local_objects_)
        {
            emit objectRemoved(hash);
        }

        this->local_objects_ = refs_reply->refs;
    });

    while(!access_buffer_.empty())
    {
        launch_access(access_buffer_.dequeue());
    }
}

void Ipfs::daemon_started()
{
    qDebug() << "daemon started";
}

void Ipfs::daemon_error(QProcess::ProcessError error)
{
    qDebug() << "daemon error " << error;
    if(state_ == RUNNING && daemon_process_->state() == QProcess::NotRunning)
    {
        // TODO: restart process
    }
}

void Ipfs::daemon_finished(int exit_code, QProcess::ExitStatus exit_status)
{
    qDebug() << "daemon finished exit code: " << exit_code
             << "exit status: " << exit_status;

    if(state_ == RUNNING && daemon_process_->state() == QProcess::NotRunning)
    {
        // TODO: restart process
    }
}

void Ipfs::daemon_stdout()
{
    QByteArray raw = daemon_process_->readAllStandardOutput();
    QTextStream stdout(&raw);

    while (!stdout.atEnd())
    {
        QString line = stdout.readLine();

        if(state_ == LAUNCH_DAEMON)
        {
            QRegExp regex("^Daemon is ready$");
            if(regex.indexIn(line) >= 0)
            {
                state_ = RUNNING;
                on_online();
            }
        }
    }
}

// Ipfs daemon output its log on stderr
void Ipfs::daemon_stderr()
{
    QByteArray raw = daemon_process_->readAllStandardError();
    QTextStream stderr(&raw);

    while (!stderr.atEnd())
    {
        QString line = stderr.readLine();

        QRegExp added("^.*Added block ([a-zA-Z0-9]*).* module=blockstore.*$");
        if(added.indexIn(line) >= 0)
        {
            try
            {
                const IpfsHash hash(added.cap(1));
                local_objects_.insert(hash);
                emit objectAdded(hash);
                qDebug() << "added " << hash;
            }
            catch(std::exception& e)
            {
                qDebug() << e.what() << added.cap(1);
            }
        }

        QRegExp removed("^.*Removed block ([a-zA-Z0-9]*).* module=blockstore.*$");
        if(removed.indexIn(line) >= 0)
        {
            try
            {
                const IpfsHash hash(removed.cap(1));
                local_objects_.remove(hash);
                qDebug() << "removed" << hash;
                emit objectRemoved(hash);
            }
            catch(std::exception& e)
            {
                qDebug() << e.what() << added.cap(1);
            }
        }
    }
}

IpfsAccess::~IpfsAccess()
{
    delete this->request;
    this->reply->deleteLater();
    delete this->timer;
}

const QJsonObject IpfsAccess::json()
{
    QString str = this->reply->readAll();

    QJsonDocument doc = QJsonDocument::fromJson(str.toUtf8());
    return doc.object();
}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (people-users@projects.maemo.org)
**
** This file is part of contactsd.
**
** If you have questions regarding the use of this file, please contact
** Nokia at people-users@projects.maemo.org.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <TelepathyQt4/ContactManager>
#include <TelepathyQt4/PendingContacts>
#include <TelepathyQt4/PendingOperation>
#include <TelepathyQt4/PendingReady>
#include <TelepathyQt4/Profile>

#include "cdtpaccount.h"
#include "cdtpcontact.h"
#include "debug.h"

using namespace Contactsd;

CDTpAccount::CDTpAccount(const Tp::AccountPtr &account, QObject *parent)
    : QObject(parent),
      mAccount(account),
      mHasRoster(false),
      mFirstSeen(false)
{
    // connect all signals we care about, so we can signal that the account
    // changed accordingly
    connect(mAccount.data(),
            SIGNAL(displayNameChanged(const QString &)),
            SLOT(onAccountDisplayNameChanged()));
    connect(mAccount.data(),
            SIGNAL(nicknameChanged(const QString &)),
            SLOT(onAccountNicknameChanged()));
    connect(mAccount.data(),
            SIGNAL(currentPresenceChanged(const Tp::Presence &)),
            SLOT(onAccountCurrentPresenceChanged()));
    connect(mAccount.data(),
            SIGNAL(avatarChanged(const Tp::Avatar &)),
            SLOT(onAccountAvatarChanged()));
    connect(mAccount.data(),
            SIGNAL(connectionChanged(const Tp::ConnectionPtr &)),
            SLOT(onAccountConnectionChanged(const Tp::ConnectionPtr &)));

    setConnection(mAccount->connection());
}

CDTpAccount::~CDTpAccount()
{
}

QList<CDTpContactPtr> CDTpAccount::contacts() const
{
    QList<CDTpContactPtr> contacts;
    Q_FOREACH (const CDTpContactPtr &contactWrapper, mContacts) {
        if (contactWrapper->isVisible()) {
            contacts << contactWrapper;
        }
    }

    return contacts;
}

QString CDTpAccount::providerName() const
{
    Tp::ProfilePtr profile = mAccount->profile();
    if (profile != 0) {
        return profile->provider();
    }

    return mAccount->serviceName();
}

void CDTpAccount::firstTimeSeen()
{
    Q_FOREACH (const CDTpContactPtr &contactWrapper, mContacts.values()) {
        maybeRequestExtraInfo(contactWrapper->contact());
    }
    if (!mAccount->connection()) {
        mFirstSeen = true;
    }
}

void CDTpAccount::onAccountDisplayNameChanged()
{
    Q_EMIT changed(CDTpAccountPtr(this), DisplayName);
}

void CDTpAccount::onAccountNicknameChanged()
{
    Q_EMIT changed(CDTpAccountPtr(this), Nickname);
}

void CDTpAccount::onAccountCurrentPresenceChanged()
{
    Q_EMIT changed(CDTpAccountPtr(this), Presence);
}

void CDTpAccount::onAccountAvatarChanged()
{
    Q_EMIT changed(CDTpAccountPtr(this), Avatar);
}

void CDTpAccount::onAccountConnectionChanged(const Tp::ConnectionPtr &connection)
{
    debug() << "Account" << mAccount->objectPath() << "connection changed";

    setConnection(connection);

    Q_EMIT rosterChanged(CDTpAccountPtr(this));
}

void CDTpAccount::setConnection(const Tp::ConnectionPtr &connection)
{
    mContacts.clear();

    if (connection && connection->actualFeatures().contains(Tp::Connection::FeatureRoster)) {
        mHasRoster = true;

        Tp::ContactManagerPtr contactManager = connection->contactManager();
        connect(contactManager.data(),
                SIGNAL(allKnownContactsChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)),
                SLOT(onAllKnownContactsChanged(const Tp::Contacts &, const Tp::Contacts &)));

        Q_FOREACH (const Tp::ContactPtr &contact, contactManager->allKnownContacts()) {
            insertContact(contact);
            if (mFirstSeen) {
                maybeRequestExtraInfo(contact);
            }
        }
    } else {
        mHasRoster = false;
    }

    mFirstSeen = false;
}

void CDTpAccount::onAllKnownContactsChanged(const Tp::Contacts &contactsAdded,
        const Tp::Contacts &contactsRemoved)
{
    debug() << "Account" << mAccount->objectPath() << "roster contacts changed:";
    debug() << " " << contactsAdded.size() << "contacts added";
    debug() << " " << contactsRemoved.size() << "contacts removed";

    QList<CDTpContactPtr> added;
    Q_FOREACH (const Tp::ContactPtr &contact, contactsAdded) {
        if (mContacts.contains(contact->id())) {
            warning() << "Internal error, contact was already in roster";
            continue;
        }
        maybeRequestExtraInfo(contact);
        CDTpContactPtr contactWrapper = insertContact(contact);
        if (contactWrapper->isVisible()) {
            added << contactWrapper;
        }
    }

    QList<CDTpContactPtr> removed;
    Q_FOREACH (const Tp::ContactPtr &contact, contactsRemoved) {
        const QString id(contact->id());
        if (!mContacts.contains(id)) {
            warning() << "Internal error, contact is not in the internal list"
                "but was removed from roster";
            continue;
        }
        CDTpContactPtr contactWrapper = mContacts.take(id);
        if (contactWrapper->isVisible()) {
            removed << contactWrapper;
        }
        contactWrapper->setRemoved(true);
    }

    if (!added.isEmpty() || !removed.isEmpty()) {
        Q_EMIT rosterUpdated(CDTpAccountPtr(this), added, removed);
    }
}

void CDTpAccount::onAccountContactChanged(CDTpContactPtr contactWrapper,
        CDTpContact::Changes changes)
{
    if ((changes & CDTpContact::Visibility) != 0) {
        // Visibility of this contact changed. Transform this update operation
        // to an add/remove operation
        debug() << "Visibility changed for contact" << contactWrapper->contact()->id();
        if (contactWrapper->isVisible()) {
            Q_EMIT rosterUpdated(CDTpAccountPtr(this),
                QList<CDTpContactPtr>() << contactWrapper,
                QList<CDTpContactPtr>());
        } else {
            contactWrapper->setRemoved(true);
            Q_EMIT rosterUpdated(CDTpAccountPtr(this),
                QList<CDTpContactPtr>(),
                QList<CDTpContactPtr>() << contactWrapper);
        }

        return;
    }

    // Forward changes only if contact is visible
    if (contactWrapper->isVisible()) {
        Q_EMIT rosterContactChanged(contactWrapper, changes);
    }
}

CDTpContactPtr CDTpAccount::insertContact(const Tp::ContactPtr &contact)
{
    debug() << "  creating wrapper for contact" << contact->id();

    CDTpContactPtr contactWrapper = CDTpContactPtr(new CDTpContact(contact, this));
    connect(contactWrapper.data(),
            SIGNAL(changed(CDTpContactPtr, CDTpContact::Changes)),
            SLOT(onAccountContactChanged(CDTpContactPtr, CDTpContact::Changes)));
    mContacts.insert(contact->id(), contactWrapper);
    return contactWrapper;
}

void CDTpAccount::maybeRequestExtraInfo(Tp::ContactPtr contact)
{
    if (!contact->isAvatarTokenKnown()) {
        debug() << contact->id() << "first seen: request avatar";
        contact->requestAvatarData();
    }
    if (!contact->isContactInfoKnown()) {
        debug() << contact->id() << "first seen: refresh ContactInfo";
        contact->refreshInfo();
    }
}

CDTpContactPtr CDTpAccount::contact(const QString &id) const
{
    return mContacts.value(id);
}

<commit_msg>Add debug message when account connection change<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (people-users@projects.maemo.org)
**
** This file is part of contactsd.
**
** If you have questions regarding the use of this file, please contact
** Nokia at people-users@projects.maemo.org.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <TelepathyQt4/ContactManager>
#include <TelepathyQt4/PendingContacts>
#include <TelepathyQt4/PendingOperation>
#include <TelepathyQt4/PendingReady>
#include <TelepathyQt4/Profile>

#include "cdtpaccount.h"
#include "cdtpcontact.h"
#include "debug.h"

using namespace Contactsd;

CDTpAccount::CDTpAccount(const Tp::AccountPtr &account, QObject *parent)
    : QObject(parent),
      mAccount(account),
      mHasRoster(false),
      mFirstSeen(false)
{
    // connect all signals we care about, so we can signal that the account
    // changed accordingly
    connect(mAccount.data(),
            SIGNAL(displayNameChanged(const QString &)),
            SLOT(onAccountDisplayNameChanged()));
    connect(mAccount.data(),
            SIGNAL(nicknameChanged(const QString &)),
            SLOT(onAccountNicknameChanged()));
    connect(mAccount.data(),
            SIGNAL(currentPresenceChanged(const Tp::Presence &)),
            SLOT(onAccountCurrentPresenceChanged()));
    connect(mAccount.data(),
            SIGNAL(avatarChanged(const Tp::Avatar &)),
            SLOT(onAccountAvatarChanged()));
    connect(mAccount.data(),
            SIGNAL(connectionChanged(const Tp::ConnectionPtr &)),
            SLOT(onAccountConnectionChanged(const Tp::ConnectionPtr &)));

    setConnection(mAccount->connection());
}

CDTpAccount::~CDTpAccount()
{
}

QList<CDTpContactPtr> CDTpAccount::contacts() const
{
    QList<CDTpContactPtr> contacts;
    Q_FOREACH (const CDTpContactPtr &contactWrapper, mContacts) {
        if (contactWrapper->isVisible()) {
            contacts << contactWrapper;
        }
    }

    return contacts;
}

QString CDTpAccount::providerName() const
{
    Tp::ProfilePtr profile = mAccount->profile();
    if (profile != 0) {
        return profile->provider();
    }

    return mAccount->serviceName();
}

void CDTpAccount::firstTimeSeen()
{
    Q_FOREACH (const CDTpContactPtr &contactWrapper, mContacts.values()) {
        maybeRequestExtraInfo(contactWrapper->contact());
    }
    if (!mAccount->connection()) {
        mFirstSeen = true;
    }
}

void CDTpAccount::onAccountDisplayNameChanged()
{
    Q_EMIT changed(CDTpAccountPtr(this), DisplayName);
}

void CDTpAccount::onAccountNicknameChanged()
{
    Q_EMIT changed(CDTpAccountPtr(this), Nickname);
}

void CDTpAccount::onAccountCurrentPresenceChanged()
{
    Q_EMIT changed(CDTpAccountPtr(this), Presence);
}

void CDTpAccount::onAccountAvatarChanged()
{
    Q_EMIT changed(CDTpAccountPtr(this), Avatar);
}

void CDTpAccount::onAccountConnectionChanged(const Tp::ConnectionPtr &connection)
{
    debug() << "Account" << mAccount->objectPath() << "connection changed";

    setConnection(connection);

    Q_EMIT rosterChanged(CDTpAccountPtr(this));
}

void CDTpAccount::setConnection(const Tp::ConnectionPtr &connection)
{
    mContacts.clear();

    if (connection && connection->actualFeatures().contains(Tp::Connection::FeatureRoster)) {
        mHasRoster = true;

        debug() << "Got new roster for account" << mAccount->objectPath();
        Tp::ContactManagerPtr contactManager = connection->contactManager();
        connect(contactManager.data(),
                SIGNAL(allKnownContactsChanged(const Tp::Contacts &, const Tp::Contacts &, const Tp::Channel::GroupMemberChangeDetails &)),
                SLOT(onAllKnownContactsChanged(const Tp::Contacts &, const Tp::Contacts &)));

        Q_FOREACH (const Tp::ContactPtr &contact, contactManager->allKnownContacts()) {
            insertContact(contact);
            if (mFirstSeen) {
                maybeRequestExtraInfo(contact);
            }
        }
    } else {
        debug() << "Drop roster for account" << mAccount->objectPath() << " - has connection:" << (connection != 0);
        mHasRoster = false;
    }

    mFirstSeen = false;
}

void CDTpAccount::onAllKnownContactsChanged(const Tp::Contacts &contactsAdded,
        const Tp::Contacts &contactsRemoved)
{
    debug() << "Account" << mAccount->objectPath() << "roster contacts changed:";
    debug() << " " << contactsAdded.size() << "contacts added";
    debug() << " " << contactsRemoved.size() << "contacts removed";

    QList<CDTpContactPtr> added;
    Q_FOREACH (const Tp::ContactPtr &contact, contactsAdded) {
        if (mContacts.contains(contact->id())) {
            warning() << "Internal error, contact was already in roster";
            continue;
        }
        maybeRequestExtraInfo(contact);
        CDTpContactPtr contactWrapper = insertContact(contact);
        if (contactWrapper->isVisible()) {
            added << contactWrapper;
        }
    }

    QList<CDTpContactPtr> removed;
    Q_FOREACH (const Tp::ContactPtr &contact, contactsRemoved) {
        const QString id(contact->id());
        if (!mContacts.contains(id)) {
            warning() << "Internal error, contact is not in the internal list"
                "but was removed from roster";
            continue;
        }
        CDTpContactPtr contactWrapper = mContacts.take(id);
        if (contactWrapper->isVisible()) {
            removed << contactWrapper;
        }
        contactWrapper->setRemoved(true);
    }

    if (!added.isEmpty() || !removed.isEmpty()) {
        Q_EMIT rosterUpdated(CDTpAccountPtr(this), added, removed);
    }
}

void CDTpAccount::onAccountContactChanged(CDTpContactPtr contactWrapper,
        CDTpContact::Changes changes)
{
    if ((changes & CDTpContact::Visibility) != 0) {
        // Visibility of this contact changed. Transform this update operation
        // to an add/remove operation
        debug() << "Visibility changed for contact" << contactWrapper->contact()->id();
        if (contactWrapper->isVisible()) {
            Q_EMIT rosterUpdated(CDTpAccountPtr(this),
                QList<CDTpContactPtr>() << contactWrapper,
                QList<CDTpContactPtr>());
        } else {
            contactWrapper->setRemoved(true);
            Q_EMIT rosterUpdated(CDTpAccountPtr(this),
                QList<CDTpContactPtr>(),
                QList<CDTpContactPtr>() << contactWrapper);
        }

        return;
    }

    // Forward changes only if contact is visible
    if (contactWrapper->isVisible()) {
        Q_EMIT rosterContactChanged(contactWrapper, changes);
    }
}

CDTpContactPtr CDTpAccount::insertContact(const Tp::ContactPtr &contact)
{
    debug() << "  creating wrapper for contact" << contact->id();

    CDTpContactPtr contactWrapper = CDTpContactPtr(new CDTpContact(contact, this));
    connect(contactWrapper.data(),
            SIGNAL(changed(CDTpContactPtr, CDTpContact::Changes)),
            SLOT(onAccountContactChanged(CDTpContactPtr, CDTpContact::Changes)));
    mContacts.insert(contact->id(), contactWrapper);
    return contactWrapper;
}

void CDTpAccount::maybeRequestExtraInfo(Tp::ContactPtr contact)
{
    if (!contact->isAvatarTokenKnown()) {
        debug() << contact->id() << "first seen: request avatar";
        contact->requestAvatarData();
    }
    if (!contact->isContactInfoKnown()) {
        debug() << contact->id() << "first seen: refresh ContactInfo";
        contact->refreshInfo();
    }
}

CDTpContactPtr CDTpAccount::contact(const QString &id) const
{
    return mContacts.value(id);
}

<|endoftext|>