diff --git a/Dockerfile b/Dockerfile index 58ff87d..0efc883 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,7 +43,7 @@ RUN wget --quiet --output-document=- "https://go.dev/dl/go${GO_VERSION}.linux-am && go version # Install GoNB (https://github.com/janpfeifer/gonb) in the user account -ARG GONB_VERSION="v0.10.4" +ARG GONB_VERSION="v0.10.5" USER $NB_USER WORKDIR ${HOME} RUN export GOPROXY=direct && \ diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 734821c..fcc526f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,9 @@ # GoNB Changelog +## v0.10.5, Added SendAsDownload + +* Added `dom.SendAsDownload` to send data from cells to the client by triggering a browser download. #134 + ## v0.10.4, Fixed #131 * Issue #131: proper handling of tuple variable declarations like `var contents, _ = os.ReadFile(...)` diff --git a/docs/coverage.txt b/docs/coverage.txt index 5123801..348853f 100644 --- a/docs/coverage.txt +++ b/docs/coverage.txt @@ -26,7 +26,7 @@ github.com/janpfeifer/gonb/cache/cache.go *Storage.Reset 75.0% github.com/janpfeifer/gonb/cache/cache.go Reset 0.0% github.com/janpfeifer/gonb/cache/cache.go CacheWith 91.7% github.com/janpfeifer/gonb/cache/cache.go Cache 0.0% -github.com/janpfeifer/gonb/cmd/nbexec/nbexec.go main 72.2% +github.com/janpfeifer/gonb/cmd/nbexec/nbexec.go main 74.3% github.com/janpfeifer/gonb/cmd/nbexec/nbexec.go startJupyterNotebook 73.2% github.com/janpfeifer/gonb/cmd/nbexec/nbexec.go executeNotebook 78.6% github.com/janpfeifer/gonb/cmd/nbexec/nbexec.go checkForInputBoxes 95.7% @@ -59,8 +59,8 @@ github.com/janpfeifer/gonb/common/common.go *ArrayFlag.String 66.7% github.com/janpfeifer/gonb/common/common.go *ArrayFlag.Set 0.0% github.com/janpfeifer/gonb/gonbui/gonbui.go init 100.0% github.com/janpfeifer/gonb/gonbui/gonbui.go Logf 50.0% -github.com/janpfeifer/gonb/gonbui/gonbui.go Error 100.0% -github.com/janpfeifer/gonb/gonbui/gonbui.go Open 100.0% +github.com/janpfeifer/gonb/gonbui/gonbui.go Error 100.0% +github.com/janpfeifer/gonb/gonbui/gonbui.go Open 100.0% github.com/janpfeifer/gonb/gonbui/gonbui.go openLocked 67.7% github.com/janpfeifer/gonb/gonbui/gonbui.go closePipesLocked 0.0% github.com/janpfeifer/gonb/gonbui/gonbui.go SendData 54.5% @@ -107,6 +107,7 @@ github.com/janpfeifer/gonb/gonbui/dom/dom.go SetInnerText 100.0% github.com/janpfeifer/gonb/gonbui/dom/dom.go GetInnerHtml 83.3% github.com/janpfeifer/gonb/gonbui/dom/dom.go Remove 100.0% github.com/janpfeifer/gonb/gonbui/dom/dom.go Persist 66.7% +github.com/janpfeifer/gonb/gonbui/dom/download.go SendAsDownload 0.0% github.com/janpfeifer/gonb/gonbui/dom/script.go LoadScriptModuleAndRun 0.0% github.com/janpfeifer/gonb/gonbui/dom/script.go LoadScriptOrRequireJSModuleAndRun 0.0% github.com/janpfeifer/gonb/gonbui/dom/script.go LoadScriptOrRequireJSModuleAndRunTransient 0.0% @@ -180,7 +181,7 @@ github.com/janpfeifer/gonb/internal/goexec/composer.go *WriterWithCursor.Error github.com/janpfeifer/gonb/internal/goexec/composer.go *WriterWithCursor.Writef 75.0% github.com/janpfeifer/gonb/internal/goexec/composer.go *WriterWithCursor.Write 76.9% github.com/janpfeifer/gonb/internal/goexec/composer.go *Declarations.RenderImports 100.0% -github.com/janpfeifer/gonb/internal/goexec/composer.go *Declarations.RenderVariables 92.0% +github.com/janpfeifer/gonb/internal/goexec/composer.go *Declarations.RenderVariables 91.2% github.com/janpfeifer/gonb/internal/goexec/composer.go *Declarations.RenderFunctions 100.0% github.com/janpfeifer/gonb/internal/goexec/composer.go *Declarations.RenderTypes 100.0% github.com/janpfeifer/gonb/internal/goexec/composer.go *Declarations.RenderConstants 100.0% @@ -215,6 +216,7 @@ github.com/janpfeifer/gonb/internal/goexec/goexec.go NewDeclarations 100.0 github.com/janpfeifer/gonb/internal/goexec/goexec.go *Declarations.Copy 100.0% github.com/janpfeifer/gonb/internal/goexec/goexec.go *Declarations.MergeFrom 100.0% github.com/janpfeifer/gonb/internal/goexec/goexec.go copyMap 100.0% +github.com/janpfeifer/gonb/internal/goexec/goexec.go variablesCopyFrom 100.0% github.com/janpfeifer/gonb/internal/goexec/goexec.go *Declarations.ClearCursor 100.0% github.com/janpfeifer/gonb/internal/goexec/goexec.go clearCursor 100.0% github.com/janpfeifer/gonb/internal/goexec/goexec.go *Declarations.DropFuncInit 100.0% @@ -248,7 +250,7 @@ github.com/janpfeifer/gonb/internal/goexec/parser.go *State.parseFromGoCode github.com/janpfeifer/gonb/internal/goexec/parser.go NewImport 88.9% github.com/janpfeifer/gonb/internal/goexec/parser.go *parseInfo.ParseImportEntry 100.0% github.com/janpfeifer/gonb/internal/goexec/parser.go *parseInfo.ParseFuncEntry 100.0% -github.com/janpfeifer/gonb/internal/goexec/parser.go *parseInfo.ParseVarEntry 81.2% +github.com/janpfeifer/gonb/internal/goexec/parser.go *parseInfo.ParseVarEntry 84.6% github.com/janpfeifer/gonb/internal/goexec/parser.go *parseInfo.ParseConstEntry 100.0% github.com/janpfeifer/gonb/internal/goexec/parser.go *parseInfo.ParseTypeEntry 100.0% github.com/janpfeifer/gonb/internal/goexec/parser.go *State.parseLinesAndComposeMain 74.3% @@ -404,7 +406,7 @@ github.com/janpfeifer/gonb/internal/specialcmd/definitions.go resetDefinitions github.com/janpfeifer/gonb/internal/specialcmd/definitions.go displayEnumeration 90.9% github.com/janpfeifer/gonb/internal/specialcmd/definitions.go listDefinitions 100.0% github.com/janpfeifer/gonb/internal/specialcmd/definitions.go removeDefinitionImpl 87.5% -github.com/janpfeifer/gonb/internal/specialcmd/definitions.go removeDefinitions 75.0% +github.com/janpfeifer/gonb/internal/specialcmd/definitions.go removeDefinitions 91.7% github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go Parse 84.6% github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go joinLine 87.5% github.com/janpfeifer/gonb/internal/specialcmd/specialcmd.go execSpecialConfig 55.3% @@ -414,4 +416,4 @@ github.com/janpfeifer/gonb/internal/specialcmd/track.go execTrack 27.3% github.com/janpfeifer/gonb/internal/specialcmd/track.go execUntrack 54.5% github.com/janpfeifer/gonb/internal/specialcmd/track.go showTrackedList 91.7% github.com/janpfeifer/gonb/internal/websocket/websocket.go Javascript 83.3% -total (statements) 64.3% +total (statements) 64.4% diff --git a/examples/tests/bash_script.ipynb b/examples/tests/bash_script.ipynb index 55cf0dd..94b9c3f 100644 --- a/examples/tests/bash_script.ipynb +++ b/examples/tests/bash_script.ipynb @@ -34,7 +34,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "/tmp/gonb_43bd76c8\n" + "/tmp/gonb_b9edd581\n" ] } ], @@ -59,7 +59,7 @@ "output_type": "stream", "text": [ "/home/janpf/Projects/gonb/examples/tests\n", - "/tmp/gonb_43bd76c8\n", + "/tmp/gonb_b9edd581\n", "/home/janpf/Projects/gonb\n", "/home/janpf/Projects/gonb\n" ] @@ -86,7 +86,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/comms.ipynb b/examples/tests/comms.ipynb index c214f4d..66573ae 100644 --- a/examples/tests/comms.ipynb +++ b/examples/tests/comms.ipynb @@ -308,7 +308,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/dom.ipynb b/examples/tests/dom.ipynb index e52f564..4f8b32a 100644 --- a/examples/tests/dom.ipynb +++ b/examples/tests/dom.ipynb @@ -88,7 +88,7 @@ { "data": { "text/html": [ - "
" + "
" ] }, "metadata": {}, @@ -152,7 +152,7 @@ { "data": { "text/html": [ - "
" + "
" ] }, "metadata": {}, @@ -197,7 +197,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/functions.ipynb b/examples/tests/functions.ipynb index 40c3f0d..35bf299 100644 --- a/examples/tests/functions.ipynb +++ b/examples/tests/functions.ipynb @@ -65,7 +65,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/goflags.ipynb b/examples/tests/goflags.ipynb index d2f12a1..f9a8334 100644 --- a/examples/tests/goflags.ipynb +++ b/examples/tests/goflags.ipynb @@ -153,9 +153,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "gonb_d53941d6/main.go:8:\tA\t\t100.0%\n", - "gonb_d53941d6/main.go:12:\tB\t\t0.0%\n", - "gonb_d53941d6/main.go:17:\tmain\t\t100.0%\n", + "gonb_0cdc700f/main.go:8:\tA\t\t100.0%\n", + "gonb_0cdc700f/main.go:12:\tB\t\t0.0%\n", + "gonb_0cdc700f/main.go:17:\tmain\t\t100.0%\n", "total\t\t\t\t(statements)\t75.0%\n" ] } @@ -238,7 +238,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "# gonb_d53941d6\n", + "# gonb_0cdc700f\n", "./main.go:10:6: can inline (*Point).ManhattanLen\n", "./main.go:16:12: inlining call to flag.Parse\n", "./main.go:18:27: inlining call to (*Point).ManhattanLen\n", @@ -267,7 +267,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/gonbui.ipynb b/examples/tests/gonbui.ipynb index 53c9d05..9a35591 100644 --- a/examples/tests/gonbui.ipynb +++ b/examples/tests/gonbui.ipynb @@ -22,7 +22,7 @@ "output_type": "stream", "text": [ "%goflags=[\"--cover\" \"--covermode=set\"]\n", - "GOCOVERDIR=/tmp/gonb_test_coverage.eLusFuePYS\n" + "GOCOVERDIR=/tmp/gonb_test_coverage.fmW2jDEhWf\n" ] } ], @@ -133,7 +133,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/gotest.ipynb b/examples/tests/gotest.ipynb index 4815d98..a3447a6 100644 --- a/examples/tests/gotest.ipynb +++ b/examples/tests/gotest.ipynb @@ -287,12 +287,12 @@ "text": [ "goos: linux\n", "goarch: amd64\n", - "pkg: gonb_103d9b0e\n", + "pkg: gonb_a1453c14\n", "cpu: 12th Gen Intel(R) Core(TM) i9-12900K\n", "BenchmarkFibonacciA32\n", - "BenchmarkFibonacciA32-24 \t 182\t 6454740 ns/op\n", + "BenchmarkFibonacciA32-24 \t 169\t 7058908 ns/op\n", "BenchmarkFibonacciB32\n", - "BenchmarkFibonacciB32-24 \t130921929\t 9.613 ns/op\n", + "BenchmarkFibonacciB32-24 \t285643864\t 3.680 ns/op\n", "PASS\n", "coverage: [no statements]\n" ] @@ -334,10 +334,10 @@ "text": [ "goos: linux\n", "goarch: amd64\n", - "pkg: gonb_103d9b0e\n", + "pkg: gonb_a1453c14\n", "cpu: 12th Gen Intel(R) Core(TM) i9-12900K\n", - "BenchmarkFibonacciA32-24 \t 171\t 6435921 ns/op\n", - "BenchmarkFibonacciB32-24 \t121723155\t 9.476 ns/op\n", + "BenchmarkFibonacciA32-24 \t 168\t 7082427 ns/op\n", + "BenchmarkFibonacciB32-24 \t308541147\t 3.901 ns/op\n", "PASS\n", "coverage: [no statements]\n" ] @@ -361,7 +361,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/gowork.ipynb b/examples/tests/gowork.ipynb index 558f8e7..88d5e99 100644 --- a/examples/tests/gowork.ipynb +++ b/examples/tests/gowork.ipynb @@ -36,7 +36,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "/tmp/gonb_tests_gowork_D4ZtmNON" + "/tmp/gonb_tests_gowork_IBSuBo7n" ] } ], @@ -64,7 +64,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Temporary test package: /tmp/gonb_tests_gowork_D4ZtmNON\n" + "Temporary test package: /tmp/gonb_tests_gowork_IBSuBo7n\n" ] } ], @@ -136,7 +136,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "\t- Added replace rule for module \"a.com/a/pkg\" to local directory \"/tmp/gonb_tests_gowork_D4ZtmNON\".\n" + "\t- Added replace rule for module \"a.com/a/pkg\" to local directory \"/tmp/gonb_tests_gowork_IBSuBo7n\".\n" ] } ], @@ -155,9 +155,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "module gonb_b0524c9c\n", + "module gonb_05a80086\n", "\n", - "go 1.23.0\n", + "go 1.23.2\n", "\n", "replace a.com/a/pkg => TMP_PKG\n" ] @@ -186,7 +186,7 @@ "text/html": [ "List of files/directories being tracked:\n", "\n" ] }, @@ -208,9 +208,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "module gonb_b0524c9c\n", + "module gonb_05a80086\n", "\n", - "go 1.23.0\n" + "go 1.23.2\n" ] } ], @@ -280,7 +280,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/hello.ipynb b/examples/tests/hello.ipynb index 66054ed..57a56a7 100644 --- a/examples/tests/hello.ipynb +++ b/examples/tests/hello.ipynb @@ -99,7 +99,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/init.ipynb b/examples/tests/init.ipynb index dc9e06f..b310420 100644 --- a/examples/tests/init.ipynb +++ b/examples/tests/init.ipynb @@ -156,7 +156,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/input_boxes.ipynb b/examples/tests/input_boxes.ipynb index 640dad9..09b2cea 100644 --- a/examples/tests/input_boxes.ipynb +++ b/examples/tests/input_boxes.ipynb @@ -22,7 +22,7 @@ "output_type": "stream", "text": [ "%goflags=[\"--cover\" \"--covermode=set\"]\n", - "GOCOVERDIR=/tmp/gonb_test_coverage.eLusFuePYS\n" + "GOCOVERDIR=/tmp/gonb_test_coverage.fmW2jDEhWf\n" ] } ], @@ -196,7 +196,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/script.ipynb b/examples/tests/script.ipynb index e06222d..1e9b50b 100644 --- a/examples/tests/script.ipynb +++ b/examples/tests/script.ipynb @@ -105,7 +105,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/vartuple.ipynb b/examples/tests/vartuple.ipynb index 8a94e10..61cc5a7 100644 --- a/examples/tests/vartuple.ipynb +++ b/examples/tests/vartuple.ipynb @@ -45,7 +45,7 @@ "text/html": [ "

