feat: modernise to Go 1.26 iterators and stdlib helpers
Add iter.Seq iterators (MessagesAll, FilteredMessagesAll, ErrorsAll, WarningsAll, ExceptionsAll, GetConsoleAll, QuerySelectorAllAll, ListTargetsAll) for streaming. Use slices.Clone for handler copies, range-over-int in findString. Co-Authored-By: Gemini <noreply@google.com> Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
17bf50b89c
commit
d0dd96d115
3 changed files with 127 additions and 47 deletions
19
cdp.go
19
cdp.go
|
|
@ -5,7 +5,9 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"net/http"
|
||||
"slices"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
|
|
@ -251,7 +253,7 @@ func (c *CDPClient) readLoop() {
|
|||
// dispatchEvent dispatches an event to registered handlers.
|
||||
func (c *CDPClient) dispatchEvent(method string, params map[string]any) {
|
||||
c.handMu.RLock()
|
||||
handlers := c.handlers[method]
|
||||
handlers := slices.Clone(c.handlers[method])
|
||||
c.handMu.RUnlock()
|
||||
|
||||
for _, handler := range handlers {
|
||||
|
|
@ -365,6 +367,21 @@ func ListTargets(debugURL string) ([]targetInfo, error) {
|
|||
return targets, nil
|
||||
}
|
||||
|
||||
// ListTargetsAll returns an iterator over all available targets.
|
||||
func ListTargetsAll(debugURL string) iter.Seq[targetInfo] {
|
||||
return func(yield func(targetInfo) bool) {
|
||||
targets, err := ListTargets(debugURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, t := range targets {
|
||||
if !yield(t) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetVersion returns Chrome version information.
|
||||
func GetVersion(debugURL string) (map[string]string, error) {
|
||||
resp, err := http.Get(debugURL + "/json/version")
|
||||
|
|
|
|||
115
console.go
115
console.go
|
|
@ -3,6 +3,8 @@ package webview
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"iter"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -75,60 +77,84 @@ func (cw *ConsoleWatcher) SetLimit(limit int) {
|
|||
|
||||
// Messages returns all captured messages.
|
||||
func (cw *ConsoleWatcher) Messages() []ConsoleMessage {
|
||||
cw.mu.RLock()
|
||||
defer cw.mu.RUnlock()
|
||||
return slices.Collect(cw.MessagesAll())
|
||||
}
|
||||
|
||||
result := make([]ConsoleMessage, len(cw.messages))
|
||||
copy(result, cw.messages)
|
||||
return result
|
||||
// MessagesAll returns an iterator over all captured messages.
|
||||
func (cw *ConsoleWatcher) MessagesAll() iter.Seq[ConsoleMessage] {
|
||||
return func(yield func(ConsoleMessage) bool) {
|
||||
cw.mu.RLock()
|
||||
defer cw.mu.RUnlock()
|
||||
|
||||
for _, msg := range cw.messages {
|
||||
if !yield(msg) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FilteredMessages returns messages matching the current filters.
|
||||
func (cw *ConsoleWatcher) FilteredMessages() []ConsoleMessage {
|
||||
cw.mu.RLock()
|
||||
defer cw.mu.RUnlock()
|
||||
return slices.Collect(cw.FilteredMessagesAll())
|
||||
}
|
||||
|
||||
if len(cw.filters) == 0 {
|
||||
result := make([]ConsoleMessage, len(cw.messages))
|
||||
copy(result, cw.messages)
|
||||
return result
|
||||
}
|
||||
// FilteredMessagesAll returns an iterator over messages matching the current filters.
|
||||
func (cw *ConsoleWatcher) FilteredMessagesAll() iter.Seq[ConsoleMessage] {
|
||||
return func(yield func(ConsoleMessage) bool) {
|
||||
cw.mu.RLock()
|
||||
defer cw.mu.RUnlock()
|
||||
|
||||
result := make([]ConsoleMessage, 0)
|
||||
for _, msg := range cw.messages {
|
||||
if cw.matchesFilter(msg) {
|
||||
result = append(result, msg)
|
||||
for _, msg := range cw.messages {
|
||||
if cw.matchesFilter(msg) {
|
||||
if !yield(msg) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Errors returns all error messages.
|
||||
func (cw *ConsoleWatcher) Errors() []ConsoleMessage {
|
||||
cw.mu.RLock()
|
||||
defer cw.mu.RUnlock()
|
||||
return slices.Collect(cw.ErrorsAll())
|
||||
}
|
||||
|
||||
result := make([]ConsoleMessage, 0)
|
||||
for _, msg := range cw.messages {
|
||||
if msg.Type == "error" {
|
||||
result = append(result, msg)
|
||||
// ErrorsAll returns an iterator over all error messages.
|
||||
func (cw *ConsoleWatcher) ErrorsAll() iter.Seq[ConsoleMessage] {
|
||||
return func(yield func(ConsoleMessage) bool) {
|
||||
cw.mu.RLock()
|
||||
defer cw.mu.RUnlock()
|
||||
|
||||
for _, msg := range cw.messages {
|
||||
if msg.Type == "error" {
|
||||
if !yield(msg) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Warnings returns all warning messages.
|
||||
func (cw *ConsoleWatcher) Warnings() []ConsoleMessage {
|
||||
cw.mu.RLock()
|
||||
defer cw.mu.RUnlock()
|
||||
return slices.Collect(cw.WarningsAll())
|
||||
}
|
||||
|
||||
result := make([]ConsoleMessage, 0)
|
||||
for _, msg := range cw.messages {
|
||||
if msg.Type == "warning" {
|
||||
result = append(result, msg)
|
||||
// WarningsAll returns an iterator over all warning messages.
|
||||
func (cw *ConsoleWatcher) WarningsAll() iter.Seq[ConsoleMessage] {
|
||||
return func(yield func(ConsoleMessage) bool) {
|
||||
cw.mu.RLock()
|
||||
defer cw.mu.RUnlock()
|
||||
|
||||
for _, msg := range cw.messages {
|
||||
if msg.Type == "warning" {
|
||||
if !yield(msg) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Clear clears all captured messages.
|
||||
|
|
@ -271,8 +297,7 @@ func (cw *ConsoleWatcher) addMessage(msg ConsoleMessage) {
|
|||
cw.messages = append(cw.messages, msg)
|
||||
|
||||
// Copy handlers to call outside lock
|
||||
handlers := make([]ConsoleHandler, len(cw.handlers))
|
||||
copy(handlers, cw.handlers)
|
||||
handlers := slices.Clone(cw.handlers)
|
||||
cw.mu.Unlock()
|
||||
|
||||
// Call handlers
|
||||
|
|
@ -315,7 +340,7 @@ func containsString(s, substr string) bool {
|
|||
|
||||
// findString finds substr in s, returns -1 if not found.
|
||||
func findString(s, substr string) int {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
for i := range len(s) - len(substr) + 1 {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return i
|
||||
}
|
||||
|
|
@ -359,12 +384,21 @@ func NewExceptionWatcher(wv *Webview) *ExceptionWatcher {
|
|||
|
||||
// Exceptions returns all captured exceptions.
|
||||
func (ew *ExceptionWatcher) Exceptions() []ExceptionInfo {
|
||||
ew.mu.RLock()
|
||||
defer ew.mu.RUnlock()
|
||||
return slices.Collect(ew.ExceptionsAll())
|
||||
}
|
||||
|
||||
result := make([]ExceptionInfo, len(ew.exceptions))
|
||||
copy(result, ew.exceptions)
|
||||
return result
|
||||
// ExceptionsAll returns an iterator over all captured exceptions.
|
||||
func (ew *ExceptionWatcher) ExceptionsAll() iter.Seq[ExceptionInfo] {
|
||||
return func(yield func(ExceptionInfo) bool) {
|
||||
ew.mu.RLock()
|
||||
defer ew.mu.RUnlock()
|
||||
|
||||
for _, exc := range ew.exceptions {
|
||||
if !yield(exc) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear clears all captured exceptions.
|
||||
|
|
@ -476,8 +510,7 @@ func (ew *ExceptionWatcher) handleException(params map[string]any) {
|
|||
|
||||
ew.mu.Lock()
|
||||
ew.exceptions = append(ew.exceptions, info)
|
||||
handlers := make([]func(ExceptionInfo), len(ew.handlers))
|
||||
copy(handlers, ew.handlers)
|
||||
handlers := slices.Clone(ew.handlers)
|
||||
ew.mu.Unlock()
|
||||
|
||||
// Call handlers
|
||||
|
|
|
|||
40
webview.go
40
webview.go
|
|
@ -25,6 +25,8 @@ import (
|
|||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"iter"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -192,14 +194,42 @@ func (wv *Webview) QuerySelectorAll(selector string) ([]*ElementInfo, error) {
|
|||
return wv.querySelectorAll(ctx, selector)
|
||||
}
|
||||
|
||||
// QuerySelectorAllAll returns an iterator over all elements matching the selector.
|
||||
func (wv *Webview) QuerySelectorAllAll(selector string) iter.Seq[*ElementInfo] {
|
||||
return func(yield func(*ElementInfo) bool) {
|
||||
ctx, cancel := context.WithTimeout(wv.ctx, wv.timeout)
|
||||
defer cancel()
|
||||
|
||||
elements, err := wv.querySelectorAll(ctx, selector)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, elem := range elements {
|
||||
if !yield(elem) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetConsole returns captured console messages.
|
||||
func (wv *Webview) GetConsole() []ConsoleMessage {
|
||||
wv.mu.RLock()
|
||||
defer wv.mu.RUnlock()
|
||||
return slices.Collect(wv.GetConsoleAll())
|
||||
}
|
||||
|
||||
result := make([]ConsoleMessage, len(wv.consoleLogs))
|
||||
copy(result, wv.consoleLogs)
|
||||
return result
|
||||
// GetConsoleAll returns an iterator over captured console messages.
|
||||
func (wv *Webview) GetConsoleAll() iter.Seq[ConsoleMessage] {
|
||||
return func(yield func(ConsoleMessage) bool) {
|
||||
wv.mu.RLock()
|
||||
defer wv.mu.RUnlock()
|
||||
|
||||
for _, msg := range wv.consoleLogs {
|
||||
if !yield(msg) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ClearConsole clears captured console messages.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue