2017-01-24 15:09:23 +00:00
{% import (
2017-01-26 07:28:34 +00:00
"github.com/knq/chromedp/cmd/chromedp-gen/internal"
2017-01-24 15:09:23 +00:00
) %}
// ExtraTimestampTemplate is a special template for the Timestamp type that
// defines its JSON unmarshaling.
2017-01-26 07:28:34 +00:00
{% func ExtraTimestampTemplate(t *internal.Type, d *internal.Domain) %}{%code
2017-02-12 04:59:33 +00:00
typ := t.IDorName()
2017-07-09 01:40:29 +00:00
monotonic := t.TimestampType == internal.TimestampTypeMonotonic
2017-07-01 13:06:43 +00:00
timeRes := "time.Millisecond"
if t.TimestampType != internal.TimestampTypeMillisecond {
timeRes = "time.Second"
}
2017-01-24 15:09:23 +00:00
%}
2017-07-09 01:40:29 +00:00
{% if monotonic %}
// {%s= typ %}Epoch is the {%s= typ %} time epoch.
var {%s= typ %}Epoch *time.Time
func init() {
// initialize epoch
bt := sysutil.BootTime()
{%s= typ %}Epoch = &bt
}
{% endif %}
2017-01-24 15:09:23 +00:00
// MarshalEasyJSON satisfies easyjson.Marshaler.
func (t {%s= typ %}) MarshalEasyJSON(out *jwriter.Writer) {
2017-07-09 01:40:29 +00:00
v := {% if monotonic %}float64(time.Time(t).Sub(*{%s= typ %}Epoch))/float64(time.Second){% else %}float64(time.Time(t).UnixNano()/int64({%s= timeRes %})){% endif %}
2017-07-01 13:06:43 +00:00
out.Buffer.EnsureSpace(20)
out.Buffer.Buf = strconv.AppendFloat(out.Buffer.Buf, v, 'f', -1, 64)
2017-01-24 15:09:23 +00:00
}
// MarshalJSON satisfies json.Marshaler.
func (t {%s= typ %}) MarshalJSON() ([]byte, error) {
return easyjson.Marshal(t)
}
// UnmarshalEasyJSON satisfies easyjson.Unmarshaler.
2017-07-09 01:40:29 +00:00
func (t *{%s= typ %}) UnmarshalEasyJSON(in *jlexer.Lexer) {{% if monotonic %}
*t = {%s= typ %}({%s= typ %}Epoch.Add(time.Duration(in.Float64()*float64(time.Second)))){% else %}
2017-07-01 13:06:43 +00:00
*t = {%s= typ %}(time.Unix(0, int64(in.Float64()*float64({%s= timeRes %})))){% endif %}
2017-01-24 15:09:23 +00:00
}
// UnmarshalJSON satisfies json.Unmarshaler.
func (t *{%s= typ %}) UnmarshalJSON(buf []byte) error {
return easyjson.Unmarshal(buf, t)
}
{% endfunc %}
// ExtraFrameTemplate is a special template for the Page.Frame type, adding FrameState.
{% func ExtraFrameTemplate() %}
// FrameState is the state of a Frame.
type FrameState uint16
// FrameState enum values.
const (
FrameDOMContentEventFired FrameState = 1 << (15 - iota)
FrameLoadEventFired
FrameAttached
FrameNavigated
FrameLoading
FrameScheduledNavigation
)
// frameStateNames are the names of the frame states.
var frameStateNames = map[FrameState]string{
FrameDOMContentEventFired: "DOMContentEventFired",
FrameLoadEventFired: "LoadEventFired",
FrameAttached: "Attached",
FrameNavigated: "Navigated",
FrameLoading: "Loading",
FrameScheduledNavigation: "ScheduledNavigation",
}
// String satisfies stringer interface.
func (fs FrameState) String() string {
var s []string
for k, v := range frameStateNames {
if fs&k != 0 {
s = append(s, v)
}
}
return "[" + strings.Join(s, " ") + "]"
}
2017-02-18 08:36:24 +00:00
// EmptyFrameID is the "non-existent" frame id.
const EmptyFrameID = FrameID("")
2017-01-24 15:09:23 +00:00
{% endfunc %}
// ExtraNodeTemplate is a special template for the DOM.Node type, adding NodeState.
{% func ExtraNodeTemplate() %}
// AttributeValue returns the named attribute for the node.
func (n *Node) AttributeValue(name string) string {
n.RLock()
defer n.RUnlock()
for i := 0; i < len(n.Attributes); i+=2 {
if n.Attributes[i] == name {
return n.Attributes[i+1]
}
}
return ""
}
// xpath builds the xpath string.
2017-01-29 03:37:56 +00:00
func (n *Node) xpath(stopAtDocument, stopAtID bool) string {
2017-02-18 07:28:43 +00:00
n.RLock()
defer n.RUnlock()
2017-01-24 15:09:23 +00:00
p := ""
pos := ""
id := n.AttributeValue("id")
switch {
case n.Parent == nil:
return n.LocalName
2017-01-29 03:37:56 +00:00
case stopAtDocument && n.NodeType == NodeTypeDocument:
return ""
case stopAtID && id != "":
2017-01-24 15:09:23 +00:00
p = "/"
pos = `[@id='`+id+`']`
case n.Parent != nil:
2017-02-18 07:28:43 +00:00
var i int
2017-01-24 15:09:23 +00:00
var found bool
2017-02-18 07:28:43 +00:00
n.Parent.RLock()
2017-01-24 15:09:23 +00:00
for j := 0; j < len(n.Parent.Children); j++ {
if n.Parent.Children[j].LocalName == n.LocalName {
i++
}
if n.Parent.Children[j].NodeID == n.NodeID {
found = true
break
}
}
2017-02-18 07:28:43 +00:00
n.Parent.RUnlock()
2017-01-24 15:09:23 +00:00
if found {
pos = "["+strconv.Itoa(i)+"]"
}
2017-02-18 07:28:43 +00:00
p = n.Parent.xpath(stopAtDocument, stopAtID)
2017-01-24 15:09:23 +00:00
}
return p + "/" + n.LocalName + pos
}
2017-01-29 03:37:56 +00:00
// PartialXPathByID returns the partial XPath for the node, stopping at the
// first parent with an id attribute or at nearest parent document node.
func (n *Node) PartialXPathByID() string {
return n.xpath(true, true)
}
// PartialXPath returns the partial XPath for the node, stopping at the nearest
// parent document node.
func (n *Node) PartialXPath() string {
return n.xpath(true, false)
}
// FullXPathByID returns the full XPath for the node, stopping at the top most
// document root or at the closest parent node with an id attribute.
func (n *Node) FullXPathByID() string {
return n.xpath(false, true)
2017-01-24 15:09:23 +00:00
}
2017-01-29 03:37:56 +00:00
// FullXPath returns the full XPath for the node, stopping only at the top most
// document root.
func (n *Node) FullXPath() string {
return n.xpath(false, false)
2017-01-24 15:09:23 +00:00
}
// NodeState is the state of a DOM node.
type NodeState uint8
// NodeState enum values.
const (
NodeReady NodeState = 1 << (7 - iota)
NodeVisible
NodeHighlighted
)
// nodeStateNames are the names of the node states.
var nodeStateNames = map[NodeState]string{
NodeReady: "Ready",
NodeVisible: "Visible",
NodeHighlighted: "Highlighted",
}
// String satisfies stringer interface.
func (ns NodeState) String() string {
var s []string
for k, v := range nodeStateNames {
if ns&k != 0 {
s = append(s, v)
}
}
return "[" + strings.Join(s, " ") + "]"
}
2017-02-18 08:36:24 +00:00
// EmptyNodeID is the "non-existent" node id.
const EmptyNodeID = NodeID(0)
2017-01-24 15:09:23 +00:00
{% endfunc %}
// ExtraFixStringUnmarshaler is a template that forces values to be parsed properly.
{% func ExtraFixStringUnmarshaler(typ, parseFunc, extra string) %}
// UnmarshalEasyJSON satisfies easyjson.Unmarshaler.
func (t *{%s= typ %}) UnmarshalEasyJSON(in *jlexer.Lexer) {
buf := in.Raw()
if l := len(buf); l > 2 && buf[0] == '"' && buf[l-1] == '"' {
buf = buf[1:l-1]
}
{% if parseFunc != "" %}
v, err := strconv.{%s= parseFunc %}(string(buf){%s= extra %})
if err != nil {
in.AddError(err)
}
{% endif %}
2017-02-18 03:58:29 +00:00
*t = {%s= typ %}({% if parseFunc != "" %}v{% else %}buf{% endif %})
2017-01-24 15:09:23 +00:00
}
// UnmarshalJSON satisfies json.Unmarshaler.
func (t *{%s= typ %}) UnmarshalJSON(buf []byte) error {
return easyjson.Unmarshal(buf, t)
}
{% endfunc %}
2017-02-08 07:27:39 +00:00
// ExtraExceptionDetailsTemplate is a special template for the Runtime.ExceptionDetails type that
// defines the standard error interface.
{% func ExtraExceptionDetailsTemplate() %}
// Error satisfies the error interface.
func (e *ExceptionDetails) Error() string {
// TODO: watch script parsed events and match the ExceptionDetails.ScriptID
// to the name/location of the actual code and display here
return fmt.Sprintf("encountered exception '%s' (%d:%d)", e.Text, e.LineNumber, e.ColumnNumber)
}
{% endfunc %}
2017-01-26 07:28:34 +00:00
// ExtraCDPTypes is the template for additional internal type
2017-01-24 15:09:23 +00:00
// declarations.
2017-01-26 07:28:34 +00:00
{% func ExtraCDPTypes() %}
2017-01-24 15:09:23 +00:00
// Error satisfies the error interface.
func (t ErrorType) Error() string {
return string(t)
}
2017-02-12 04:59:33 +00:00
// Handler is the common interface for a Chrome Debugging Protocol target.
type Handler interface {
// SetActive changes the top level frame id.
2017-01-24 15:09:23 +00:00
SetActive(context.Context, FrameID) error
2017-02-12 04:59:33 +00:00
// GetRoot returns the root document node for the top level frame.
2017-01-24 15:09:23 +00:00
GetRoot(context.Context) (*Node, error)
2017-02-12 04:59:33 +00:00
// WaitFrame waits for a frame to be available.
2017-01-24 15:09:23 +00:00
WaitFrame(context.Context, FrameID) (*Frame, error)
2017-02-12 04:59:33 +00:00
// WaitNode waits for a node to be available.
2017-01-24 15:09:23 +00:00
WaitNode(context.Context, *Frame, NodeID) (*Node, error)
// Execute executes the specified command using the supplied context and
// parameters.
2017-02-14 08:41:23 +00:00
Execute(context.Context, MethodType, easyjson.Marshaler, easyjson.Unmarshaler) error
2017-02-12 04:59:33 +00:00
// Listen creates a channel that will receive an event for the types
// specified.
Listen(...MethodType) <-chan interface{}
// Release releases a channel returned from Listen.
Release(<-chan interface{})
2017-01-24 15:09:23 +00:00
}
{% endfunc %}
// ExtraUtilTemplate generates the decode func for the Message type.
2017-01-26 07:28:34 +00:00
{% func ExtraUtilTemplate(domains []*internal.Domain) %}
2017-01-24 15:09:23 +00:00
type empty struct{}
var emptyVal = &empty{}
// UnmarshalMessage unmarshals the message result or params.
2017-01-26 07:28:34 +00:00
func UnmarshalMessage(msg *cdp.Message) (interface{}, error) {
2017-01-24 15:09:23 +00:00
var v easyjson.Unmarshaler
switch msg.Method {{% for _, d := range domains %}{% for _, c := range d.Commands %}
2017-01-26 07:28:34 +00:00
case cdp.{%s= c.CommandMethodType(d) %}:{% if len(c.Returns) == 0 %}
2017-01-24 15:09:23 +00:00
return emptyVal, nil{% else %}
v = new({%s= d.PackageRefName() %}.{%s= c.CommandReturnsType() %}){% endif %}
{% endfor %}{% for _, e := range d.Events %}
2017-01-26 07:28:34 +00:00
case cdp.{%s= e.EventMethodType(d) %}:
2017-01-24 15:09:23 +00:00
v = new({%s= d.PackageRefName() %}.{%s= e.EventType() %})
{% endfor %}{% endfor %}}
var buf easyjson.RawMessage
switch {
case msg.Params != nil:
buf = msg.Params
case msg.Result != nil:
buf = msg.Result
default:
return nil, errors.New("msg missing params or result")
}
err := easyjson.Unmarshal(buf, v)
if err != nil {
return nil, err
}
return v, nil
}
{% endfunc %}
{% func ExtraMethodTypeDomainDecoder() %}
// Domain returns the Chrome Debugging Protocol domain of the event or command.
func (t MethodType) Domain() string {
return string(t[:strings.IndexByte(string(t), '.')])
}
{% endfunc %}