Variables

\n", "" diff --git a/examples/tests/widgets.ipynb b/examples/tests/widgets.ipynb index 4c636aa..1ca72cc 100644 --- a/examples/tests/widgets.ipynb +++ b/examples/tests/widgets.ipynb @@ -95,7 +95,7 @@ { "data": { "text/html": [ - "
" + "
" ] }, "metadata": {}, @@ -189,7 +189,7 @@ { "data": { "text/html": [ - "
" + "
" ] }, "metadata": {}, @@ -304,7 +304,7 @@ { "data": { "text/html": [ - "
" + "
" ] }, "metadata": {}, @@ -416,7 +416,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/examples/tests/writefile.ipynb b/examples/tests/writefile.ipynb index ccbd17f..c68b0f8 100644 --- a/examples/tests/writefile.ipynb +++ b/examples/tests/writefile.ipynb @@ -10,7 +10,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "Cell contents written to \"/tmp/gonb_nbtests_writefile_203091453/poetry.txt\".\n" + "Cell contents written to \"/tmp/gonb_nbtests_writefile_4201179243/poetry.txt\".\n" ] } ], @@ -32,7 +32,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "Cell contents appended to \"/tmp/gonb_nbtests_writefile_203091453/poetry.txt\".\n" + "Cell contents appended to \"/tmp/gonb_nbtests_writefile_4201179243/poetry.txt\".\n" ] } ], @@ -55,7 +55,7 @@ "name": "go", "nbconvert_exporter": "", "pygments_lexer": "", - "version": "go1.23.0" + "version": "go1.23.2" } }, "nbformat": 4, diff --git a/gonbui/dom/download.go b/gonbui/dom/download.go new file mode 100644 index 0000000..86839d8 --- /dev/null +++ b/gonbui/dom/download.go @@ -0,0 +1,56 @@ +package dom + +import ( + "bytes" + "encoding/base64" + "github.com/janpfeifer/gonb/gonbui/protocol" + "github.com/pkg/errors" +) + +// SendAsDownload sends data from a cell to the client by triggering a browser download. +// +// This function initiates a file download in the user's browser. It works by +// creating a temporary link with the provided data and simulating a click on it. +// The link is then removed. +// +// Note: This function encodes the data into the webpage, which is inefficient +// for large files. It's best suited for downloading smaller files. +// +// Parameters: +// - fileName: The name of the downloaded file. +// - data: The file content as a byte array. +// - mimeType: The MIME type of the file (e.g., "text/csv", "image/png"). +// +// Example: +// +// lines := []string{"name,phone"} // Header +// nameToPhone := map[string]string{ +// "SpiderMan": "+1 407 224-1783", +// "SandMan": "+44 20 999 123 456", +// "Wanda": "+1 732 555 0125", +// } +// for name, phone := range nameToPhone { +// lines = append(lines, fmt.Sprintf("%q,%q", name, phone)) +// } +// data := []byte(strings.Join(lines, "\n")) +// dom.SendAsDownload("phonebook.csv", data, "text/csv") +func SendAsDownload(fileName string, data []byte, mimeType protocol.MIMEType) { + var b bytes.Buffer + w := base64.NewEncoder(base64.StdEncoding, &b) + if _, err := w.Write(data); err != nil { + // bytes.Buffer.Write never returns an error. + panic(errors.Wrapf(err, "failed to write to bytes.Buffer, this should never happen -- in dom.SendAsDownload(%q, data, %q)", fileName, mimeType)) + } + if err := w.Close(); err != nil { + // bytes.Buffer.Close never returns an error. + panic(errors.Wrapf(err, "failed to close bytes.Buffer, this should never happen -- in dom.SendAsDownload(%q, data, %q)", fileName, mimeType)) + } + dataURL := "data:" + string(mimeType) + ";base64," + b.String() + + TransientJavascript(`var downloadLink = document.createElement('a'); +downloadLink.href = '` + dataURL + `'; +downloadLink.download = '` + fileName + `'; +document.body.appendChild(downloadLink); +downloadLink.click(); +document.body.removeChild(downloadLink);`) +} diff --git a/gonbui/gonbui.go b/gonbui/gonbui.go index 1fe831d..93fb02d 100644 --- a/gonbui/gonbui.go +++ b/gonbui/gonbui.go @@ -13,6 +13,21 @@ // // This guarantees that no in-transit display content get left behind when a program // exits. +// +// Error Handling in Gonbui: +// +// Gonbui involves communication between several components: the code execution environment, +// the Jupyter kernel, the Jupyter server, and the browser. This communication is asynchronous +// and errors may occur at various points. +// +// Gonbui employs a simplified error handling approach: +// - Global Error State: A single global error state is maintained. While not recoverable, +// errors are rare. You can check this state using the `Error` function. +// - Logging: All errors are logged. However, if communication is broken, logs might not +// reach the browser. Check the Jupyter (and potentially Gonbui) logs in such cases. +// +// This approach prioritizes simplicity over transactional error handling, acknowledging the +// challenges of maintaining consistency across asynchronous components. package gonbui import ( @@ -27,7 +42,6 @@ import ( "image/png" "io" "k8s.io/klog/v2" - "log" "os" "sync" ) @@ -44,7 +58,7 @@ var Debug bool // Usually only useful for those developing new widgets and the like. func Logf(format string, args ...any) { if Debug { - log.Printf(format, args...) + klog.Infof(format, args...) } } @@ -74,6 +88,21 @@ var ( // It returns nil if there were no errors. // // It can be tested as a health check. +// +// Error Handling in Gonbui: +// +// Gonbui involves communication between several components: the code execution environment, +// the Jupyter kernel, the Jupyter server, and the browser. This communication is asynchronous +// and errors may occur at various points. +// +// Gonbui employs a simplified error handling approach: +// - Global Error State: A single global error state is maintained. While not recoverable, +// errors are rare. You can check this state using the `Error` function. +// - Logging: All errors are logged. However, if communication is broken, logs might not +// reach the browser. Check the Jupyter (and potentially Gonbui) logs in such cases. +// +// This approach prioritizes simplicity over transactional error handling, acknowledging the +// challenges of maintaining consistency across asynchronous components. func Error() error { return gonbPipesError } @@ -219,7 +248,7 @@ func pollReaderPipe() { Logf("\ttriggered sync(%d) latch.", syncId) delete(syncRequestsMap, syncId) } else { - log.Printf("Received invalid sync acknowledgment %+v !? Communication to front-end may have become unstable!", valueMsg) + klog.Infof("Received invalid sync acknowledgment %+v !? Communication to front-end may have become unstable!", valueMsg) } mu.Unlock()