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: add websocket server nodejs extension which depends on third-party packages #504

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
91d3a86
feat: add websocket server nodejs extension which depends on third-pa…
sunxilin Jan 3, 2025
8f15882
fix: avoid properties overwriten in http server nodejs extension
sunxilin Jan 3, 2025
3bbab42
feat: add test case for mixing python and nodejs
sunxilin Jan 3, 2025
d6935ee
fix: python dependency
sunxilin Jan 3, 2025
04644fb
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
halajohn Jan 3, 2025
0cc23df
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
sunxilin Jan 6, 2025
4952752
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
halajohn Jan 6, 2025
b1b9810
fix: cleanup in the final stage of nodejs testing cases
sunxilin Jan 6, 2025
f748ccf
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
halajohn Jan 6, 2025
069e6d4
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
halajohn Jan 6, 2025
e79b77d
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
sunxilin Jan 7, 2025
5cb491b
fix: fix asan detect error
sunxilin Jan 7, 2025
48fef22
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
sunxilin Jan 7, 2025
ff1174a
feat: add Python websocket extension and test case
sunxilin Jan 7, 2025
98d5bb2
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
sunxilin Jan 7, 2025
9fe8b1f
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
sunxilin Jan 7, 2025
c297123
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
halajohn Jan 7, 2025
74d7ec1
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
halajohn Jan 8, 2025
19a4c23
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
sunxilin Jan 8, 2025
2d30883
fix: refine codes
halajohn Jan 8, 2025
3c811ba
Merge branch 'main' into 488-in-the-http_server_extension_ts-the-effe…
halajohn Jan 8, 2025
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
9 changes: 9 additions & 0 deletions .github/tools/setup_pytest_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ def setup():
"python-dotenv",
]
)
utils.run_cmd_with_retry(
[
sys.executable,
"-m",
"pip",
"install",
"websocket-client",
]
)


