fix(cef): run injected javascript on ui thread
- commit
- 03caa44a9537046cafe3b6e6b797fb24b41056fb
- author
- brice · · 2026-06-24 05:02 UTC
- parent
- 85f934a
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +57 -0
M internal/infrastructure/cef/webview.go +17 -0
| @@ -1055,6 +1055,23 @@ func (wv *WebView) RunJavaScript(_ context.Context, script string) { | |||
| 1055 | 1055 | if wv.destroyed.Load() { | |
| 1056 | 1056 | return | |
| 1057 | 1057 | } | |
| 1058 | + | if wv.engine == nil { | |
| 1059 | + | wv.executeJavaScriptNow(script) | |
| 1060 | + | return | |
| 1061 | + | } | |
| 1062 | + | task := cefNewTask(cefTaskFunc(func() { | |
| 1063 | + | wv.executeJavaScriptNow(script) | |
| 1064 | + | })) | |
| 1065 | + | if task == nil { | |
| 1066 | + | return | |
| 1067 | + | } | |
| 1068 | + | cefPostTask(purecef.ThreadIDTidUi, task) | |
| 1069 | + | } | |
| 1070 | + | ||
| 1071 | + | func (wv *WebView) executeJavaScriptNow(script string) { | |
| 1072 | + | if wv == nil || wv.destroyed.Load() { | |
| 1073 | + | return | |
| 1074 | + | } | |
| 1058 | 1075 | wv.mu.RLock() | |
| 1059 | 1076 | browser := wv.browser | |
| 1060 | 1077 | wv.mu.RUnlock() | |
| @@ -1055,6 +1055,23 @@ func (wv *WebView) RunJavaScript(_ context.Context, script string) { | |||||
| 1055 | if wv.destroyed.Load() { | 1055 | if wv.destroyed.Load() { | ||
| 1056 | return | 1056 | return | ||
| 1057 | } | 1057 | } | ||
| 1058 | + | if wv.engine == nil { | |||
| 1059 | + | wv.executeJavaScriptNow(script) | |||
| 1060 | + | return | |||
| 1061 | + | } | |||
| 1062 | + | task := cefNewTask(cefTaskFunc(func() { | |||
| 1063 | + | wv.executeJavaScriptNow(script) | |||
| 1064 | + | })) | |||
| 1065 | + | if task == nil { | |||
| 1066 | + | return | |||
| 1067 | + | } | |||
| 1068 | + | cefPostTask(purecef.ThreadIDTidUi, task) | |||
| 1069 | + | } | |||
| 1070 | + | ||||
| 1071 | + | func (wv *WebView) executeJavaScriptNow(script string) { | |||
| 1072 | + | if wv == nil || wv.destroyed.Load() { | |||
| 1073 | + | return | |||
| 1074 | + | } | |||
| 1058 | wv.mu.RLock() | 1075 | wv.mu.RLock() | ||
| 1059 | browser := wv.browser | 1076 | browser := wv.browser | ||
| 1060 | wv.mu.RUnlock() | 1077 | wv.mu.RUnlock() | ||
A internal/infrastructure/cef/webview_javascript_test.go +40 -0
| @@ -0,0 +1,40 @@ | |||
| 1 | + | package cef | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "context" | |
| 5 | + | "testing" | |
| 6 | + | ||
| 7 | + | purecef "github.com/bnema/purego-cef/cef" | |
| 8 | + | cefmocks "github.com/bnema/purego-cef/cef/mocks" | |
| 9 | + | "github.com/stretchr/testify/require" | |
| 10 | + | ) | |
| 11 | + | ||
| 12 | + | func TestWebViewRunJavaScript_PostsExecutionToCefUIThread(t *testing.T) { | |
| 13 | + | browser := cefmocks.NewMockBrowser(t) | |
| 14 | + | frame := cefmocks.NewMockFrame(t) | |
| 15 | + | const script = "document.body.dataset.dumber = '1'" | |
| 16 | + | ||
| 17 | + | oldTask := cefNewTask | |
| 18 | + | oldPost := cefPostTask | |
| 19 | + | defer func() { | |
| 20 | + | cefNewTask = oldTask | |
| 21 | + | cefPostTask = oldPost | |
| 22 | + | }() | |
| 23 | + | cefNewTask = func(task purecef.Task) purecef.Task { return task } | |
| 24 | + | ||
| 25 | + | var scheduled purecef.Task | |
| 26 | + | cefPostTask = func(threadID purecef.ThreadID, task purecef.Task) int32 { | |
| 27 | + | require.Equal(t, purecef.ThreadIDTidUi, threadID) | |
| 28 | + | require.NotNil(t, task) | |
| 29 | + | scheduled = task | |
| 30 | + | return 1 | |
| 31 | + | } | |
| 32 | + | ||
| 33 | + | wv := &WebView{ctx: context.Background(), engine: &Engine{}, browser: browser} | |
| 34 | + | wv.RunJavaScript(context.Background(), script) | |
| 35 | + | ||
| 36 | + | require.NotNil(t, scheduled) | |
| 37 | + | browser.EXPECT().GetMainFrame().Return(frame).Once() | |
| 38 | + | frame.EXPECT().ExecuteJavaScript(script, "", int32(0)).Once() | |
| 39 | + | scheduled.Execute() | |
| 40 | + | } | |
| @@ -0,0 +1,40 @@ | |||||
| 1 | + | package cef | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "context" | |||
| 5 | + | "testing" | |||
| 6 | + | ||||
| 7 | + | purecef "github.com/bnema/purego-cef/cef" | |||
| 8 | + | cefmocks "github.com/bnema/purego-cef/cef/mocks" | |||
| 9 | + | "github.com/stretchr/testify/require" | |||
| 10 | + | ) | |||
| 11 | + | ||||
| 12 | + | func TestWebViewRunJavaScript_PostsExecutionToCefUIThread(t *testing.T) { | |||
| 13 | + | browser := cefmocks.NewMockBrowser(t) | |||
| 14 | + | frame := cefmocks.NewMockFrame(t) | |||
| 15 | + | const script = "document.body.dataset.dumber = '1'" | |||
| 16 | + | ||||
| 17 | + | oldTask := cefNewTask | |||
| 18 | + | oldPost := cefPostTask | |||
| 19 | + | defer func() { | |||
| 20 | + | cefNewTask = oldTask | |||
| 21 | + | cefPostTask = oldPost | |||
| 22 | + | }() | |||
| 23 | + | cefNewTask = func(task purecef.Task) purecef.Task { return task } | |||
| 24 | + | ||||
| 25 | + | var scheduled purecef.Task | |||
| 26 | + | cefPostTask = func(threadID purecef.ThreadID, task purecef.Task) int32 { | |||
| 27 | + | require.Equal(t, purecef.ThreadIDTidUi, threadID) | |||
| 28 | + | require.NotNil(t, task) | |||
| 29 | + | scheduled = task | |||
| 30 | + | return 1 | |||
| 31 | + | } | |||
| 32 | + | ||||
| 33 | + | wv := &WebView{ctx: context.Background(), engine: &Engine{}, browser: browser} | |||
| 34 | + | wv.RunJavaScript(context.Background(), script) | |||
| 35 | + | ||||
| 36 | + | require.NotNil(t, scheduled) | |||
| 37 | + | browser.EXPECT().GetMainFrame().Return(frame).Once() | |||
| 38 | + | frame.EXPECT().ExecuteJavaScript(script, "", int32(0)).Once() | |||
| 39 | + | scheduled.Execute() | |||
| 40 | + | } | |||