diff --git a/cpp/open3d/visualization/webrtc_server/PeerConnectionManager.cpp b/cpp/open3d/visualization/webrtc_server/PeerConnectionManager.cpp index aef757932f9..7b61ac144f5 100644 --- a/cpp/open3d/visualization/webrtc_server/PeerConnectionManager.cpp +++ b/cpp/open3d/visualization/webrtc_server/PeerConnectionManager.cpp @@ -140,19 +140,19 @@ PeerConnectionManager::PeerConnectionManager( // Register api in http server. func_["/api/getMediaList"] = [this](const struct mg_request_info *req_info, const Json::Value &in) -> Json::Value { - utility::LogInfo("[Called HTTP API] /api/getMediaList"); + utility::LogDebug("[Called HTTP API] /api/getMediaList"); return this->GetMediaList(); }; func_["/api/getIceServers"] = [this](const struct mg_request_info *req_info, const Json::Value &in) -> Json::Value { - utility::LogInfo("[Called HTTP API] /api/getIceServers"); + utility::LogDebug("[Called HTTP API] /api/getIceServers"); return this->GetIceServers(); }; func_["/api/call"] = [this](const struct mg_request_info *req_info, const Json::Value &in) -> Json::Value { - utility::LogInfo("[Called HTTP API] /api/call"); + utility::LogDebug("[Called HTTP API] /api/call"); std::string peerid; std::string url; // window_uid. std::string options; @@ -167,7 +167,7 @@ PeerConnectionManager::PeerConnectionManager( func_["/api/getIceCandidate"] = [this](const struct mg_request_info *req_info, const Json::Value &in) -> Json::Value { - utility::LogInfo("[Called HTTP API] /api/getIceCandidate"); + utility::LogDebug("[Called HTTP API] /api/getIceCandidate"); std::string peerid; if (req_info->query_string) { CivetServer::getParam(req_info->query_string, "peerid", peerid); @@ -178,7 +178,7 @@ PeerConnectionManager::PeerConnectionManager( func_["/api/addIceCandidate"] = [this](const struct mg_request_info *req_info, const Json::Value &in) -> Json::Value { - utility::LogInfo("[Called HTTP API] /api/addIceCandidate"); + utility::LogDebug("[Called HTTP API] /api/addIceCandidate"); std::string peerid; if (req_info->query_string) { CivetServer::getParam(req_info->query_string, "peerid", peerid); @@ -188,7 +188,7 @@ PeerConnectionManager::PeerConnectionManager( func_["/api/hangup"] = [this](const struct mg_request_info *req_info, const Json::Value &in) -> Json::Value { - utility::LogInfo("[Called HTTP API] /api/hangup"); + utility::LogDebug("[Called HTTP API] /api/hangup"); std::string peerid; if (req_info->query_string) { CivetServer::getParam(req_info->query_string, "peerid", peerid); @@ -713,8 +713,8 @@ void PeerConnectionManager::SendInitFramesToPeer(const std::string &peerid) { void PeerConnectionManager::CloseWindowConnections( const std::string &window_uid) { - utility::LogInfo("PeerConnectionManager::CloseWindowConnections: {}", - window_uid); + utility::LogDebug("PeerConnectionManager::CloseWindowConnections: {}", + window_uid); std::set peerids; { std::lock_guard mlock(window_uid_to_peerids_mutex_); diff --git a/cpp/open3d/visualization/webrtc_server/PeerConnectionManager.h b/cpp/open3d/visualization/webrtc_server/PeerConnectionManager.h index 173f642fae2..ceb0fc9df74 100644 --- a/cpp/open3d/visualization/webrtc_server/PeerConnectionManager.h +++ b/cpp/open3d/visualization/webrtc_server/PeerConnectionManager.h @@ -204,7 +204,7 @@ class PeerConnectionManager { const std::string state = webrtc::DataChannelInterface::DataStateString( data_channel_->state()); - utility::LogInfo( + utility::LogDebug( "DataChannelObserver::OnStateChange label: {}, state: {}, " "peerid: {}", label, state, peerid_); diff --git a/cpp/open3d/visualization/webrtc_server/WebRTCWindowSystem.cpp b/cpp/open3d/visualization/webrtc_server/WebRTCWindowSystem.cpp index e83939ee82f..4440f0d865b 100644 --- a/cpp/open3d/visualization/webrtc_server/WebRTCWindowSystem.cpp +++ b/cpp/open3d/visualization/webrtc_server/WebRTCWindowSystem.cpp @@ -419,7 +419,7 @@ void WebRTCWindowSystem::SendInitFrames(const std::string &window_uid) { std::string WebRTCWindowSystem::CallHttpAPI(const std::string &entry_point, const std::string &query_string, const std::string &data) const { - utility::LogInfo("[Called HTTP API (custom handshake)] {}", entry_point); + utility::LogDebug("[Called HTTP API (custom handshake)] {}", entry_point); std::string query_string_trimmed = ""; if (!query_string.empty() && query_string[0] == '?') { diff --git a/cpp/pybind/make_install_pip_package.cmake b/cpp/pybind/make_install_pip_package.cmake index a5c9fcdd05c..98754677d11 100644 --- a/cpp/pybind/make_install_pip_package.cmake +++ b/cpp/pybind/make_install_pip_package.cmake @@ -4,5 +4,5 @@ # Note: Since `make python-package` clears PYTHON_COMPILED_MODULE_DIR every time, # it is guaranteed that there is only one wheel in ${PYTHON_PACKAGE_DST_DIR}/pip_package/*.whl file(GLOB WHEEL_FILE "${PYTHON_PACKAGE_DST_DIR}/pip_package/*.whl") -execute_process(COMMAND ${Python3_EXECUTABLE} -m pip uninstall open3d --yes) +execute_process(COMMAND ${Python3_EXECUTABLE} -m pip uninstall open3d open3d-cpu --yes) execute_process(COMMAND ${Python3_EXECUTABLE} -m pip install ${WHEEL_FILE} -U) diff --git a/python/js/amd-public-path.js b/python/js/amd-public-path.js new file mode 100644 index 00000000000..71f9372e44f --- /dev/null +++ b/python/js/amd-public-path.js @@ -0,0 +1,8 @@ +// In an AMD module, we set the public path using the magic requirejs "module" dependency +// See https://github.com/requirejs/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#module +// Since "module" is a requirejs magic module, we must include "module" in the webpack externals configuration. +var module = require("module"); +var url = new URL(module.uri, document.location); +// Using lastIndexOf("/")+1 gives us the empty string if there is no "/", so pathname becomes "/" +url.pathname = url.pathname.slice(0, url.pathname.lastIndexOf("/") + 1); +__webpack_public_path__ = `${url.origin}${url.pathname}`; diff --git a/python/js/lib/embed.js b/python/js/lib/embed.js deleted file mode 100644 index ff852e762cf..00000000000 --- a/python/js/lib/embed.js +++ /dev/null @@ -1,9 +0,0 @@ -// Entry point for the unpkg bundle containing custom model definitions. -// -// It differs from the notebook bundle in that it does not need to define a -// dynamic baseURL for the static assets and may load some css that would -// already be loaded by the notebook otherwise. - -// Export widget models and views, and the npm package version number. -module.exports = require("./web_visualizer.js"); -module.exports["version"] = require("../package.json").version; diff --git a/python/js/lib/extension.js b/python/js/lib/extension.js index 7c220feaed0..991c9a9a596 100644 --- a/python/js/lib/extension.js +++ b/python/js/lib/extension.js @@ -1,12 +1,6 @@ // This file contains the javascript that is run when the notebook is loaded. // It contains some requirejs configuration and the `load_ipython_extension` // which is required for any notebook extension. -// -// Some static assets may be required by the custom widget javascript. The base -// url for the notebook is not known at build time and is therefore computed -// dynamically. -__webpack_public_path__ = document.querySelector('body').getAttribute('data-base-url') + 'nbextensions/open3d'; - // Configure requirejs if (window.require) { @@ -21,5 +15,5 @@ if (window.require) { // Export the required load_ipython_extension module.exports = { - load_ipython_extension: function() {} + load_ipython_extensionn() {} }; diff --git a/python/js/lib/labplugin.js b/python/js/lib/labplugin.js index 50a8fda4b40..95c8cd49ad6 100644 --- a/python/js/lib/labplugin.js +++ b/python/js/lib/labplugin.js @@ -4,13 +4,12 @@ var base = require('@jupyter-widgets/base'); module.exports = { id: 'open3d:plugin', requires: [base.IJupyterWidgetRegistry], - activate: function(app, widgets) { - widgets.registerWidget({ - name: 'open3d', - version: plugin.version, - exports: plugin - }); + activate: (app, widgets) => { + widgets.registerWidget({ + name: 'open3d', + version: plugin.version, + exports: plugin + }); }, autoStart: true }; - diff --git a/python/js/lib/web_visualizer.js b/python/js/lib/web_visualizer.js index fd68ad6c307..3ccdff725a3 100644 --- a/python/js/lib/web_visualizer.js +++ b/python/js/lib/web_visualizer.js @@ -1,27 +1,8 @@ // ---------------------------------------------------------------------------- -// - Open3D: www.open3d.org - +// - Open3D: www.open3d.org - // ---------------------------------------------------------------------------- -// The MIT License (MIT) -// -// Copyright (c) 2018-2023 www.open3d.org -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. +// Copyright(c) 2018-2023 www.open3d.org +// SPDX - License - Identifier: MIT // ---------------------------------------------------------------------------- // Jupyter widget for Open3D WebRTC visualizer. See web_visualizer.py for the @@ -44,49 +25,51 @@ let WebRtcStreamer = require("./webrtcstreamer"); // // When serializing the entire widget state for embedding, only values that // differ from the defaults will be specified. -let WebVisualizerModel = widgets.DOMWidgetModel.extend({ - defaults: _.extend(widgets.DOMWidgetModel.prototype.defaults(), { - _model_name: "WebVisualizerModel", - _view_name: "WebVisualizerView", - _model_module: "open3d", - _view_module: "open3d", - // @...@ is configured by cpp/pybind/make_python_package.cmake. - _model_module_version: "@PROJECT_VERSION_THREE_NUMBER@", - _view_module_version: "@PROJECT_VERSION_THREE_NUMBER@", - }), -}); +class WebVisualizerModel extends widgets.DOMWidgetModel { + defaults() { + return _.extend(widgets.DOMWidgetModel.prototype.defaults(), { + _model_name: "WebVisualizerModel", + _view_name: "WebVisualizerView", + _model_module: "open3d", + _view_module: "open3d", + // @...@ is configured by cpp/pybind/make_python_package.cmake. + _model_module_version: "@PROJECT_VERSION_THREE_NUMBER@", + _view_module_version: "@PROJECT_VERSION_THREE_NUMBER@", + }); + } +} // Custom View. Renders the widget model. -let WebVisualizerView = widgets.DOMWidgetView.extend({ - sleep: function (time_ms) { +class WebVisualizerView extends widgets.DOMWidgetView { + sleep(time_ms) { return new Promise((resolve) => setTimeout(resolve, time_ms)); - }, + } - logAndReturn: function (value) { + logAndReturn(value) { console.log("logAndReturn: ", value); return value; - }, + } - callResultReady: function (callId) { + callResultReady(callId) { let pyjs_channel = this.model.get("pyjs_channel"); console.log("Current pyjs_channel:", pyjs_channel); let callResultMap = JSON.parse(this.model.get("pyjs_channel")); return callId in callResultMap; - }, + } - extractCallResult: function (callId) { + extractCallResult(callId) { if (!this.callResultReady(callId)) { throw "extractCallResult not ready yet."; } let callResultMap = JSON.parse(this.model.get("pyjs_channel")); return callResultMap[callId]; - }, + } /** * Hard-coded to call "call_http_api". Args and return value are all * strings. */ - callPython: async function (func, args = []) { + async callPython(func, args = []) { let callId = this.callId.toString(); this.callId++; let message = { @@ -116,9 +99,9 @@ let WebVisualizerView = widgets.DOMWidgetView.extend({ json_result ); return json_result; - }, + } - commsCall: function (url, data = {}) { + commsCall(url, data = {}) { // https://stackoverflow.com/a/736970/1255535 // parseUrl(url).hostname // parseUrl(url).entryPoint @@ -180,9 +163,9 @@ let WebVisualizerView = widgets.DOMWidgetView.extend({ } else { throw "Unsupported entryPoint: " + entryPoint; } - }, + } - render: function () { + render() { let windowUID = this.model.get("window_uid"); let onClose = function () { console.log("onClose() called for window_uid:", windowUID); @@ -214,8 +197,8 @@ let WebVisualizerView = widgets.DOMWidgetView.extend({ this.commsCall.bind(this) ); this.webRtcClient.connect(windowUID); - }, -}); + } +} module.exports = { WebVisualizerModel: WebVisualizerModel, diff --git a/python/js/package.json b/python/js/package.json index 091a632aae6..73a76b3a8af 100644 --- a/python/js/package.json +++ b/python/js/package.json @@ -1,8 +1,8 @@ { "name": "open3d", "version": "@PROJECT_VERSION_THREE_NUMBER@", - "description": "Open3D: A Modern Library for 3D Data Processing", - "author": "Open3D.org", + "description": "@PROJECT_DESCRIPTION@", + "author": "@PROJECT_EMAIL@", "main": "lib/index.js", "repository": { "type": "git", @@ -36,7 +36,7 @@ "rimraf": "^2.6.1" }, "dependencies": { - "@jupyter-widgets/base": "^1.1 || ^2 || ^3 || ^4", + "@jupyter-widgets/base": "^2 || ^3 || ^4 || ^5 || ^6", "lodash": "^4.17.4", "webrtc-adapter": "^4.2.2" }, diff --git a/python/js/webpack.config.js b/python/js/webpack.config.js index 7a7d378b956..05c2bee12aa 100644 --- a/python/js/webpack.config.js +++ b/python/js/webpack.config.js @@ -16,13 +16,11 @@ module.exports = (env, argv) => { // some configuration for requirejs, and provides the legacy // "load_ipython_extension" function which is required for any notebook // extension. - // entry: "./lib/extension.js", output: { filename: "extension.js", path: path.resolve(__dirname, "..", "open3d", "nbextension"), libraryTarget: "amd", - publicPath: "", // publicPath is set in extension.js }, devtool, }, @@ -32,47 +30,43 @@ module.exports = (env, argv) => { // This bundle contains the implementation for the custom widget views and // custom widget. // It must be an amd module - // - entry: "./lib/index.js", + entry: ["./amd-public-path.js", "./lib/index.js"], output: { filename: "index.js", path: path.resolve(__dirname, "..", "open3d", "nbextension"), libraryTarget: "amd", - publicPath: "", + publicPath: "", // Set in amd-public-path.js }, devtool, module: { rules: rules, }, - externals: ["@jupyter-widgets/base"], + // "module" is the magic requirejs dependency used to set the publicPath + externals: ["@jupyter-widgets/base", "module"] }, { // Embeddable open3d bundle // - // This bundle is generally almost identical to the notebook bundle - // containing the custom widget views and models. - // - // The only difference is in the configuration of the webpack public path - // for the static assets. - // - // It will be automatically distributed by unpkg to work with the static - // widget embedder. - // - // The target bundle is always `dist/index.js`, which is the path required - // by the custom widget embedder. + // This bundle is identical to the notebook bundle containing the custom + // widget views and models. The only difference is it is placed in the + // dist/ directory and shipped with the npm package for use from a CDN + // like jsdelivr. // - entry: "./lib/embed.js", + // The target bundle is always `dist/index.js`, which is the path + // required by the custom widget embedder. + entry: ["./amd-public-path.js", "./lib/index.js"], output: { filename: "index.js", path: path.resolve(__dirname, "dist"), libraryTarget: "amd", - publicPath: "https://unpkg.com/open3d@" + version + "/dist/", + publicPath: "", // Set in amd-public-path.js }, devtool, module: { rules: rules, }, - externals: ["@jupyter-widgets/base"], + // "module" is the magic requirejs dependency used to set the publicPath + externals: ["@jupyter-widgets/base", "module"] }, ]; }; diff --git a/python/pyproject.toml b/python/pyproject.toml index 25cafb616b9..3d229011876 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -1,3 +1,3 @@ [build-system] -requires = ["ipywidgets>=7.6.0", "pygments>=2.7.4", "jupyter_packaging~=0.10", "jupyterlab>=3.0.0,==3.*", "setuptools>=40.8.0", "wheel"] +requires = ["ipywidgets>=8.0.3", "pygments>=2.7.4", "jupyter_packaging~=0.12", "jupyterlab>=3.0.0,==3.*", "setuptools>=50.3.2", "wheel==0.38.4"] build-backend = "setuptools.build_meta" diff --git a/python/requirements_jupyter_build.txt b/python/requirements_jupyter_build.txt index 9d43e772d4d..492acf451d4 100644 --- a/python/requirements_jupyter_build.txt +++ b/python/requirements_jupyter_build.txt @@ -1,5 +1,5 @@ pywinpty==2.0.2; sys_platform=='win32' and python_version=='3.6' ipywidgets>=8.0.4 pygments>=2.7.4 -jupyter_packaging~=0.10 +jupyter_packaging~=0.12 jupyterlab>=3.0.0,==3.* diff --git a/python/setup.py b/python/setup.py index 5e69df23932..d2fea21ef7e 100644 --- a/python/setup.py +++ b/python/setup.py @@ -35,7 +35,7 @@ import jupyterlab # noqa # pylint: disable=unused-import except ImportError as error: print(error.__class__.__name__ + ": " + error.message) - print("Run `pip install jupyter_packaging ipywidgets jupyterlab`.") + print("Run `pip install -r requirements-jupyter-build.txt`.") here = os.path.dirname(os.path.abspath(__file__)) js_dir = os.path.join(here, "js")