Skip to content

Commit

Permalink
Google Sign In Support (#193)
Browse files Browse the repository at this point in the history
-Basic Google Sign In support. Will run the flutter
 packages google_sign_in example project
-To build static plugin add CMake build flag
 -DBUILD_PLUGIN_GOOGLE_SIGN_IN=ON
-runtime library dependency is libcurl

Signed-off-by: Joel Winarske <joel.winarske@woven-planet.global>
  • Loading branch information
Joel Winarske authored and GitHub Enterprise committed Oct 14, 2023
1 parent 786387a commit 0e4661b
Show file tree
Hide file tree
Showing 11 changed files with 1,340 additions and 32 deletions.
6 changes: 6 additions & 0 deletions cmake/plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,10 @@ if (BUILD_PLUGIN_KEYBOARD_MANAGER)
ENABLE_PLUGIN(keyboard_manager)
endif ()

option(BUILD_PLUGIN_GOOGLE_SIGN_IN "Include Google Sign In manager" OFF)
if (BUILD_PLUGIN_GOOGLE_SIGN_IN)
ENABLE_PLUGIN(google_sign_in)
pkg_check_modules(LIBCURL REQUIRED libcurl)
endif ()

message(STATUS "Plugin Config .......... ${PLUGINS}")
7 changes: 7 additions & 0 deletions shell/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ add_executable(homescreen
app.cc
configuration/configuration.cc
engine.cc
json_utils.cc
main.cc
platform_channel.cc
textures/texture.cc
Expand Down Expand Up @@ -64,6 +65,10 @@ if (BUILD_CRASH_HANDLER)
target_sources(homescreen PRIVATE crash_handler.cc)
endif ()

if (BUILD_PLUGIN_GOOGLE_SIGN_IN)
target_sources(homescreen PRIVATE curl_client/curl_client.cc)
endif ()

target_compile_definitions(homescreen
PRIVATE
HAVE_STRCHRNUL
Expand All @@ -89,6 +94,7 @@ target_include_directories(homescreen
${GLIB2_INCLUDE_DIRS}
${GST_INCLUDE_DIRS}
${GST_VIDEO_INCLUDE_DIRS}
${LIBCURL_INCLUDE_DIRS}
${AVFORMAT_INCLUDE_DIRS}
${PLUGIN_SECURE_STORAGE_INCLUDE_DIRS}
../third_party/spdlog-1.12.0/include
Expand All @@ -115,6 +121,7 @@ target_link_libraries(homescreen PRIVATE
dl
${GST_LIBRARIES}
${GST_VIDEO_LIBRARIES}
${LIBCURL_LIBRARIES}
${AVFORMAT_LIBRARIES}
${PLUGIN_SECURE_STORAGE_LINK_LIBRARIES}
)
Expand Down
126 changes: 126 additions & 0 deletions shell/curl_client/curl_client.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright 2023 Toyota Connected North America
*
* 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 "curl_client.h"

#include "logging.h"

CurlClient::CurlClient() {
curl_global_init(CURL_GLOBAL_DEFAULT);
std::make_unique<char>(CURL_ERROR_SIZE);
}

CurlClient::~CurlClient() {
curl_easy_cleanup(mConn);
mErrorBuffer.reset();
}

int CurlClient::Writer(char* data,
size_t size,
size_t num_mem_block,
std::string* writerData) {
writerData->append(data, size * num_mem_block);
return static_cast<int>(size * num_mem_block);
}

bool CurlClient::Init(
std::string& url,
std::vector<std::string>& headers,
std::vector<std::pair<std::string, std::string>>& url_form,
bool follow_location) {
mCode = CURLE_OK;
mBuffer.clear();

mConn = curl_easy_init();
if (mConn == nullptr) {
spdlog::error("[CurlClient] Failed to create CURL connection");
return false;
}

mCode = curl_easy_setopt(mConn, CURLOPT_ERRORBUFFER, mErrorBuffer.get());
if (mCode != CURLE_OK) {
spdlog::error("[CurlClient] Failed to set error buffer [{}]", static_cast<int>(mCode));
return false;
}

mUrl = url;
spdlog::trace("[CurlClient] URL: {}", mUrl);

mCode = curl_easy_setopt(mConn, CURLOPT_URL, mUrl.c_str());
if (mCode != CURLE_OK) {
spdlog::error("[CurlClient] Failed to set URL [{}]", mErrorBuffer.get());
return false;
}

if (!url_form.empty()) {
mPostFields.clear();
int count = 0;
for (auto& item : url_form) {
if (count) {
mPostFields += "&";
}
mPostFields.append(item.first + "=" + item.second);
count++;
}
spdlog::trace("[CurlClient] PostFields: {}", mPostFields);
curl_easy_setopt(mConn, CURLOPT_POSTFIELDSIZE, mPostFields.length());
// libcurl does not copy
curl_easy_setopt(mConn, CURLOPT_POSTFIELDS, mPostFields.c_str());
}

if (!headers.empty()) {
struct curl_slist* curl_headers{};
for (auto& header : headers) {
spdlog::trace("[CurlClient] Header: {}", header);
curl_headers = curl_slist_append(curl_headers, header.c_str());
}
mCode = curl_easy_setopt(mConn, CURLOPT_HTTPHEADER, curl_headers);
if (mCode != CURLE_OK) {
spdlog::error("[CurlClient] Failed to set headers option [{}]", mErrorBuffer.get());
return false;
}
}

mCode = curl_easy_setopt(mConn, CURLOPT_FOLLOWLOCATION, follow_location ? 1L : 0L);
if (mCode != CURLE_OK) {
spdlog::error("[CurlClient] Failed to set redirect option [{}]", mErrorBuffer.get());
return false;
}

mCode = curl_easy_setopt(mConn, CURLOPT_WRITEFUNCTION, Writer);
if (mCode != CURLE_OK) {
spdlog::error("[CurlClient] Failed to set writer [{}]", mErrorBuffer.get());
return false;
}

mCode = curl_easy_setopt(mConn, CURLOPT_WRITEDATA, &mBuffer);
if (mCode != CURLE_OK) {
spdlog::error("[CurlClient] Failed to set write data [{}]", mErrorBuffer.get());
return false;
}

return true;
}

std::string CurlClient::RetrieveContent(bool verbose) {
curl_easy_setopt(mConn, CURLOPT_VERBOSE, verbose ? 1L : 0L);
mCode = curl_easy_perform(mConn);
if (mCode != CURLE_OK) {
spdlog::error("[CurlClient] Failed to get '{}' [{}]\n", mUrl, mErrorBuffer.get());
return {};
}
return mBuffer;
}
87 changes: 87 additions & 0 deletions shell/curl_client/curl_client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2023 Toyota Connected North America
*
* 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.
*/

#pragma once

#include <memory>
#include <sstream>
#include <vector>

#include <curl/curl.h>

class CurlClient {
public:
CurlClient();
~CurlClient();

/**
* @brief Initialization Function
* @param headers vector of headers to use
* @param url_form url form key/values
* @param follow_location follows redirects from server. Defaults to true
* @return bool
* @retval true if initialized, false if failed
* @relation
* google_sign_in
*/
bool Init(std::string& url,
std::vector<std::string>& headers,
std::vector<std::pair<std::string, std::string>>& url_form,
bool follow_location = true);

/**
* @brief Function to execute http client
* @param verbose flag to enable stderr output of curl dialog
* @return std::string
* @retval body response of client request
* @relation
* google_sign_in
*/
std::string RetrieveContent(bool verbose = false);

/**
* @brief Function to return last curl response code
* @return CURLcode
* @retval the last response code. Used to check response state
* @relation
* google_sign_in
*/
CURLcode GetCode() { return mCode; }

private:
CURL* mConn;
CURLcode mCode;
std::string mUrl;
std::string mPostFields;
std::unique_ptr<char> mErrorBuffer;
std::string mBuffer;

/**
* @brief Callback function for curl client
* @param data buffer of response
* @param size length of buffer
* @param num_mem_block number of memory blocks
* @param writerData user pointer
* @return int
* @retval returns back to curl size of write
* @relation
* google_sign_in
*/
static int Writer(char* data,
size_t size,
size_t num_mem_block,
std::string* writerData);
};
96 changes: 96 additions & 0 deletions shell/json_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2023 Toyota Connected North America
*
* 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 "json_utils.h"

#include <filesystem>
#include <fstream>

#include <rapidjson/filewritestream.h>
#include <rapidjson/istreamwrapper.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>

#include "logging.h"

rapidjson::Document JsonUtils::GetJsonDocumentFromFile(std::string& path,
bool missing_is_error) {
rapidjson::Document d{};
if (std::filesystem::exists(path)) {
std::ifstream ifs{path};
if (!ifs.is_open()) {
if (missing_is_error) {
d.Parse("{}");
spdlog::error("Failed to open file for reading: {}", path);
}
return std::move(d);
}
rapidjson::IStreamWrapper isw{ifs};
d.ParseStream(isw);
} else {
d.SetObject();
if (missing_is_error) {
spdlog::error("File missing: {}", path);
}
}
return std::move(d);
}

bool JsonUtils::WriteJsonDocumentToFile(std::string& path,
rapidjson::Document& doc) {
if (path.empty()) {
spdlog::error("Missing File Path: {}", path);
return false;
}

if (!std::filesystem::exists(path)) {
std::filesystem::path p(path);
std::filesystem::create_directories(p.parent_path());
}

FILE* fp = fopen(path.c_str(), "w+");
if (fp == nullptr) {
spdlog::error("Failed to open file: {}", path);
return false;
}

const auto bufSize = 1024;
auto buffer = std::make_unique<char[]>(bufSize);
rapidjson::FileWriteStream os(fp, buffer.get(), bufSize);
rapidjson::PrettyWriter<rapidjson::FileWriteStream> writer(os);
doc.Accept(writer);

fclose(fp);
buffer.reset();

return true;
}

bool JsonUtils::AddEmptyKeyToFile(std::string& path, const char* key) {
auto d = JsonUtils::GetJsonDocumentFromFile(path, false);
auto& allocator = d.GetAllocator();
auto obj = d.GetObject();
if (obj.HasMember(key)) {
obj[key] = "";
} else {
rapidjson::Value k(key, allocator);
rapidjson::Value v("", allocator);
obj.AddMember(k, v, allocator);
}

// flush to disk
return WriteJsonDocumentToFile(path, d);
}
Loading

0 comments on commit 0e4661b

Please sign in to comment.