Skip to content

Commit

Permalink
feat: runtime check graph (#165)
Browse files Browse the repository at this point in the history
* feat: check graph in ten_runtime

---------

Co-authored-by: Hu Yueh-Wei <[email protected]>
  • Loading branch information
leoadonia and halajohn authored Oct 17, 2024
1 parent 5781bb3 commit 888a918
Show file tree
Hide file tree
Showing 52 changed files with 1,498 additions and 64 deletions.
15 changes: 9 additions & 6 deletions build/ten_runtime/feature/test.gni
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ template("ten_package_test_prepare_app") {
app_run_root_dir = "${test_case_root_dir}/${_target_name}"

install_app_dummy_output_file =
"${target_gen_dir}/install_app_dummy_output_file"
"${target_gen_dir}/${_target_name}/install_app_dummy_output_file"
install_app_depfile = "${target_gen_dir}/install_app_depfile"

action("${test_case_unique_target_name}_${_target_name}_install_app") {
Expand Down Expand Up @@ -168,7 +168,7 @@ template("ten_package_test_prepare_app") {
}

install_all_dummy_output_file =
"${target_gen_dir}/install_all_dummy_output_file"
"${target_gen_dir}/${_target_name}/install_all_dummy_output_file"

action("${test_case_unique_target_name}_${_target_name}_install_all") {
script = "//build/ten_runtime/feature/install_all.py"
Expand Down Expand Up @@ -290,7 +290,8 @@ template("ten_package_test_prepare_app") {
}

# App building phase.
build_app_dummy_output_file = "${target_gen_dir}/build_app_dummy_output_file"
build_app_dummy_output_file =
"${target_gen_dir}/${_target_name}/build_app_dummy_output_file"

action("${test_case_unique_target_name}_${_target_name}_build") {
script = "//build/ten_runtime/feature/build_pkg.py"
Expand Down Expand Up @@ -543,7 +544,7 @@ template("ten_package_standalone_pkg") {
pkg_root_dir = "${test_case_root_dir}/${_target_name}"

install_standalone_dummy_output_file =
"${target_gen_dir}/install_standalone_dummy_output_file"
"${target_gen_dir}/${_target_name}/install_standalone_dummy_output_file"
install_standalone_depfile = "${target_gen_dir}/install_standalone_depfile"

action("${test_case_unique_target_name}_${_target_name}_install_pkg") {
Expand Down Expand Up @@ -624,7 +625,8 @@ template("ten_package_standalone_pkg") {
]
}

install_all_dummy_output_file = "${target_gen_dir}/install_dummy_output_file"
install_all_dummy_output_file =
"${target_gen_dir}/${_target_name}/install_dummy_output_file"

# Install dependencies of the standalone package.
action("${test_case_unique_target_name}_${_target_name}_install") {
Expand Down Expand Up @@ -689,7 +691,8 @@ template("ten_package_standalone_pkg") {
}

# Build this standalone package.
build_pkg_dummy_output_file = "${target_gen_dir}/build_pkg_dummy_output_file"
build_pkg_dummy_output_file =
"${target_gen_dir}/${_target_name}/build_pkg_dummy_output_file"

action("${test_case_unique_target_name}_${_target_name}_build") {
script = "//build/ten_runtime/feature/build_pkg.py"
Expand Down
19 changes: 19 additions & 0 deletions core/include_internal/ten_runtime/app/graph.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.
//
#pragma once

#include "ten_runtime/ten_config.h"

#include <stdbool.h>

#include "ten_utils/lib/error.h"
#include "ten_utils/lib/json.h"

typedef struct ten_app_t ten_app_t;

TEN_RUNTIME_PRIVATE_API bool ten_app_check_start_graph_cmd_json(
ten_app_t *self, ten_json_t *start_graph_cmd_json, ten_error_t *err);
2 changes: 2 additions & 0 deletions core/src/ten_runtime/app/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ glob("app") {
"msg_interface",
"ten_env",
]

public_deps = [ "//core/src/ten_rust:ten_rust_binding" ]
}
51 changes: 51 additions & 0 deletions core/src/ten_runtime/app/graph.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// 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/app/graph.h"

#include "include_internal/ten_runtime/app/app.h"
#include "include_internal/ten_runtime/app/base_dir.h"
#include "include_internal/ten_runtime/common/constant_str.h"
#include "include_internal/ten_rust/ten_rust.h"
#include "ten_runtime/app/app.h"
#include "ten_utils/macro/memory.h"

bool ten_app_check_start_graph_cmd_json(ten_app_t *self,
ten_json_t *start_graph_cmd_json,
ten_error_t *err) {
TEN_ASSERT(self && ten_app_check_integrity(self, true), "Should not happen.");
TEN_ASSERT(start_graph_cmd_json, "Invalid argument.");

const char *base_dir = ten_app_get_base_dir(self);

// The pkg_info of extensions in the graph is read from the ten_packages
// directory under the base dir of app. If the base dir is not set, the app
// might be running in a thread, ex: the smoke testing. In this case, we can
// not retrieve the enough information to check the graph.
if (!base_dir || ten_c_string_is_empty(base_dir)) {
TEN_LOGD("The base dir of app [%s] is not set, skip checking graph.",
ten_app_get_uri(self));
return true;
}

bool free_json_string = false;
const char *graph_json_str = ten_json_to_string(
start_graph_cmd_json, TEN_STR_UNDERLINE_TEN, &free_json_string);

const char *err_msg = NULL;
bool rc = ten_rust_check_graph_for_app(base_dir, graph_json_str, &err_msg);

if (free_json_string) {
TEN_FREE(graph_json_str);
}

if (!rc) {
ten_error_set(err, TEN_ERRNO_INVALID_GRAPH, err_msg);
ten_rust_free_cstring(err_msg);
}

return rc;
}
46 changes: 46 additions & 0 deletions core/src/ten_runtime/app/msg_interface/start_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "include_internal/ten_runtime/app/app.h"
#include "include_internal/ten_runtime/app/close.h"
#include "include_internal/ten_runtime/app/engine_interface.h"
#include "include_internal/ten_runtime/app/graph.h"
#include "include_internal/ten_runtime/app/metadata.h"
#include "include_internal/ten_runtime/app/msg_interface/common.h"
#include "include_internal/ten_runtime/app/predefined_graph.h"
Expand All @@ -24,7 +25,12 @@
#include "include_internal/ten_runtime/msg/msg.h"
#include "include_internal/ten_runtime/protocol/protocol.h"
#include "ten_runtime/app/app.h"
#include "ten_runtime/common/status_code.h"
#include "ten_runtime/msg/cmd_result/cmd_result.h"
#include "ten_runtime/msg/msg.h"
#include "ten_utils/lib/json.h"
#include "ten_utils/lib/smart_ptr.h"
#include "ten_utils/log/log.h"
#include "ten_utils/macro/check.h"

static bool ten_app_fill_start_graph_cmd_extensions_info_from_predefined_graph(
Expand Down Expand Up @@ -53,6 +59,39 @@ static bool ten_app_fill_start_graph_cmd_extensions_info_from_predefined_graph(
return true;
}

bool ten_app_check_start_graph_cmd(ten_app_t *self,
ten_connection_t *connection,
ten_shared_ptr_t *cmd, ten_error_t *err) {
TEN_ASSERT(self && ten_app_check_integrity(self, true), "Invalid argument.");
TEN_ASSERT(cmd && ten_cmd_base_check_integrity(cmd), "Invalid argument.");
TEN_ASSERT(ten_msg_get_type(cmd) == TEN_MSG_TYPE_CMD_START_GRAPH,
"Invalid argument.");
TEN_ASSERT(err && ten_error_check_integrity(err), "Invalid argument.");

ten_json_t *cmd_json = ten_msg_to_json(cmd, err);
if (!cmd_json) {
TEN_ASSERT(0,
"Failed to convert start graph cmd to json, should not happen.");
return false;
}

bool rc = ten_app_check_start_graph_cmd_json(self, cmd_json, err);

ten_json_destroy(cmd_json);

if (!rc && connection) {
ten_shared_ptr_t *ret_cmd =
ten_cmd_result_create_from_cmd(TEN_STATUS_CODE_ERROR, cmd);
ten_msg_set_property(ret_cmd, TEN_STR_DETAIL,
ten_value_create_string(ten_error_errmsg(err)), NULL);
ten_msg_clear_and_set_dest_from_msg_src(ret_cmd, cmd);
ten_connection_send_msg(connection, ret_cmd);
ten_shared_ptr_destroy(ret_cmd);
}

return rc;
}

bool ten_app_handle_start_graph_cmd(ten_app_t *self,
ten_connection_t *connection,
ten_shared_ptr_t *cmd, ten_error_t *err) {
Expand All @@ -75,6 +114,13 @@ bool ten_app_handle_start_graph_cmd(ten_app_t *self,
ten_engine_t *engine =
ten_app_get_engine_based_on_dest_graph_id_from_msg(self, cmd);
if (engine == NULL) {
// The graph should be only checked once.
if (!ten_app_check_start_graph_cmd(self, connection, cmd, err)) {
TEN_LOGE("[%s] Failed to check start_graph cmd, %s",
ten_app_get_uri(self), ten_error_errmsg(err));
return false;
}

// The engine does not exist, create one, and send 'cmd' to the newly
// created engine.
engine = ten_app_create_engine(self, cmd);
Expand Down
9 changes: 9 additions & 0 deletions core/src/ten_runtime/app/predefined_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "include_internal/ten_runtime/app/app.h"
#include "include_internal/ten_runtime/app/engine_interface.h"
#include "include_internal/ten_runtime/app/graph.h"
#include "include_internal/ten_runtime/app/metadata.h"
#include "include_internal/ten_runtime/common/constant_str.h"
#include "include_internal/ten_runtime/engine/engine.h"
Expand All @@ -25,6 +26,7 @@
#include "ten_utils/lib/error.h"
#include "ten_utils/lib/json.h"
#include "ten_utils/lib/string.h"
#include "ten_utils/log/log.h"
#include "ten_utils/macro/check.h"
#include "ten_utils/value/value_get.h"

Expand Down Expand Up @@ -149,6 +151,13 @@ bool ten_app_start_predefined_graph(
return false;
}

if (!ten_app_check_start_graph_cmd_json(self, start_graph_cmd_json, err)) {
// TODO(Wei): The graph check does not support message conversion now, so we
// can not return false here. WIP: issues#160.
TEN_LOGW("[%s] The predefined graph is invalid, %s", ten_app_get_uri(self),
ten_error_errmsg(err));
}

ten_shared_ptr_t *start_graph_cmd =
ten_msg_create_from_json(start_graph_cmd_json, NULL);

Expand Down
2 changes: 1 addition & 1 deletion core/src/ten_runtime/app/ten_env/on_xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static void ten_app_on_configure_done_internal(ten_app_t *self) {
}

rc = ten_app_start_auto_start_predefined_graph(self, &err);
TEN_ASSERT(rc, "Should not happen.");
TEN_ASSERT(rc, "Should not happen, %s.", ten_error_errmsg(&err));

ten_error_deinit(&err);
}
Expand Down
15 changes: 12 additions & 3 deletions core/src/ten_runtime/engine/msg_interface/cmd_result.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "ten_utils/lib/smart_ptr.h"
#include "ten_utils/lib/string.h"
#include "ten_utils/macro/check.h"
#include "ten_utils/value/value_get.h"
#include "ten_utils/value/value_is.h"

static bool ten_engine_close_duplicated_remote_or_upgrade_it_to_normal(
Expand Down Expand Up @@ -156,9 +157,17 @@ static bool ten_engine_handle_cmd_result_for_cmd_start_graph(
"The engine should be started because of receiving a 'start_graph' "
"command.");

ten_engine_return_error_for_cmd_start_graph(
self, original_start_graph_cmd, "Failed to connect to %s",
ten_msg_get_src_app_uri(cmd_result));
ten_value_t *err_msg_value =
ten_msg_peek_property(cmd_result, TEN_STR_DETAIL, NULL);
if (err_msg_value) {
TEN_ASSERT(ten_value_is_string(err_msg_value), "Should not happen.");
ten_engine_return_error_for_cmd_start_graph(
self, original_start_graph_cmd, ten_value_peek_string(err_msg_value));
} else {
ten_engine_return_error_for_cmd_start_graph(
self, original_start_graph_cmd, "Failed to start engine in app [%s].",
ten_msg_get_src_app_uri(cmd_result));
}
} else {
TEN_ASSERT(0, "Should not happen.");
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/ten_runtime/metadata/metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static bool ten_metadata_load_from_json_string(ten_value_t *metadata,
TEN_ASSERT(metadata && ten_value_check_integrity(metadata) && json_str,
"Should not happen.");

ten_json_t *json = ten_json_from_string(json_str, NULL);
ten_json_t *json = ten_json_from_string(json_str, err);
if (!json) {
return false;
}
Expand Down
38 changes: 38 additions & 0 deletions core/src/ten_rust/src/pkg_info/binding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// 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.
//
use std::ffi::{c_char, CStr, CString};

#[no_mangle]
pub extern "C" fn ten_rust_check_graph_for_app(
app_base_dir: *const c_char,
graph_json: *const c_char,
out_err_msg: *mut *const c_char,
) -> bool {
assert!(!app_base_dir.is_null(), "Invalid argument.");
assert!(!graph_json.is_null(), "Invalid argument.");

let c_app_base_dir = unsafe { CStr::from_ptr(app_base_dir) };
let c_graph_json = unsafe { CStr::from_ptr(graph_json) };

let rust_app_base_dir = c_app_base_dir.to_str().unwrap();
let rust_graph_json = c_graph_json.to_str().unwrap();

let ret = crate::pkg_info::ten_rust_check_graph_for_app(
rust_app_base_dir,
rust_graph_json,
);
if ret.is_err() {
let err_msg = ret.err().unwrap().to_string();
let c_err_msg =
CString::new(err_msg).expect("Failed to allocate memory.");
unsafe {
*out_err_msg = c_err_msg.into_raw();
}
return false;
}
true
}
Loading

0 comments on commit 888a918

Please sign in to comment.