From 8b3e83d902298e446c3d659fd9b059984455a1d6 Mon Sep 17 00:00:00 2001 From: Yunzi Zhang <166091910+yzzhang11@users.noreply.github.com> Date: Thu, 23 May 2024 10:43:21 -0700 Subject: [PATCH] pre-app recommendation cobalt platform service reference code (#3277) b/325133487 b/342046135 (cherry picked from commit adf26ec7b7efc6df7f0847e410df0d9da560ceaa) --- .../pre-app-recommendation-demo.html | 125 ++++++++++++ starboard/linux/shared/BUILD.gn | 2 + starboard/linux/shared/platform_service.cc | 4 +- .../shared/pre_app_recommendation_service.cc | 193 ++++++++++++++++++ .../shared/pre_app_recommendation_service.h | 30 +++ 5 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 cobalt/demos/content/pre-app-recommendation-demo/pre-app-recommendation-demo.html create mode 100644 starboard/linux/shared/pre_app_recommendation_service.cc create mode 100644 starboard/linux/shared/pre_app_recommendation_service.h diff --git a/cobalt/demos/content/pre-app-recommendation-demo/pre-app-recommendation-demo.html b/cobalt/demos/content/pre-app-recommendation-demo/pre-app-recommendation-demo.html new file mode 100644 index 000000000000..1fd5827d4a18 --- /dev/null +++ b/cobalt/demos/content/pre-app-recommendation-demo/pre-app-recommendation-demo.html @@ -0,0 +1,125 @@ + + + + + + + diff --git a/starboard/linux/shared/BUILD.gn b/starboard/linux/shared/BUILD.gn index ef9228453e72..07daff0131ba 100644 --- a/starboard/linux/shared/BUILD.gn +++ b/starboard/linux/shared/BUILD.gn @@ -81,6 +81,8 @@ static_library("starboard_platform_sources") { "//starboard/linux/shared/platform_service.cc", "//starboard/linux/shared/platform_service.h", "//starboard/linux/shared/player_components_factory.cc", + "//starboard/linux/shared/pre_app_recommendation_service.cc", + "//starboard/linux/shared/pre_app_recommendation_service.h", "//starboard/linux/shared/routes.cc", "//starboard/linux/shared/routes.h", "//starboard/linux/shared/soft_mic_platform_service.cc", diff --git a/starboard/linux/shared/platform_service.cc b/starboard/linux/shared/platform_service.cc index 5962884169b9..f6423ae7bc1e 100644 --- a/starboard/linux/shared/platform_service.cc +++ b/starboard/linux/shared/platform_service.cc @@ -21,6 +21,7 @@ #include "starboard/common/log.h" #include "starboard/common/string.h" #include "starboard/configuration.h" +#include "starboard/linux/shared/pre_app_recommendation_service.h" #include "starboard/linux/shared/soft_mic_platform_service.h" #include "starboard/shared/starboard/application.h" #if SB_IS(EVERGREEN_COMPATIBLE) @@ -40,7 +41,8 @@ struct cmp_str { }; std::map platform_service_registry = { - {kSoftMicPlatformServiceName, GetSoftMicPlatformServiceApi}}; + {kSoftMicPlatformServiceName, GetSoftMicPlatformServiceApi}, + {kPreappRecommendationServiceName, GetPreappRecommendationServiceApi}}; bool Has(const char* name) { // Checks whether Cobalt platform service registry has service name diff --git a/starboard/linux/shared/pre_app_recommendation_service.cc b/starboard/linux/shared/pre_app_recommendation_service.cc new file mode 100644 index 000000000000..9700663a18b3 --- /dev/null +++ b/starboard/linux/shared/pre_app_recommendation_service.cc @@ -0,0 +1,193 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// 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 "starboard/linux/shared/pre_app_recommendation_service.h" + +#include +#include + +#include "starboard/common/log.h" +#include "starboard/common/string.h" +#include "starboard/configuration.h" +#include "starboard/linux/shared/platform_service.h" +#include "starboard/shared/starboard/application.h" + +// Omit namespace 'linux' due to symbol name conflict with macro 'linux' +namespace starboard { +namespace shared { +namespace { +typedef struct PreAppRecommendationsPlatformServiceImpl + : public PlatformServiceImpl { + // Define additional data field. + // variable_1, variable_2,... + PreAppRecommendationsPlatformServiceImpl( + void* context, + ReceiveMessageCallback receive_callback) + : PlatformServiceImpl(context, receive_callback) {} + + // Default constructor. + PreAppRecommendationsPlatformServiceImpl() = default; + +} PreAppRecommendationsPlatformServiceImpl; + +// Use HTTP status code in response to YouTube application's method recommend +// call. +const char kSuccess[] = "200"; +const char kBadRequest[] = "400"; +// Methods supported +const char kGetPartnerIdMethod[] = "getPartnerId"; +const char kRecommendMethod[] = "recommend"; +// Operations supported +const char kUpsertOp[] = "upsert"; +const char kDeleteOp[] = "delete"; +// Configure partner Id +const char kPartnerId[] = "dummy_partner_id"; + +bool Has(const char* name) { + // Check if platform has service name. + return strcmp(name, kPreappRecommendationServiceName) == 0; +} + +PlatformServiceImpl* Open(void* context, + ReceiveMessageCallback receive_callback) { + SB_DCHECK(context); + SB_LOG(INFO) << "Open() service created: " + << kPreappRecommendationServiceName; + + return new PreAppRecommendationsPlatformServiceImpl(context, + receive_callback); +} + +void Close(PlatformServiceImpl* service) { + // Function Close shouldn't manually delete PlatformServiceImpl pointer, + // because it is managed by unique_ptr in Platform Service. + SB_LOG(INFO) + << kPreappRecommendationServiceName + << " Perform actions before gracefully shutting down the service"; +} + +std::string extractJsonValue(const std::string& jsonLikeString, + const std::string& key) { + std::string result; + std::size_t start = jsonLikeString.find("\"" + key + "\""); + + if (start != std::string::npos) { + start = jsonLikeString.find(":", start); + if (start != std::string::npos) { + start = jsonLikeString.find_first_of("\"", start); + if (start != std::string::npos) { + ++start; // Skip the opening quote + std::size_t end = jsonLikeString.find("\"", start); + if (end != std::string::npos) { + result = jsonLikeString.substr(start, end - start); + } + } + } + } + + return result; +} + +void* Send(PlatformServiceImpl* service, + void* data, + uint64_t length, + uint64_t* output_length, + bool* invalid_state) { + SB_DCHECK(service); + SB_DCHECK(data); + SB_DCHECK(output_length); + + char message[length + 1]; + std::memcpy(message, data, length); + message[length] = '\0'; + + std::string response = ""; + + // TODO: Replace extractJsonValue function with a robust JSON parsing + // library for production use. The current implementation has limited + // capabilities that nested object isn't supported. + std::string method_name = extractJsonValue(message, "method"); + + if (method_name.length() == 0) { + SB_LOG(ERROR) << "Could not extract method value from the input JSON file:" + << message; + } + + // When method_name = getPartnerId, platform returns partner Id to get + // authenticated by YouTube app. + if (method_name == kGetPartnerIdMethod) { + // Populate Partner Id in the response. + // Partner Id will be used by YouTube app to authenticate platforms and + // retrieve specified topics for a platform. + // auto partner_id = "\"dummmy_partner_id\""; + response = FormatString("{\"partner_id\": \"%s\"}", kPartnerId); + } + + // When method_name = recommend, platform processes data according to + // operation field. + if (method_name == kRecommendMethod) { + std::string operation = extractJsonValue(message, "operation"); + if (operation.length() != 0) { + // When operation = upsert, platform parses recs_response field and + // insert/update data in local storage. + if (operation == kUpsertOp) { + std::string recs_response = extractJsonValue(message, "recs_response"); + + if (recs_response.length() != 0) { + // Store recommendations data in the local storage, such as local + // database or local filesystem. + SB_LOG(INFO) << "operation = " << operation + << ", parse recs_response and store data locally"; + } else { + SB_LOG(ERROR) + << "Could not extract recsResponse from the input JSON file:" + << message; + } + } else if (operation == kDeleteOp) { + // When operation = delete, platform delete YouTube data in local + // storage. + SB_LOG(INFO) << "operation = " << operation + << ", data in local storage is deleted"; + } + // Populate response with 200 to indicate data is processed + // successfully. + response = kSuccess; + } else { + // Populate response with error code if data isn't processed successfully. + response = kBadRequest; + } + } + + *output_length = response.length(); + auto ptr = malloc(*output_length); + response.copy(reinterpret_cast(ptr), response.length()); + return ptr; +} + +const CobaltPlatformServiceApi kGetPreappRecommendationServiceApi = { + kPreappRecommendationServiceName, + 1, // API version that's implemented. + &Has, + &Open, + &Close, + &Send}; + +} // namespace + +const void* GetPreappRecommendationServiceApi() { + return &kGetPreappRecommendationServiceApi; +} + +} // namespace shared +} // namespace starboard diff --git a/starboard/linux/shared/pre_app_recommendation_service.h b/starboard/linux/shared/pre_app_recommendation_service.h new file mode 100644 index 000000000000..33b17cb9e4e8 --- /dev/null +++ b/starboard/linux/shared/pre_app_recommendation_service.h @@ -0,0 +1,30 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// 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. + +#ifndef STARBOARD_LINUX_SHARED_PRE_APP_RECOMMENDATION_SERVICE_H_ +#define STARBOARD_LINUX_SHARED_PRE_APP_RECOMMENDATION_SERVICE_H_ + +// Omit namespace 'linux' due to symbol name conflict with macro 'linux' +namespace starboard { +namespace shared { + +const char* const kPreappRecommendationServiceName = + "com.google.youtube.tv.Recommendations"; + +const void* GetPreappRecommendationServiceApi(); + +} // namespace shared +} // namespace starboard + +#endif // STARBOARD_LINUX_SHARED_PRE_APP_RECOMMENDATION_SERVICE_H_