if __name__ == "__main__":
Expand Down
12 changes: 8 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -673,9 +673,9 @@
"request": "launch",
"program": "node",
"args": [
"${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/nodejs/http_server_nodejs/http_server_nodejs_app/build/start.js"
"${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/nodejs/mix_python_ext_nodejs/mix_python_ext_nodejs_app/build/start.js"
],
"cwd": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/nodejs/http_server_nodejs/http_server_nodejs_app/",
"cwd": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/nodejs/mix_python_ext_nodejs/mix_python_ext_nodejs_app/",
"env": {
"LD_PRELOAD": "ten_packages/system/ten_runtime/lib/libasan.so",
"NODE_PATH": "ten_packages/system/ten_runtime_nodejs/lib:$NODE_PATH",
Expand All @@ -689,9 +689,9 @@
"program": "/usr/bin/node",
"args": [
"--expose-gc",
"${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/nodejs/http_server_nodejs/http_server_nodejs_app/build/start.js"
"${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/nodejs/mix_python_ext_nodejs/mix_python_ext_nodejs_app/build/start.js"
],
"cwd": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/nodejs/http_server_nodejs/http_server_nodejs_app/",
"cwd": "${workspaceFolder}/out/linux/x64/tests/ten_runtime/integration/nodejs/mix_python_ext_nodejs/mix_python_ext_nodejs_app/",
"environment": [
{
"name": "LD_PRELOAD",
Expand All @@ -708,6 +708,10 @@
{
"name": "LSAN_OPTIONS",
"value": "verbosity=1:log_threads=1"
},
{
"name": "TEN_ENABLE_MEMORY_TRACKING",
"value": "true"
}
],
"sourceFileMap": {
Expand Down
5 changes: 5 additions & 0 deletions build/ten_runtime/feature/build_pkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ def build_nodejs_extensions(app_root_path: str) -> int:
# Change to extension directory.
os.chdir(extension_path)

status = npm_install()
if status != 0:
print(f"Failed to npm install in {extension_path}")
return 1

now = datetime.now()
cmd = ["npm", "run", "build"]
returncode, output = cmd_exec.run_cmd(cmd)
Expand Down
7 changes: 7 additions & 0 deletions packages/example_extensions/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,12 @@ group("example_extensions") {
"pil_demo_python",
]
}

if (ten_enable_nodejs_binding) {
deps += [
"http_server_extension_nodejs",
"websocket_server_nodejs",
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ class HttpServerExtension extends Extension {
} else if ("name" in _ten) {
const name = _ten["name"];
const cmd = Cmd.Create(name);
cmd.setPropertyFromJson("", body);
cmd.setPropertyString("method", req.method!);
cmd.setPropertyString("url", req.url!);
cmd.setPropertyFromJson("", body);

this.tenEnv!.sendCmd(cmd).then(
([cmdResult, error]: [CmdResult | null, Error | null]) => {
Expand Down
5 changes: 5 additions & 0 deletions packages/example_extensions/pil_demo_python/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#
# This file is part of TEN Framework, an open source project.
# Licensed under the Apache License, Version 2.0.
# See the LICENSE file for more information.
#
from . import main

print("pil demo extension loaded")
32 changes: 32 additions & 0 deletions packages/example_extensions/simple_echo_python/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# This file is part of TEN Framework, an open source project.
# Licensed under the Apache License, Version 2.0.
# See the LICENSE file for more information.
#
import("//build/feature/ten_package.gni")
import("//build/ten_runtime/feature/publish.gni")
import("//build/ten_runtime/glob.gni")
import("//build/ten_runtime/options.gni")

ten_package("simple_echo_python") {
package_kind = "extension"

resources = [
"__init__.py",
"addon.py",
"extension.py",
"manifest.json",
"property.json",
"requirements.txt",
]

deps = [ "//core/src/ten_runtime" ]
}

if (ten_enable_ten_manager) {
ten_package_publish("upload_simple_echo_python_to_server") {
base_dir =
rebase_path("${root_out_dir}/ten_packages/extension/simple_echo_python")
deps = [ ":simple_echo_python" ]
}
}
13 changes: 13 additions & 0 deletions packages/example_extensions/simple_echo_python/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright © 2025 Agora

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.
6 changes: 6 additions & 0 deletions packages/example_extensions/simple_echo_python/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# This file is part of TEN Framework, an open source project.
# Licensed under the Apache License, Version 2.0.
# See the LICENSE file for more information.
#
from . import addon
17 changes: 17 additions & 0 deletions packages/example_extensions/simple_echo_python/addon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# This file is part of TEN Framework, an open source project.
# Licensed under the Apache License, Version 2.0.
# See the LICENSE file for more information.
#
from ten import (
Addon,
register_addon_as_extension,
TenEnv,
)
from .extension import SimpleEchoExtension


@register_addon_as_extension("simple_echo_python")
class SimpleEchoExtensionAddon(Addon):
def on_create_instance(self, ten_env: TenEnv, name: str, context) -> None:
ten_env.on_create_instance_done(SimpleEchoExtension(name), context)
102 changes: 102 additions & 0 deletions packages/example_extensions/simple_echo_python/extension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#
# This file is part of TEN Framework, an open source project.
# Licensed under the Apache License, Version 2.0.
# See the LICENSE file for more information.
#
from ten import (
AudioFrame,
VideoFrame,
AsyncExtension,
AsyncTenEnv,
Cmd,
StatusCode,
CmdResult,
Data,
)


class SimpleEchoExtension(AsyncExtension):
async def on_init(self, ten_env: AsyncTenEnv) -> None:
ten_env.log_debug("on_init")

async def on_start(self, ten_env: AsyncTenEnv) -> None:
ten_env.log_debug("on_start")

# TODO: read properties, initialize resources

async def on_stop(self, ten_env: AsyncTenEnv) -> None:
ten_env.log_debug("on_stop")

# TODO: clean up resources

async def on_deinit(self, ten_env: AsyncTenEnv) -> None:
ten_env.log_debug("on_deinit")

async def on_cmd(self, ten_env: AsyncTenEnv, cmd: Cmd) -> None:
cmd_name = cmd.get_name()
ten_env.log_debug("on_cmd name {}".format(cmd_name))

cmd_result = CmdResult.create(StatusCode.OK)
cmd_result.set_property_string("detail", cmd_name + ", too")

await ten_env.return_result(cmd_result, cmd)

async def on_data(self, ten_env: AsyncTenEnv, data: Data) -> None:
data_name = data.get_name()
ten_env.log_debug("on_data name {}".format(data_name))

buf = data.get_buf()

new_data = Data.create(data_name)
new_data.alloc_buf(len(buf))
new_buf = new_data.lock_buf()
new_buf[:] = buf
new_data.unlock_buf(new_buf)

await ten_env.send_data(new_data)

async def on_audio_frame(
self, ten_env: AsyncTenEnv, audio_frame: AudioFrame
) -> None:
audio_frame_name = audio_frame.get_name()
ten_env.log_debug("on_audio_frame name {}".format(audio_frame_name))

buf = audio_frame.get_buf()
new_audio_frame = AudioFrame.create(audio_frame_name)
new_audio_frame.alloc_buf(len(buf))
new_buf = new_audio_frame.lock_buf()
new_buf[:] = buf
new_audio_frame.unlock_buf(new_buf)

new_audio_frame.set_bytes_per_sample(audio_frame.get_bytes_per_sample())
new_audio_frame.set_sample_rate(audio_frame.get_sample_rate())
new_audio_frame.set_data_fmt(audio_frame.get_data_fmt())
new_audio_frame.set_eof(audio_frame.is_eof())
new_audio_frame.set_line_size(audio_frame.get_line_size())
new_audio_frame.set_number_of_channels(
audio_frame.get_number_of_channels()
)
new_audio_frame.set_timestamp(audio_frame.get_timestamp())

await ten_env.send_audio_frame(new_audio_frame)

async def on_video_frame(
self, ten_env: AsyncTenEnv, video_frame: VideoFrame
) -> None:
video_frame_name = video_frame.get_name()
ten_env.log_debug("on_video_frame name {}".format(video_frame_name))

buf = video_frame.get_buf()
new_video_frame = VideoFrame.create(video_frame_name)
new_video_frame.alloc_buf(len(buf))
new_buf = new_video_frame.lock_buf()
new_buf[:] = buf
new_video_frame.unlock_buf(new_buf)

new_video_frame.set_eof(video_frame.is_eof())
new_video_frame.set_height(video_frame.get_height())
new_video_frame.set_width(video_frame.get_width())
new_video_frame.set_timestamp(video_frame.get_timestamp())
new_video_frame.set_pixel_fmt(video_frame.get_pixel_fmt())

await ten_env.send_video_frame(new_video_frame)
13 changes: 13 additions & 0 deletions packages/example_extensions/simple_echo_python/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"type": "extension",
"name": "simple_echo_python",
"version": "0.1.0",
"dependencies": [
{
"type": "system",
"name": "ten_runtime_python",
"version": "0.6.0"
}
],
"api": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Empty file.
32 changes: 32 additions & 0 deletions packages/example_extensions/websocket_server_nodejs/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# This file is part of TEN Framework, an open source project.
# Licensed under the Apache License, Version 2.0.
# See the LICENSE file for more information.
#
import("//build/feature/ten_package.gni")
import("//build/ten_runtime/feature/publish.gni")
import("//build/ten_runtime/glob.gni")
import("//build/ten_runtime/options.gni")

ten_package("websocket_server_nodejs") {
package_kind = "extension"

resources = [
"BUILD.gn",
"manifest.json",
"package.json",
"property.json",
"src/index.ts",
"tsconfig.json",
]

deps = [ "//core/src/ten_runtime" ]
}

if (ten_enable_ten_manager) {
ten_package_publish("upload_websocket_server_nodejs_to_server") {
base_dir = rebase_path(
"${root_out_dir}/ten_packages/extension/websocket_server_nodejs")
deps = [ ":websocket_server_nodejs" ]
}
}
13 changes: 13 additions & 0 deletions packages/example_extensions/websocket_server_nodejs/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright © 2025 Agora

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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"type": "extension",
"name": "websocket_server_nodejs",
"version": "0.6.0",
"dependencies": [
{
"type": "system",
"name": "ten_runtime_nodejs",
"version": "0.6.0"
}
],
"package": {
"include": [
"manifest.json",
"property.json",
"BUILD.gn",
"src/**",
"tsconfig.json",
"package.json"
]
},
"api": {}
}
Loading
Loading