Comments (6)
One way to improve this would be to not return an error when creating a client, just: frameNavigated := c.Page.FrameNavigated(ctx)
. I've entertained this possibility before but I dislike it for two reasons:
- It does not instantly inform the user if the connection is already closed when they are trying to create the client
- It might promote incorrect usage
ev, err := c.Page.FrameNavigated(ctx).Recv()
which would leak memory (leaves the event client open, buffering any future events of this kind)
For these two reasons I think it's best to find alternate solutions (like above). It's a bit unfortunate, since not returning the error would allow us to write the above as:
events := []cdp.Event{
c.Page.FrameNavigated(ctx),
c.Domain.SomeOther(ctx),
}
Which doesn't introduce an alternate way to reference the events.
from cdp.
The more I think about this issue, perhaps the right API for this kind of functionality is a cdp.RecvAll(ctx, c)
(name and signature TBD).
This would create a client that automatically subscribes to all possible events.
We could introduce state into cdp.Client
so that only domains that have been enabled (via client) are subscribed to. Disable would unsubscribe. Don't know if this is useful or not. This might warrant a (*cdp.Client).Close()
method. If so, does it also close *rpcc.Conn
?
from cdp.
So far this hasn't been a big issue for me. Despite starting out with a bunch of events, I generally only use maybe 2-4 now.
The copying and pasting is a little annoying, but I've been sticking them in goroutines to clean it up a bit. To me, that's been a little nicer than using a switch statement.
One nice thing about something like cdp.RecvAll(ctx, c)
would be for logging / debugging though
from cdp.
Thanks for the input!
The copying and pasting is a little annoying, but I've been sticking them in goroutines to clean it up a bit. To me, that's been a little nicer than using a switch statement.
I can relate to the annoying part, but I'm glad you like it anyway! One reason for this proposal is use cases that aren't possible with the current API, for example, syncing a local representation of the DOM, consider the following:
switch ev := ev.(type) {
case *dom.AttributeModifiedReply:
data.updateAttribute(ev.NodeID, ev.Name, ev.Value)
case *dom.AttributeRemovedReply:
data.removeAttribute(ev.NodeID, ev.Name)
case *dom.ChildNodeCountUpdatedReply:
data.updateNodeCount(ev.NodeID, ev.ChildNodeCount)
case *dom.ChildNodeInsertedReply:
data.insertNode(ev.ParentNodeID, ev.PreviousNodeID, ev.Node)
case *dom.ChildNodeRemovedReply:
data.removeNode(ev.ParentNodeID, ev.NodeID)
}
With the proposed API we can be sure that all events arrive in the correct order, allowing us to keep an accurate representation as long as we handle all events. This also reduces the number of goroutines we need to have running (1 in this case vs at least 5 by launching a goroutine for each client). This also allows us to keep all the syncing logic in one place.
One nice thing about something like
cdp.RecvAll(ctx, c)
would be for logging / debugging though
That's a good point. On that note, did you know there's a logging example in the repo/godoc? It's a bit verbose (custom codec) but quite flexible :-).
I think a potentially valid option (in addition to cdp.RecvAll
) would be cdp.Merge
, it could look like this:
attributeModified, err := c.DOM.AttributeModified(ctx)
if err != nil {
return err
}
attributeRemoved, err := c.DOM.AttributeRemoved(ctx)
if err != nil {
return err
}
mergedClient := cdp.Merge(attributeModified, attributeRemoved)
mergedClient.Recv() // (interface{}, error)
from cdp.
I believe I finally found a satisfactory (alternative) solution to merging events. It avoids the need to switch on event types entirely.
It doesn't solve the sync problem though, but I think that could be solvable via an option passed to the client (e.g. c.DOM.AttributeModified(ctx, syncOption)
).
Here's what the alternative solution looks like:
attributeModified, err := c.DOM.AttributeModified(ctx)
if err != nil {
return err
}
attributeRemoved, err := c.DOM.AttributeRemoved(ctx)
if err != nil {
return err
}
go func() {
defer func() {
attributeModified.Close()
attributeRemoved.Close()
}
select {
case <-attributeModified.Ready():
ev, err := attributeModified.Recv() // Does not block.
if err != nil {
// Handle error.
}
_ = ev
case <-attributeRemoved.Ready():
// attributeRemoved.Recv() ...
case <-timeout:
log.Println("timed out")
return
}
}
from cdp.
Regarding synchronization, I think I have it down to two alternatives (although I'm open to better ideas!)
- Create event clients like before, then call
cdp.Sync(client1, client2, client3)
, the clients are now syncedcpd.Sync
could return a functionunsync()
cdp.Sync
discards all previous (unread) events on client(s)+
Hard to use incorrectly
- Create a new option
syncOpt := cdp.Sync()
and use it when creating clients:c.DOM.AttributeModified(ctx, syncOpt)
+
Can be a bit smarter when creating the client (resource wise, quite insignificant though)-
Same sync option must be used for all clients to be synced-
Might encourage bad usage:c.DOM.AttributeModified(ctx, cdp.Sync())
will not work as intended
In both cases, all calls to RecvMsg
will block unless the next message belongs to that event client.
Sync behavior example:
client1
andclient2
receive events (in that order)client1
Ready-channel closes- Calls to
RecvMsg
will block for bothclient2
andclient3
, but notclient1
client1.RecvMsg
is calledclient2
Ready-channel closes- Calls to
RecvMsg
will block for bothclient1
andclient3
, but notclient2
client2.RecvMsg
is called- Now all will block again (no events pending)
from cdp.
Related Issues (20)
- HTTP error / timeout when printing certain images in html HOT 1
- BrowserContextID is not accessible anymore HOT 2
- Is possible to wait for an Ajax request? HOT 2
- Lifecycle events not fire in order and this ones are fired twice HOT 2
- RequestIntercepted can't set respond HOT 2
- session.Manager.watch may not finish when unexpected error happens on websocket
- Non-wrapped error HOT 3
- How to optionally download files while also dealing with regular web pages HOT 6
- Connection for every thread HOT 2
- Default example not working dial tcp [::1]:9222: connectex HOT 1
- Rpc command not found HOT 4
- Attempted to use with node, too many chrome assumptions? HOT 4
- Problem interacting with the remote debugging host over HTTP HOT 5
- Breaking changes in node js debugging in v0.34.0 HOT 4
- Remote Pipe
- resolving URL from scriptID in pausedClient HOT 2
- Default example doesn't work - Page.Enable wasn't found HOT 3
- New browser tab event / notification HOT 1
- Is This Repo Abandoned or Dead? HOT 4
- Extensions.loadUnpacked wasn't found HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cdp.