Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: addons only be loaded from the file system if they are explicitly specified in the app's manifest.json #320

Merged
merged 1 commit into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/include/ten_runtime/binding/cpp/internal/addon.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class extension_addon_t : public addon_t {
g_##NAME##_default_extension_group_addon->get_c_addon()); \
ten_string_destroy(base_dir); \
} \
TEN_DESTRUCTOR(____dtor_ten_declare_##NAME##_##TYPE##_addon____) { \
TEN_DESTRUCTOR(____dtor_ten_declare_##NAME##_extension_group_addon____) { \
ten_addon_unregister_extension_group(#NAME); \
delete g_##NAME##_default_extension_group_addon; \
}
Expand Down Expand Up @@ -279,7 +279,7 @@ class extension_addon_t : public addon_t {
g_##NAME##_default_extension_addon->get_c_addon()); \
ten_string_destroy(base_dir); \
} \
TEN_DESTRUCTOR(____dtor_ten_declare_##NAME##_##TYPE##_addon____) { \
TEN_DESTRUCTOR(____dtor_ten_declare_##NAME##_extension_addon____) { \
ten_addon_unregister_extension(#NAME); \
delete g_##NAME##_default_extension_addon; \
}
6 changes: 3 additions & 3 deletions core/include_internal/ten_runtime/addon/addon_autoload.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@

typedef struct ten_app_t ten_app_t;

TEN_RUNTIME_PRIVATE_API void ten_addon_load_from_path(const char *path);

TEN_RUNTIME_PRIVATE_API bool ten_addon_load_all_from_app_base_dir(
ten_app_t *app, ten_error_t *err);
ten_app_t *app, ten_list_t *extension_dependencies,
ten_list_t *extension_group_dependencies, ten_list_t *protocol_dependencies,
ten_error_t *err);

TEN_RUNTIME_PRIVATE_API bool ten_addon_load_all_from_ten_package_base_dirs(
ten_app_t *app, ten_error_t *err);
2 changes: 1 addition & 1 deletion core/include_internal/ten_runtime/app/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ typedef struct ten_app_t {
ten_metadata_info_t *manifest_info;
ten_metadata_info_t *property_info;

ten_list_t predefined_graph_infos;
ten_list_t predefined_graph_infos; // ten_predefined_graph_info_t*

ten_app_on_configure_func_t on_configure;
ten_app_on_init_func_t on_init;
Expand Down
19 changes: 19 additions & 0 deletions core/include_internal/ten_runtime/metadata/manifest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Copyright © 2024 Agora
// This file is part of TEN Framework, an open source project.
// Licensed under the Apache License, Version 2.0, with certain conditions.
// Refer to the "LICENSE" file in the root directory for more information.
//
#include "ten_runtime/ten_config.h"

#include "ten_utils/lib/string.h"
#include "ten_utils/value/value.h"

TEN_RUNTIME_PRIVATE_API void
ten_manifest_dependencies_get_dependencies_type_and_name(
ten_value_t *manifest_dependencies, ten_list_t *extension_list,
ten_list_t *extension_group_list, ten_list_t *protocol_list);

TEN_RUNTIME_PRIVATE_API void ten_manifest_get_dependencies_type_and_name(
ten_value_t *manifest, ten_list_t *extension_list,
ten_list_t *extension_group_list, ten_list_t *protocol_list);
22 changes: 22 additions & 0 deletions core/include_internal/ten_runtime/ten_env/metadata_cb.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ typedef struct ten_value_t ten_value_t;
typedef struct ten_extension_t ten_extension_t;
typedef struct ten_extension_group_t ten_extension_group_t;

typedef void (*ten_env_peek_manifest_async_cb_t)(ten_env_t *ten_env,
ten_value_t *value,
void *cb_data,
ten_error_t *err);

typedef struct ten_peek_manifest_sync_context_t {
ten_value_t *res;
ten_event_t *completed;
Expand All @@ -39,6 +44,23 @@ typedef struct ten_env_peek_property_sync_context_t {
ten_event_t *completed;
} ten_env_peek_property_sync_context_t;

typedef struct ten_env_peek_manifest_async_context_t {
ten_env_t *ten_env;
ten_env_peek_manifest_async_cb_t cb;
void *cb_data;
ten_value_t *res;

union {
ten_extension_t *extension;
ten_extension_group_t *extension_group;
} from;
} ten_env_peek_manifest_async_context_t;

typedef struct ten_env_peek_manifest_sync_context_t {
ten_value_t *res;
ten_event_t *completed;
} ten_env_peek_manifest_sync_context_t;

typedef struct ten_env_set_property_async_context_t {
ten_env_t *ten_env;
ten_env_set_property_async_cb_t cb;
Expand Down
53 changes: 37 additions & 16 deletions core/src/ten_runtime/addon/addon_autoload.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ static void ten_addon_load_from_base_dir(const char *path) {
ten_string_deinit(&self);
}

static void load_all_dynamic_libraries(const char *path) {
static void load_all_dynamic_libraries(const char *path,
ten_list_t *dependencies) {
ten_string_t *cur = NULL;
ten_string_t *short_name = NULL;
ten_string_t *self = NULL;
Expand Down Expand Up @@ -175,6 +176,28 @@ static void load_all_dynamic_libraries(const char *path) {
goto continue_loop;
}

// Check if short_name is in dependencies list.
bool should_load = false;
if (dependencies) {
// Iterate over dependencies and check if short_name matches any.
ten_list_foreach (dependencies, dep_iter) {
ten_string_t *dep_name = ten_str_listnode_get(dep_iter.node);
if (ten_string_is_equal(short_name, dep_name)) {
should_load = true;
break;
}
}
} else {
// If dependencies list is NULL, we load all addons.
should_load = true;
}

if (!should_load) {
TEN_LOGI("Skipping addon '%s' as it's not in dependencies.",
ten_string_get_raw_str(short_name));
goto continue_loop;
}

cur = ten_path_itor_get_full_name(itor);
if (!cur) {
TEN_LOGE("Failed to get full name under path: %s", path);
Expand Down Expand Up @@ -216,16 +239,10 @@ static void load_all_dynamic_libraries(const char *path) {
}
}

typedef struct addon_folder_t {
const char *path;
} addon_folder_t;

void ten_addon_load_from_path(const char *path) {
TEN_ASSERT(path, "Invalid argument.");
load_all_dynamic_libraries(path);
}

bool ten_addon_load_all_from_app_base_dir(ten_app_t *app, ten_error_t *err) {
bool ten_addon_load_all_from_app_base_dir(
ten_app_t *app, ten_list_t *extension_dependencies,
ten_list_t *extension_group_dependencies, ten_list_t *protocol_dependencies,
ten_error_t *err) {
TEN_ASSERT(app && ten_app_check_integrity(app, true), "Invalid argument.");

bool success = true;
Expand Down Expand Up @@ -255,10 +272,13 @@ bool ten_addon_load_all_from_app_base_dir(ten_app_t *app, ten_error_t *err) {
AddDllDirectory(ten_string_get_raw_str(app_lib_path));
#endif

static const addon_folder_t folders[] = {
{"/ten_packages/extension"},
{"/ten_packages/extension_group"},
{"/ten_packages/protocol"},
struct {
const char *path;
ten_list_t *dependencies;
} folders[] = {
{"/ten_packages/extension", extension_dependencies},
{"/ten_packages/extension_group", extension_group_dependencies},
{"/ten_packages/protocol", protocol_dependencies},
};

for (int i = 0; i < sizeof(folders) / sizeof(folders[0]); i++) {
Expand All @@ -280,7 +300,8 @@ bool ten_addon_load_all_from_app_base_dir(ten_app_t *app, ten_error_t *err) {
// The modules (e.g., extensions/protocols) do not exist if only the TEN
// app has been installed.
if (ten_path_exists(ten_string_get_raw_str(&module_path))) {
load_all_dynamic_libraries(ten_string_get_raw_str(&module_path));
load_all_dynamic_libraries(ten_string_get_raw_str(&module_path),
folders[i].dependencies);
}
} while (0);

Expand Down
23 changes: 21 additions & 2 deletions core/src/ten_runtime/app/ten_env/on_xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "include_internal/ten_runtime/app/predefined_graph.h"
#include "include_internal/ten_runtime/common/constant_str.h"
#include "include_internal/ten_runtime/extension_group/builtin/builtin_extension_group.h"
#include "include_internal/ten_runtime/metadata/manifest.h"
#include "include_internal/ten_runtime/metadata/metadata.h"
#include "include_internal/ten_runtime/metadata/metadata_info.h"
#include "include_internal/ten_runtime/protocol/close.h"
Expand Down Expand Up @@ -136,7 +137,7 @@ void ten_app_on_configure_done(ten_env_t *ten_env) {
}

if (!ten_app_handle_ten_namespace_properties(self)) {
TEN_LOGW("App determine default prop failed! \n");
TEN_LOGW("Failed to determine app default property.");
}

ten_metadata_init_schema_store(&self->manifest, &self->schema_store);
Expand All @@ -147,9 +148,27 @@ void ten_app_on_configure_done(ten_env_t *ten_env) {
strlen(TEN_STR_LOCALHOST));
}

ten_addon_load_all_from_app_base_dir(self, &err);
ten_list_t extension_dependencies;
ten_list_t extension_group_dependencies;
ten_list_t protocol_dependencies;

ten_list_init(&extension_dependencies);
ten_list_init(&extension_group_dependencies);
ten_list_init(&protocol_dependencies);

ten_manifest_get_dependencies_type_and_name(
&self->manifest, &extension_dependencies, &extension_group_dependencies,
&protocol_dependencies);

ten_addon_load_all_from_app_base_dir(self, &extension_dependencies,
&extension_group_dependencies,
&protocol_dependencies, &err);
ten_addon_load_all_from_ten_package_base_dirs(self, &err);

ten_list_clear(&extension_dependencies);
ten_list_clear(&extension_group_dependencies);
ten_list_clear(&protocol_dependencies);

if (!ten_app_get_predefined_graphs_from_property(self)) {
goto error;
}
Expand Down
83 changes: 83 additions & 0 deletions core/src/ten_runtime/metadata/manifest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//
// Copyright © 2024 Agora
// This file is part of TEN Framework, an open source project.
// Licensed under the Apache License, Version 2.0, with certain conditions.
// Refer to the "LICENSE" file in the root directory for more information.
//
#include "include_internal/ten_runtime/metadata/manifest.h"

#include "ten_utils/log/log.h"

void ten_manifest_dependencies_get_dependencies_type_and_name(
ten_value_t *manifest_dependencies, ten_list_t *extension_list,
ten_list_t *extension_group_list, ten_list_t *protocol_list) {
TEN_ASSERT(manifest_dependencies,
"Invalid argument: manifest_dependencies is NULL.");
TEN_ASSERT(ten_value_check_integrity(manifest_dependencies),
"Invalid manifest_dependencies value.");
// Ensure that "dependencies" is an array.
TEN_ASSERT(ten_value_is_array(manifest_dependencies),
"The 'dependencies' field should be an array.");
TEN_ASSERT(extension_list, "Invalid argument: extension_list is NULL.");
TEN_ASSERT(extension_group_list,
"Invalid argument: extension_group_list is NULL.");
TEN_ASSERT(protocol_list, "Invalid argument: protocol_list is NULL.");

// Iterate over each dependency in the array.
ten_value_array_foreach(manifest_dependencies, iter) {
ten_value_t *dep = ten_ptr_listnode_get(iter.node);
TEN_ASSERT(dep, "Dependency is NULL.");
TEN_ASSERT(ten_value_check_integrity(dep), "Invalid dependency value.");
TEN_ASSERT(ten_value_is_object(dep),
"Each dependency should be an object.");

// Get the "type" field of the dependency.
ten_value_t *type_value = ten_value_object_peek(dep, "type");
TEN_ASSERT(type_value, "Dependency missing 'type' field.");
TEN_ASSERT(ten_value_is_string(type_value),
"The 'type' field should be a string.");
ten_string_t *type_str = ten_value_peek_string(type_value);

// Get the "name" field of the dependency.
ten_value_t *name_value = ten_value_object_peek(dep, "name");
TEN_ASSERT(name_value, "Dependency missing 'name' field.");
TEN_ASSERT(ten_value_is_string(name_value),
"The 'name' field should be a string.");
ten_string_t *name_str = ten_value_peek_string(name_value);
const char *name_cstr = ten_string_get_raw_str(name_str);

// Add the dependency name to the appropriate list based on its type.
if (ten_string_is_equal_c_str(type_str, "extension")) {
TEN_LOGI("Collect extension dependency: %s", name_cstr);
ten_list_push_str_back(extension_list, name_cstr);
} else if (ten_string_is_equal_c_str(type_str, "extension_group")) {
TEN_LOGI("Collect extension_group dependency: %s", name_cstr);
ten_list_push_str_back(extension_group_list, name_cstr);
} else if (ten_string_is_equal_c_str(type_str, "protocol")) {
TEN_LOGI("Collect protocol dependency: %s", name_cstr);
ten_list_push_str_back(protocol_list, name_cstr);
}
}
}

void ten_manifest_get_dependencies_type_and_name(
ten_value_t *manifest, ten_list_t *extension_list,
ten_list_t *extension_group_list, ten_list_t *protocol_list) {
TEN_ASSERT(manifest, "Invalid argument: manifest is NULL.");
TEN_ASSERT(extension_list, "Invalid argument: extension_list is NULL.");
TEN_ASSERT(extension_group_list,
"Invalid argument: extension_group_list is NULL.");
TEN_ASSERT(protocol_list, "Invalid argument: protocol_list is NULL.");
TEN_ASSERT(ten_value_check_integrity(manifest), "Invalid manifest value.");
TEN_ASSERT(ten_value_is_object(manifest), "Manifest should be an object.");

// Retrieve the "dependencies" field from the manifest.
ten_value_t *dependencies = ten_value_object_peek(manifest, "dependencies");
if (!dependencies) {
// No dependencies found; nothing to do.
return;
}

ten_manifest_dependencies_get_dependencies_type_and_name(
dependencies, extension_list, extension_group_list, protocol_list);
}
Loading
Loading